blob: 3c17bed52136fcb03edd533f576fafccbd4b34ee [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkPath.h"
9#include "include/core/SkRegion.h"
10#include "include/core/SkStrokeRec.h"
11#include "include/effects/Sk2DPathEffect.h"
12#include "src/core/SkReadBuffer.h"
13#include "src/core/SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
Mike Reedec87dc12021-05-20 15:16:34 -040015class Sk2DPathEffect : public SkPathEffect {
16public:
17 Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
18 // Calling invert will set the type mask on both matrices, making them thread safe.
19 fMatrixIsInvertible = fMatrix.invert(&fInverse);
20 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
Mike Reedec87dc12021-05-20 15:16:34 -040022protected:
23 /** New virtual, to be overridden by subclasses.
24 This is called once from filterPath, and provides the
25 uv parameter bounds for the path. Subsequent calls to
26 next() will receive u and v values within these bounds,
27 and then a call to end() will signal the end of processing.
28 */
29 virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
30 virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
31 virtual void end(SkPath* dst) const {}
32
33 /** Low-level virtual called per span of locations in the u-direction.
34 The default implementation calls next() repeatedly with each
35 location.
36 */
37 virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
38 if (!fMatrixIsInvertible) {
39 return;
40 }
41 #if defined(SK_BUILD_FOR_FUZZER)
42 if (count > 100) {
43 return;
44 }
45 #endif
46
47 const SkMatrix& mat = this->getMatrix();
48 SkPoint src, dst;
49
50 src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
51 do {
52 mat.mapPoints(&dst, &src, 1);
53 this->next(dst, x++, y, path);
54 src.fX += SK_Scalar1;
55 } while (--ucount > 0);
56 }
57
58 const SkMatrix& getMatrix() const { return fMatrix; }
59
60 void flatten(SkWriteBuffer& buffer) const override {
61 this->INHERITED::flatten(buffer);
62 buffer.writeMatrix(fMatrix);
63 }
64
65 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
66 const SkRect* cullRect) const override {
67 if (!fMatrixIsInvertible) {
68 return false;
69 }
70
71 SkPath tmp;
72 SkIRect ir;
73
74 src.transform(fInverse, &tmp);
75 tmp.getBounds().round(&ir);
76 if (!ir.isEmpty()) {
77 this->begin(ir, dst);
78
79 SkRegion rgn;
80 rgn.setPath(tmp, SkRegion(ir));
81 SkRegion::Iterator iter(rgn);
82 for (; !iter.done(); iter.next()) {
83 const SkIRect& rect = iter.rect();
84 for (int y = rect.fTop; y < rect.fBottom; ++y) {
85 this->nextSpan(rect.fLeft, y, rect.width(), dst);
86 }
87 }
88
89 this->end(dst);
90 }
91 return true;
92 }
93
94private:
95 SkMatrix fMatrix, fInverse;
96 bool fMatrixIsInvertible;
97
98 // For simplicity, assume fast bounds cannot be computed
99 bool computeFastBounds(SkRect*) const override { return false; }
100
101 friend class Sk2DPathEffectBlitter;
102 using INHERITED = SkPathEffect;
103};
104
105///////////////////////////////////////////////////////////////////////////////
106
107class SkLine2DPathEffectImpl : public Sk2DPathEffect {
108public:
109 SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
110 : Sk2DPathEffect(matrix)
111 , fWidth(width)
112 {
113 SkASSERT(width >= 0);
114 }
115
116 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
117 const SkRect* cullRect) const override {
118 if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
119 rec->setStrokeStyle(fWidth);
120 return true;
121 }
mike@reedtribe.org90bf4272012-04-14 19:06:16 +0000122 return false;
123 }
124
Mike Reedec87dc12021-05-20 15:16:34 -0400125 void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
126 if (ucount > 1) {
127 SkPoint src[2], dstP[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128
Mike Reedec87dc12021-05-20 15:16:34 -0400129 src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
130 src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
131 this->getMatrix().mapPoints(dstP, src, 2);
reed@google.com6db93752012-08-09 19:18:02 +0000132
Mike Reedec87dc12021-05-20 15:16:34 -0400133 dst->moveTo(dstP[0]);
134 dst->lineTo(dstP[1]);
reed@google.com6db93752012-08-09 19:18:02 +0000135 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137
Mike Reedec87dc12021-05-20 15:16:34 -0400138 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
139 SkMatrix matrix;
140 buffer.readMatrix(&matrix);
141 SkScalar width = buffer.readScalar();
142 return SkLine2DPathEffect::Make(width, matrix);
mike@reedtribe.org90bf4272012-04-14 19:06:16 +0000143 }
Mike Reedec87dc12021-05-20 15:16:34 -0400144
145 void flatten(SkWriteBuffer &buffer) const override {
146 buffer.writeMatrix(this->getMatrix());
147 buffer.writeScalar(fWidth);
Kevin Lubick493f89e2020-09-14 08:37:35 -0400148 }
mike@reedtribe.org90bf4272012-04-14 19:06:16 +0000149
Mike Reedec87dc12021-05-20 15:16:34 -0400150 Factory getFactory() const override { return CreateProc; }
151 const char* getTypeName() const override { return "SkLine2DPathEffect"; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152
Mike Reedec87dc12021-05-20 15:16:34 -0400153private:
154 SkScalar fWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155
Mike Reedec87dc12021-05-20 15:16:34 -0400156 using INHERITED = Sk2DPathEffect;
157};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
Mike Reedec87dc12021-05-20 15:16:34 -0400159/////////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160
Mike Reedec87dc12021-05-20 15:16:34 -0400161class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
162public:
163 SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164
Mike Reedec87dc12021-05-20 15:16:34 -0400165 void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
166 dst->addPath(fPath, loc.fX, loc.fY);
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000167 }
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000168
Mike Reedec87dc12021-05-20 15:16:34 -0400169 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
170 SkMatrix matrix;
171 buffer.readMatrix(&matrix);
172 SkPath path;
173 buffer.readPath(&path);
174 return SkPath2DPathEffect::Make(matrix, path);
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000175 }
Mike Reedec87dc12021-05-20 15:16:34 -0400176
177 void flatten(SkWriteBuffer& buffer) const override {
178 buffer.writeMatrix(this->getMatrix());
179 buffer.writePath(fPath);
180 }
181
182 Factory getFactory() const override { return CreateProc; }
183 const char* getTypeName() const override { return "SkPath2DPathEffect"; }
184
185private:
186 SkPath fPath;
187
188 using INHERITED = Sk2DPathEffect;
189};
190
191//////////////////////////////////////////////////////////////////////////////////////////////////
192
193sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
194 if (!(width >= 0)) {
195 return nullptr;
196 }
197 return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000198}
199
Mike Reedec87dc12021-05-20 15:16:34 -0400200sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
201 return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
reed9fa60da2014-08-21 07:59:51 -0700202}
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000203
Mike Reedec87dc12021-05-20 15:16:34 -0400204void SkLine2DPathEffect::RegisterFlattenables() {
205 SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000206}
207
Mike Reedec87dc12021-05-20 15:16:34 -0400208void SkPath2DPathEffect::RegisterFlattenables() {
209 SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
reed@google.com18dc4772011-08-09 18:47:40 +0000210}