1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
10cb93a386Sopenharmony_ci#include "include/core/SkPoint.h"
11cb93a386Sopenharmony_ci#include "include/effects/SkCornerPathEffect.h"
12cb93a386Sopenharmony_ci#include "src/core/SkPathEffectBase.h"
13cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h"
14cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cistatic bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
17cb93a386Sopenharmony_ci                        SkPoint* step) {
18cb93a386Sopenharmony_ci    SkScalar dist = SkPoint::Distance(a, b);
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci    *step = b - a;
21cb93a386Sopenharmony_ci    if (dist <= radius * 2) {
22cb93a386Sopenharmony_ci        *step *= SK_ScalarHalf;
23cb93a386Sopenharmony_ci        return false;
24cb93a386Sopenharmony_ci    } else {
25cb93a386Sopenharmony_ci        *step *= radius / dist;
26cb93a386Sopenharmony_ci        return true;
27cb93a386Sopenharmony_ci    }
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ciclass SkCornerPathEffectImpl : public SkPathEffectBase {
31cb93a386Sopenharmony_cipublic:
32cb93a386Sopenharmony_ci    explicit SkCornerPathEffectImpl(SkScalar radius) : fRadius(radius) {
33cb93a386Sopenharmony_ci        SkASSERT(radius > 0);
34cb93a386Sopenharmony_ci    }
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
37cb93a386Sopenharmony_ci                      const SkMatrix&) const override {
38cb93a386Sopenharmony_ci        if (fRadius <= 0) {
39cb93a386Sopenharmony_ci            return false;
40cb93a386Sopenharmony_ci        }
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci        SkPath::Iter    iter(src, false);
43cb93a386Sopenharmony_ci        SkPath::Verb    verb, prevVerb = SkPath::kDone_Verb;
44cb93a386Sopenharmony_ci        SkPoint         pts[4];
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci        bool        closed;
47cb93a386Sopenharmony_ci        SkPoint     moveTo, lastCorner;
48cb93a386Sopenharmony_ci        SkVector    firstStep, step;
49cb93a386Sopenharmony_ci        bool        prevIsValid = true;
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci        // to avoid warnings
52cb93a386Sopenharmony_ci        step.set(0, 0);
53cb93a386Sopenharmony_ci        moveTo.set(0, 0);
54cb93a386Sopenharmony_ci        firstStep.set(0, 0);
55cb93a386Sopenharmony_ci        lastCorner.set(0, 0);
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci        for (;;) {
58cb93a386Sopenharmony_ci            switch (verb = iter.next(pts)) {
59cb93a386Sopenharmony_ci                case SkPath::kMove_Verb:
60cb93a386Sopenharmony_ci                    // close out the previous (open) contour
61cb93a386Sopenharmony_ci                    if (SkPath::kLine_Verb == prevVerb) {
62cb93a386Sopenharmony_ci                        dst->lineTo(lastCorner);
63cb93a386Sopenharmony_ci                    }
64cb93a386Sopenharmony_ci                    closed = iter.isClosedContour();
65cb93a386Sopenharmony_ci                    if (closed) {
66cb93a386Sopenharmony_ci                        moveTo = pts[0];
67cb93a386Sopenharmony_ci                        prevIsValid = false;
68cb93a386Sopenharmony_ci                    } else {
69cb93a386Sopenharmony_ci                        dst->moveTo(pts[0]);
70cb93a386Sopenharmony_ci                        prevIsValid = true;
71cb93a386Sopenharmony_ci                    }
72cb93a386Sopenharmony_ci                    break;
73cb93a386Sopenharmony_ci                case SkPath::kLine_Verb: {
74cb93a386Sopenharmony_ci                    bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
75cb93a386Sopenharmony_ci                    // prev corner
76cb93a386Sopenharmony_ci                    if (!prevIsValid) {
77cb93a386Sopenharmony_ci                        dst->moveTo(moveTo + step);
78cb93a386Sopenharmony_ci                        prevIsValid = true;
79cb93a386Sopenharmony_ci                    } else {
80cb93a386Sopenharmony_ci                        dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
81cb93a386Sopenharmony_ci                                    pts[0].fY + step.fY);
82cb93a386Sopenharmony_ci                    }
83cb93a386Sopenharmony_ci                    if (drawSegment) {
84cb93a386Sopenharmony_ci                        dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
85cb93a386Sopenharmony_ci                    }
86cb93a386Sopenharmony_ci                    lastCorner = pts[1];
87cb93a386Sopenharmony_ci                    prevIsValid = true;
88cb93a386Sopenharmony_ci                    break;
89cb93a386Sopenharmony_ci                }
90cb93a386Sopenharmony_ci                case SkPath::kQuad_Verb:
91cb93a386Sopenharmony_ci                    // TBD - just replicate the curve for now
92cb93a386Sopenharmony_ci                    if (!prevIsValid) {
93cb93a386Sopenharmony_ci                        dst->moveTo(pts[0]);
94cb93a386Sopenharmony_ci                        prevIsValid = true;
95cb93a386Sopenharmony_ci                    }
96cb93a386Sopenharmony_ci                    dst->quadTo(pts[1], pts[2]);
97cb93a386Sopenharmony_ci                    lastCorner = pts[2];
98cb93a386Sopenharmony_ci                    firstStep.set(0, 0);
99cb93a386Sopenharmony_ci                    break;
100cb93a386Sopenharmony_ci                case SkPath::kConic_Verb:
101cb93a386Sopenharmony_ci                    // TBD - just replicate the curve for now
102cb93a386Sopenharmony_ci                    if (!prevIsValid) {
103cb93a386Sopenharmony_ci                        dst->moveTo(pts[0]);
104cb93a386Sopenharmony_ci                        prevIsValid = true;
105cb93a386Sopenharmony_ci                    }
106cb93a386Sopenharmony_ci                    dst->conicTo(pts[1], pts[2], iter.conicWeight());
107cb93a386Sopenharmony_ci                    lastCorner = pts[2];
108cb93a386Sopenharmony_ci                    firstStep.set(0, 0);
109cb93a386Sopenharmony_ci                    break;
110cb93a386Sopenharmony_ci                case SkPath::kCubic_Verb:
111cb93a386Sopenharmony_ci                    if (!prevIsValid) {
112cb93a386Sopenharmony_ci                        dst->moveTo(pts[0]);
113cb93a386Sopenharmony_ci                        prevIsValid = true;
114cb93a386Sopenharmony_ci                    }
115cb93a386Sopenharmony_ci                    // TBD - just replicate the curve for now
116cb93a386Sopenharmony_ci                    dst->cubicTo(pts[1], pts[2], pts[3]);
117cb93a386Sopenharmony_ci                    lastCorner = pts[3];
118cb93a386Sopenharmony_ci                    firstStep.set(0, 0);
119cb93a386Sopenharmony_ci                    break;
120cb93a386Sopenharmony_ci                case SkPath::kClose_Verb:
121cb93a386Sopenharmony_ci                    if (firstStep.fX || firstStep.fY) {
122cb93a386Sopenharmony_ci                        dst->quadTo(lastCorner.fX, lastCorner.fY,
123cb93a386Sopenharmony_ci                                    lastCorner.fX + firstStep.fX,
124cb93a386Sopenharmony_ci                                    lastCorner.fY + firstStep.fY);
125cb93a386Sopenharmony_ci                    }
126cb93a386Sopenharmony_ci                    dst->close();
127cb93a386Sopenharmony_ci                    prevIsValid = false;
128cb93a386Sopenharmony_ci                    break;
129cb93a386Sopenharmony_ci                case SkPath::kDone_Verb:
130cb93a386Sopenharmony_ci                    if (prevIsValid) {
131cb93a386Sopenharmony_ci                        dst->lineTo(lastCorner);
132cb93a386Sopenharmony_ci                    }
133cb93a386Sopenharmony_ci                    return true;
134cb93a386Sopenharmony_ci                default:
135cb93a386Sopenharmony_ci                    SkDEBUGFAIL("default should not be reached");
136cb93a386Sopenharmony_ci                    return false;
137cb93a386Sopenharmony_ci            }
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci            if (SkPath::kMove_Verb == prevVerb) {
140cb93a386Sopenharmony_ci                firstStep = step;
141cb93a386Sopenharmony_ci            }
142cb93a386Sopenharmony_ci            prevVerb = verb;
143cb93a386Sopenharmony_ci        }
144cb93a386Sopenharmony_ci        return true;
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci    bool computeFastBounds(SkRect*) const override {
148cb93a386Sopenharmony_ci        // Rounding sharp corners within a path produces a new path that is still contained within
149cb93a386Sopenharmony_ci        // the original's bounds, so leave 'bounds' unmodified.
150cb93a386Sopenharmony_ci        return true;
151cb93a386Sopenharmony_ci    }
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
154cb93a386Sopenharmony_ci        return SkCornerPathEffect::Make(buffer.readScalar());
155cb93a386Sopenharmony_ci    }
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci    void flatten(SkWriteBuffer& buffer) const override {
158cb93a386Sopenharmony_ci        buffer.writeScalar(fRadius);
159cb93a386Sopenharmony_ci    }
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci    Factory getFactory() const override { return CreateProc; }
162cb93a386Sopenharmony_ci    const char* getTypeName() const override { return "SkCornerPathEffect"; }
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ciprivate:
165cb93a386Sopenharmony_ci    const SkScalar fRadius;
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    using INHERITED = SkPathEffectBase;
168cb93a386Sopenharmony_ci};
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkCornerPathEffect::Make(SkScalar radius) {
173cb93a386Sopenharmony_ci    return SkScalarIsFinite(radius) && (radius > 0) ?
174cb93a386Sopenharmony_ci            sk_sp<SkPathEffect>(new SkCornerPathEffectImpl(radius)) : nullptr;
175cb93a386Sopenharmony_ci}
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_civoid SkCornerPathEffect::RegisterFlattenables() {
178cb93a386Sopenharmony_ci    SkFlattenable::Register("SkCornerPathEffect", SkCornerPathEffectImpl::CreateProc);
179cb93a386Sopenharmony_ci}
180