Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / SkCornerPathEffect.cpp
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 "SkReadBuffer.h"
14 #include "SkWriteBuffer.h"
15
16 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
17 SkCornerPathEffect::~SkCornerPathEffect() {}
18
19 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
20                         SkPoint* step) {
21     SkScalar dist = SkPoint::Distance(a, b);
22
23     step->set(b.fX - a.fX, b.fY - a.fY);
24
25     if (dist <= radius * 2) {
26         step->scale(SK_ScalarHalf);
27         return false;
28     } else {
29         step->scale(SkScalarDiv(radius, dist));
30         return true;
31     }
32 }
33
34 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
35                                     SkStrokeRec*, const SkRect*) const {
36     if (0 == fRadius) {
37         return false;
38     }
39
40     SkPath::Iter    iter(src, false);
41     SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
42     SkPoint         pts[4];
43
44     bool        closed;
45     SkPoint     moveTo, lastCorner;
46     SkVector    firstStep, step;
47     bool        prevIsValid = true;
48
49     // to avoid warnings
50     moveTo.set(0, 0);
51     firstStep.set(0, 0);
52     lastCorner.set(0, 0);
53
54     for (;;) {
55         switch (verb = iter.next(pts, false)) {
56             case SkPath::kMove_Verb:
57                     // close out the previous (open) contour
58                 if (SkPath::kLine_Verb == prevVerb) {
59                     dst->lineTo(lastCorner);
60                 }
61                 closed = iter.isClosedContour();
62                 if (closed) {
63                     moveTo = pts[0];
64                     prevIsValid = false;
65                 } else {
66                     dst->moveTo(pts[0]);
67                     prevIsValid = true;
68                 }
69                 break;
70             case SkPath::kLine_Verb: {
71                 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
72                 // prev corner
73                 if (!prevIsValid) {
74                     dst->moveTo(moveTo + step);
75                     prevIsValid = true;
76                 } else {
77                     dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
78                                 pts[0].fY + step.fY);
79                 }
80                 if (drawSegment) {
81                     dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
82                 }
83                 lastCorner = pts[1];
84                 prevIsValid = true;
85                 break;
86             }
87             case SkPath::kQuad_Verb:
88                 // TBD - just replicate the curve for now
89                 if (!prevIsValid) {
90                     dst->moveTo(pts[0]);
91                     prevIsValid = true;
92                 }
93                 dst->quadTo(pts[1], pts[2]);
94                 lastCorner = pts[2];
95                 firstStep.set(0, 0);
96                 break;
97             case SkPath::kCubic_Verb:
98                 if (!prevIsValid) {
99                     dst->moveTo(pts[0]);
100                     prevIsValid = true;
101                 }
102                 // TBD - just replicate the curve for now
103                 dst->cubicTo(pts[1], pts[2], pts[3]);
104                 lastCorner = pts[3];
105                 firstStep.set(0, 0);
106                 break;
107             case SkPath::kClose_Verb:
108                 if (firstStep.fX || firstStep.fY) {
109                     dst->quadTo(lastCorner.fX, lastCorner.fY,
110                                 lastCorner.fX + firstStep.fX,
111                                 lastCorner.fY + firstStep.fY);
112                     }
113                 dst->close();
114                 break;
115             case SkPath::kConic_Verb:
116                 SkASSERT(0);
117                 break;
118             case SkPath::kDone_Verb:
119                 goto DONE;
120         }
121
122         if (SkPath::kMove_Verb == prevVerb) {
123             firstStep = step;
124         }
125         prevVerb = verb;
126     }
127 DONE:
128     return true;
129 }
130
131 SkFlattenable* SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
132     return SkCornerPathEffect::Create(buffer.readScalar());
133 }
134
135 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
136     buffer.writeScalar(fRadius);
137 }
138
139 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
140 SkCornerPathEffect::SkCornerPathEffect(SkReadBuffer& buffer) {
141     fRadius = buffer.readScalar();
142 }
143 #endif