SkCornerPathEffect.cpp revision 8a1c16ff38322f0210116fa7293eb8817c7e477e
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
23SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
24{
25}
26
27SkCornerPathEffect::~SkCornerPathEffect()
28{
29}
30
31static 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
47bool 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            closed = iter.isClosedContour();
70            if (closed) {
71                moveTo = pts[0];
72                prevIsValid = false;
73            }
74            else {
75                dst->moveTo(pts[0]);
76                prevIsValid = true;
77            }
78            break;
79        case SkPath::kLine_Verb:
80            {
81                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
82                // prev corner
83                if (!prevIsValid) {
84                    dst->moveTo(moveTo + step);
85                    prevIsValid = true;
86                }
87                else {
88                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY);
89                }
90                if (drawSegment) {
91                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
92                }
93                lastCorner = pts[1];
94                prevIsValid = true;
95            }
96            break;
97        case SkPath::kQuad_Verb:
98            // TBD - just replicate the curve for now
99            if (!prevIsValid)
100            {
101                dst->moveTo(pts[0]);
102                prevIsValid = true;
103            }
104            dst->quadTo(pts[1], pts[2]);
105            lastCorner = pts[2];
106            firstStep.set(0, 0);
107            break;
108        case SkPath::kCubic_Verb:
109            if (!prevIsValid)
110            {
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            dst->close();
125            break;
126        case SkPath::kDone_Verb:
127            goto DONE;
128        }
129
130        if (SkPath::kMove_Verb == prevVerb)
131            firstStep = step;
132        prevVerb = verb;
133    }
134DONE:
135    return true;
136}
137
138SkFlattenable::Factory SkCornerPathEffect::getFactory()
139{
140    return CreateProc;
141}
142
143void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
144{
145    buffer.writeScalar(fRadius);
146}
147
148SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
149{
150    return SkNEW_ARGS(SkCornerPathEffect, (buffer));
151}
152
153SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer)
154{
155    fRadius = buffer.readScalar();
156}
157
158