blob: d35813d85a018bcece03cb3317e51c525e5e44f4 [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"
Mike Reedec9d0e82021-05-21 17:42:14 -040012#include "src/core/SkPathEffectBase.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkReadBuffer.h"
14#include "src/core/SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
Mike Reedec9d0e82021-05-21 17:42:14 -040016class Sk2DPathEffect : public SkPathEffectBase {
Mike Reedec87dc12021-05-20 15:16:34 -040017public:
18 Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
19 // Calling invert will set the type mask on both matrices, making them thread safe.
20 fMatrixIsInvertible = fMatrix.invert(&fInverse);
21 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000022
Mike Reedec87dc12021-05-20 15:16:34 -040023protected:
24 /** New virtual, to be overridden by subclasses.
25 This is called once from filterPath, and provides the
26 uv parameter bounds for the path. Subsequent calls to
27 next() will receive u and v values within these bounds,
28 and then a call to end() will signal the end of processing.
29 */
30 virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
31 virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
32 virtual void end(SkPath* dst) const {}
33
34 /** Low-level virtual called per span of locations in the u-direction.
35 The default implementation calls next() repeatedly with each
36 location.
37 */
38 virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
39 if (!fMatrixIsInvertible) {
40 return;
41 }
42 #if defined(SK_BUILD_FOR_FUZZER)
Michael Ludwigdb285de2021-09-16 11:46:13 -040043 if (ucount > 100) {
Mike Reedec87dc12021-05-20 15:16:34 -040044 return;
45 }
46 #endif
47
48 const SkMatrix& mat = this->getMatrix();
49 SkPoint src, dst;
50
51 src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
52 do {
53 mat.mapPoints(&dst, &src, 1);
54 this->next(dst, x++, y, path);
55 src.fX += SK_Scalar1;
56 } while (--ucount > 0);
57 }
58
59 const SkMatrix& getMatrix() const { return fMatrix; }
60
61 void flatten(SkWriteBuffer& buffer) const override {
62 this->INHERITED::flatten(buffer);
63 buffer.writeMatrix(fMatrix);
64 }
65
66 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -040067 const SkRect* cullRect, const SkMatrix&) const override {
Mike Reedec87dc12021-05-20 15:16:34 -040068 if (!fMatrixIsInvertible) {
69 return false;
70 }
71
72 SkPath tmp;
73 SkIRect ir;
74
75 src.transform(fInverse, &tmp);
76 tmp.getBounds().round(&ir);
77 if (!ir.isEmpty()) {
78 this->begin(ir, dst);
79
80 SkRegion rgn;
81 rgn.setPath(tmp, SkRegion(ir));
82 SkRegion::Iterator iter(rgn);
83 for (; !iter.done(); iter.next()) {
84 const SkIRect& rect = iter.rect();
85 for (int y = rect.fTop; y < rect.fBottom; ++y) {
86 this->nextSpan(rect.fLeft, y, rect.width(), dst);
87 }
88 }
89
90 this->end(dst);
91 }
92 return true;
93 }
94
95private:
96 SkMatrix fMatrix, fInverse;
97 bool fMatrixIsInvertible;
98
99 // For simplicity, assume fast bounds cannot be computed
100 bool computeFastBounds(SkRect*) const override { return false; }
101
102 friend class Sk2DPathEffectBlitter;
103 using INHERITED = SkPathEffect;
104};
105
106///////////////////////////////////////////////////////////////////////////////
107
108class SkLine2DPathEffectImpl : public Sk2DPathEffect {
109public:
110 SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
111 : Sk2DPathEffect(matrix)
112 , fWidth(width)
113 {
114 SkASSERT(width >= 0);
115 }
116
117 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -0400118 const SkRect* cullRect, const SkMatrix& ctm) const override {
119 if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) {
Mike Reedec87dc12021-05-20 15:16:34 -0400120 rec->setStrokeStyle(fWidth);
121 return true;
122 }
mike@reedtribe.org90bf4272012-04-14 19:06:16 +0000123 return false;
124 }
125
Mike Reedec87dc12021-05-20 15:16:34 -0400126 void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
127 if (ucount > 1) {
128 SkPoint src[2], dstP[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129
Mike Reedec87dc12021-05-20 15:16:34 -0400130 src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
131 src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
132 this->getMatrix().mapPoints(dstP, src, 2);
reed@google.com6db93752012-08-09 19:18:02 +0000133
Mike Reedec87dc12021-05-20 15:16:34 -0400134 dst->moveTo(dstP[0]);
135 dst->lineTo(dstP[1]);
reed@google.com6db93752012-08-09 19:18:02 +0000136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138
Mike Reedec87dc12021-05-20 15:16:34 -0400139 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
140 SkMatrix matrix;
141 buffer.readMatrix(&matrix);
142 SkScalar width = buffer.readScalar();
143 return SkLine2DPathEffect::Make(width, matrix);
mike@reedtribe.org90bf4272012-04-14 19:06:16 +0000144 }
Mike Reedec87dc12021-05-20 15:16:34 -0400145
146 void flatten(SkWriteBuffer &buffer) const override {
147 buffer.writeMatrix(this->getMatrix());
148 buffer.writeScalar(fWidth);
Kevin Lubick493f89e2020-09-14 08:37:35 -0400149 }
mike@reedtribe.org90bf4272012-04-14 19:06:16 +0000150
Mike Reedec87dc12021-05-20 15:16:34 -0400151 Factory getFactory() const override { return CreateProc; }
152 const char* getTypeName() const override { return "SkLine2DPathEffect"; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153
Mike Reedec87dc12021-05-20 15:16:34 -0400154private:
155 SkScalar fWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156
Mike Reedec87dc12021-05-20 15:16:34 -0400157 using INHERITED = Sk2DPathEffect;
158};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159
Mike Reedec87dc12021-05-20 15:16:34 -0400160/////////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161
Mike Reedec87dc12021-05-20 15:16:34 -0400162class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
163public:
164 SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165
Mike Reedec87dc12021-05-20 15:16:34 -0400166 void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
167 dst->addPath(fPath, loc.fX, loc.fY);
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000168 }
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000169
Mike Reedec87dc12021-05-20 15:16:34 -0400170 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
171 SkMatrix matrix;
172 buffer.readMatrix(&matrix);
173 SkPath path;
174 buffer.readPath(&path);
175 return SkPath2DPathEffect::Make(matrix, path);
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000176 }
Mike Reedec87dc12021-05-20 15:16:34 -0400177
178 void flatten(SkWriteBuffer& buffer) const override {
179 buffer.writeMatrix(this->getMatrix());
180 buffer.writePath(fPath);
181 }
182
183 Factory getFactory() const override { return CreateProc; }
184 const char* getTypeName() const override { return "SkPath2DPathEffect"; }
185
186private:
187 SkPath fPath;
188
189 using INHERITED = Sk2DPathEffect;
190};
191
192//////////////////////////////////////////////////////////////////////////////////////////////////
193
194sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
195 if (!(width >= 0)) {
196 return nullptr;
197 }
198 return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000199}
200
Mike Reedec87dc12021-05-20 15:16:34 -0400201sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
202 return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
reed9fa60da2014-08-21 07:59:51 -0700203}
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000204
Mike Reedec87dc12021-05-20 15:16:34 -0400205void SkLine2DPathEffect::RegisterFlattenables() {
206 SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000207}
208
Mike Reedec87dc12021-05-20 15:16:34 -0400209void SkPath2DPathEffect::RegisterFlattenables() {
210 SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
reed@google.com18dc4772011-08-09 18:47:40 +0000211}