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#include "include/core/SkPath.h"
9cb93a386Sopenharmony_ci#include "include/core/SkRegion.h"
10cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h"
11cb93a386Sopenharmony_ci#include "include/effects/Sk2DPathEffect.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_ciclass Sk2DPathEffect : public SkPathEffectBase {
17cb93a386Sopenharmony_cipublic:
18cb93a386Sopenharmony_ci    Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
19cb93a386Sopenharmony_ci        // Calling invert will set the type mask on both matrices, making them thread safe.
20cb93a386Sopenharmony_ci        fMatrixIsInvertible = fMatrix.invert(&fInverse);
21cb93a386Sopenharmony_ci    }
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciprotected:
24cb93a386Sopenharmony_ci    /** New virtual, to be overridden by subclasses.
25cb93a386Sopenharmony_ci        This is called once from filterPath, and provides the
26cb93a386Sopenharmony_ci        uv parameter bounds for the path. Subsequent calls to
27cb93a386Sopenharmony_ci        next() will receive u and v values within these bounds,
28cb93a386Sopenharmony_ci        and then a call to end() will signal the end of processing.
29cb93a386Sopenharmony_ci    */
30cb93a386Sopenharmony_ci    virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
31cb93a386Sopenharmony_ci    virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
32cb93a386Sopenharmony_ci    virtual void end(SkPath* dst) const {}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    /** Low-level virtual called per span of locations in the u-direction.
35cb93a386Sopenharmony_ci        The default implementation calls next() repeatedly with each
36cb93a386Sopenharmony_ci        location.
37cb93a386Sopenharmony_ci    */
38cb93a386Sopenharmony_ci    virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
39cb93a386Sopenharmony_ci        if (!fMatrixIsInvertible) {
40cb93a386Sopenharmony_ci            return;
41cb93a386Sopenharmony_ci        }
42cb93a386Sopenharmony_ci    #if defined(SK_BUILD_FOR_FUZZER)
43cb93a386Sopenharmony_ci        if (ucount > 100) {
44cb93a386Sopenharmony_ci            return;
45cb93a386Sopenharmony_ci        }
46cb93a386Sopenharmony_ci    #endif
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci        const SkMatrix& mat = this->getMatrix();
49cb93a386Sopenharmony_ci        SkPoint src, dst;
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci        src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
52cb93a386Sopenharmony_ci        do {
53cb93a386Sopenharmony_ci            mat.mapPoints(&dst, &src, 1);
54cb93a386Sopenharmony_ci            this->next(dst, x++, y, path);
55cb93a386Sopenharmony_ci            src.fX += SK_Scalar1;
56cb93a386Sopenharmony_ci        } while (--ucount > 0);
57cb93a386Sopenharmony_ci    }
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    const SkMatrix& getMatrix() const { return fMatrix; }
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    void flatten(SkWriteBuffer& buffer) const override {
62cb93a386Sopenharmony_ci        this->INHERITED::flatten(buffer);
63cb93a386Sopenharmony_ci        buffer.writeMatrix(fMatrix);
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
67cb93a386Sopenharmony_ci                      const SkRect* cullRect, const SkMatrix&) const override {
68cb93a386Sopenharmony_ci        if (!fMatrixIsInvertible) {
69cb93a386Sopenharmony_ci            return false;
70cb93a386Sopenharmony_ci        }
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci        SkPath  tmp;
73cb93a386Sopenharmony_ci        SkIRect ir;
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci        src.transform(fInverse, &tmp);
76cb93a386Sopenharmony_ci        tmp.getBounds().round(&ir);
77cb93a386Sopenharmony_ci        if (!ir.isEmpty()) {
78cb93a386Sopenharmony_ci            this->begin(ir, dst);
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci            SkRegion rgn;
81cb93a386Sopenharmony_ci            rgn.setPath(tmp, SkRegion(ir));
82cb93a386Sopenharmony_ci            SkRegion::Iterator iter(rgn);
83cb93a386Sopenharmony_ci            for (; !iter.done(); iter.next()) {
84cb93a386Sopenharmony_ci                const SkIRect& rect = iter.rect();
85cb93a386Sopenharmony_ci                for (int y = rect.fTop; y < rect.fBottom; ++y) {
86cb93a386Sopenharmony_ci                    this->nextSpan(rect.fLeft, y, rect.width(), dst);
87cb93a386Sopenharmony_ci                }
88cb93a386Sopenharmony_ci            }
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci            this->end(dst);
91cb93a386Sopenharmony_ci        }
92cb93a386Sopenharmony_ci        return true;
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ciprivate:
96cb93a386Sopenharmony_ci    SkMatrix    fMatrix, fInverse;
97cb93a386Sopenharmony_ci    bool        fMatrixIsInvertible;
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    // For simplicity, assume fast bounds cannot be computed
100cb93a386Sopenharmony_ci    bool computeFastBounds(SkRect*) const override { return false; }
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci    friend class Sk2DPathEffectBlitter;
103cb93a386Sopenharmony_ci    using INHERITED = SkPathEffect;
104cb93a386Sopenharmony_ci};
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ciclass SkLine2DPathEffectImpl : public Sk2DPathEffect {
109cb93a386Sopenharmony_cipublic:
110cb93a386Sopenharmony_ci    SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
111cb93a386Sopenharmony_ci        : Sk2DPathEffect(matrix)
112cb93a386Sopenharmony_ci        , fWidth(width)
113cb93a386Sopenharmony_ci    {
114cb93a386Sopenharmony_ci        SkASSERT(width >= 0);
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
118cb93a386Sopenharmony_ci                      const SkRect* cullRect, const SkMatrix& ctm) const override {
119cb93a386Sopenharmony_ci        if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) {
120cb93a386Sopenharmony_ci            rec->setStrokeStyle(fWidth);
121cb93a386Sopenharmony_ci            return true;
122cb93a386Sopenharmony_ci        }
123cb93a386Sopenharmony_ci        return false;
124cb93a386Sopenharmony_ci    }
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
127cb93a386Sopenharmony_ci        if (ucount > 1) {
128cb93a386Sopenharmony_ci            SkPoint    src[2], dstP[2];
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci            src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
131cb93a386Sopenharmony_ci            src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
132cb93a386Sopenharmony_ci            this->getMatrix().mapPoints(dstP, src, 2);
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci            dst->moveTo(dstP[0]);
135cb93a386Sopenharmony_ci            dst->lineTo(dstP[1]);
136cb93a386Sopenharmony_ci        }
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
140cb93a386Sopenharmony_ci        SkMatrix matrix;
141cb93a386Sopenharmony_ci        buffer.readMatrix(&matrix);
142cb93a386Sopenharmony_ci        SkScalar width = buffer.readScalar();
143cb93a386Sopenharmony_ci        return SkLine2DPathEffect::Make(width, matrix);
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    void flatten(SkWriteBuffer &buffer) const override {
147cb93a386Sopenharmony_ci        buffer.writeMatrix(this->getMatrix());
148cb93a386Sopenharmony_ci        buffer.writeScalar(fWidth);
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    Factory getFactory() const override { return CreateProc; }
152cb93a386Sopenharmony_ci    const char* getTypeName() const override { return "SkLine2DPathEffectImpl"; }
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ciprivate:
155cb93a386Sopenharmony_ci    SkScalar fWidth;
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci    using INHERITED = Sk2DPathEffect;
158cb93a386Sopenharmony_ci};
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ciclass SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
163cb93a386Sopenharmony_cipublic:
164cb93a386Sopenharmony_ci    SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
167cb93a386Sopenharmony_ci        dst->addPath(fPath, loc.fX, loc.fY);
168cb93a386Sopenharmony_ci    }
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
171cb93a386Sopenharmony_ci        SkMatrix matrix;
172cb93a386Sopenharmony_ci        buffer.readMatrix(&matrix);
173cb93a386Sopenharmony_ci        SkPath path;
174cb93a386Sopenharmony_ci        buffer.readPath(&path);
175cb93a386Sopenharmony_ci        return SkPath2DPathEffect::Make(matrix, path);
176cb93a386Sopenharmony_ci    }
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci    void flatten(SkWriteBuffer& buffer) const override {
179cb93a386Sopenharmony_ci        buffer.writeMatrix(this->getMatrix());
180cb93a386Sopenharmony_ci        buffer.writePath(fPath);
181cb93a386Sopenharmony_ci    }
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci    Factory getFactory() const override { return CreateProc; }
184cb93a386Sopenharmony_ci    const char* getTypeName() const override { return "SkPath2DPathEffectImpl"; }
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ciprivate:
187cb93a386Sopenharmony_ci    SkPath  fPath;
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci    using INHERITED = Sk2DPathEffect;
190cb93a386Sopenharmony_ci};
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
195cb93a386Sopenharmony_ci    if (!(width >= 0)) {
196cb93a386Sopenharmony_ci        return nullptr;
197cb93a386Sopenharmony_ci    }
198cb93a386Sopenharmony_ci    return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
199cb93a386Sopenharmony_ci}
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
202cb93a386Sopenharmony_ci    return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
203cb93a386Sopenharmony_ci}
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_civoid SkLine2DPathEffect::RegisterFlattenables() {
206cb93a386Sopenharmony_ci    SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
207cb93a386Sopenharmony_ci}
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_civoid SkPath2DPathEffect::RegisterFlattenables() {
210cb93a386Sopenharmony_ci    SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
211cb93a386Sopenharmony_ci}
212