blob: e39cb0c41c1cc4ce6ff35ecdc122cbaf87179e68 [file] [log] [blame]
Mike Reed0ef539a2018-07-18 13:28:42 -04001/*
2 * Copyright 2018 Google Inc.
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/SkStrokeRec.h"
Michael Ludwig4e1c1a72021-05-11 11:39:36 -04009#include "src/core/SkPathEffectPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/core/SkReadBuffer.h"
Michael Ludwig4e1c1a72021-05-11 11:39:36 -040011#include "src/core/SkRectPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/core/SkWriteBuffer.h"
13#include "src/effects/SkOpPE.h"
Mike Reed0ef539a2018-07-18 13:28:42 -040014
Mike Reed310f44d2018-07-19 13:47:44 -040015sk_sp<SkPathEffect> SkMergePathEffect::Make(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two,
16 SkPathOp op) {
Mike Reed0ef539a2018-07-18 13:28:42 -040017 return sk_sp<SkPathEffect>(new SkOpPE(std::move(one), std::move(two), op));
18}
19
20SkOpPE::SkOpPE(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two, SkPathOp op)
21 : fOne(std::move(one)), fTwo(std::move(two)), fOp(op) {}
22
Mike Reed6d10f8b2018-08-16 13:22:16 -040023bool SkOpPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
24 const SkRect* cull) const {
Mike Reed0ef539a2018-07-18 13:28:42 -040025 SkPath one, two;
26 if (fOne) {
27 if (!fOne->filterPath(&one, src, rec, cull)) {
28 return false;
29 }
30 } else {
31 one = src;
32 }
33 if (fTwo) {
34 if (!fTwo->filterPath(&two, src, rec, cull)) {
35 return false;
36 }
37 } else {
38 two = src;
39 }
40 return Op(one, two, fOp, dst);
41}
42
Michael Ludwig4e1c1a72021-05-11 11:39:36 -040043bool SkOpPE::computeFastBounds(SkRect* bounds) const {
44 if (!bounds) {
45 return (!SkToBool(fOne) || SkPathEffectPriv::ComputeFastBounds(fOne.get(), nullptr)) &&
46 (!SkToBool(fTwo) || SkPathEffectPriv::ComputeFastBounds(fTwo.get(), nullptr));
47 }
48
49 // bounds will hold the result of the fOne while b2 holds the result of fTwo's fast bounds
50 SkRect b2 = *bounds;
51 if (fOne && !SkPathEffectPriv::ComputeFastBounds(fOne.get(), bounds)) {
52 return false;
53 }
54 if (fTwo && !SkPathEffectPriv::ComputeFastBounds(fTwo.get(), &b2)) {
55 return false;
56 }
57
58 switch (fOp) {
59 case SkPathOp::kIntersect_SkPathOp:
60 if (!bounds->intersect(b2)) {
61 bounds->setEmpty();
62 }
63 break;
64 case SkPathOp::kDifference_SkPathOp:
65 // (one - two) conservatively leaves one's bounds unmodified
66 break;
67 case SkPathOp::kReverseDifference_SkPathOp:
68 // (two - one) conservatively leaves two's bounds unmodified
69 *bounds = b2;
70 break;
71 case SkPathOp::kXOR_SkPathOp:
72 // fall through to union since XOR computes a subset of regular OR
73 case SkPathOp::kUnion_SkPathOp:
74 bounds->join(b2);
75 break;
76 }
77
78 return true;
79}
80
Mike Reed0ef539a2018-07-18 13:28:42 -040081void SkOpPE::flatten(SkWriteBuffer& buffer) const {
82 buffer.writeFlattenable(fOne.get());
83 buffer.writeFlattenable(fTwo.get());
84 buffer.write32(fOp);
85}
86
87sk_sp<SkFlattenable> SkOpPE::CreateProc(SkReadBuffer& buffer) {
88 auto one = buffer.readPathEffect();
89 auto two = buffer.readPathEffect();
90 SkPathOp op = buffer.read32LE(kReverseDifference_SkPathOp);
Mike Reed310f44d2018-07-19 13:47:44 -040091 return buffer.isValid() ? SkMergePathEffect::Make(std::move(one), std::move(two), op) : nullptr;
Mike Reed0ef539a2018-07-18 13:28:42 -040092}
93
94//////////////////////////////////////////////////////////////////////////////////////////////////
95
96sk_sp<SkPathEffect> SkMatrixPathEffect::MakeTranslate(SkScalar dx, SkScalar dy) {
97 if (!SkScalarsAreFinite(dx, dy)) {
98 return nullptr;
99 }
Mike Reed1f607332020-05-21 12:11:27 -0400100 return sk_sp<SkPathEffect>(new SkMatrixPE(SkMatrix::Translate(dx, dy)));
Mike Reed0ef539a2018-07-18 13:28:42 -0400101}
102
103sk_sp<SkPathEffect> SkMatrixPathEffect::Make(const SkMatrix& matrix) {
104 if (!matrix.isFinite()) {
105 return nullptr;
106 }
107 return sk_sp<SkPathEffect>(new SkMatrixPE(matrix));
108}
109
110SkMatrixPE::SkMatrixPE(const SkMatrix& matrix) : fMatrix(matrix) {
111 SkASSERT(matrix.isFinite());
112}
113
Mike Reed6d10f8b2018-08-16 13:22:16 -0400114bool SkMatrixPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const {
Mike Reed0ef539a2018-07-18 13:28:42 -0400115 src.transform(fMatrix, dst);
116 return true;
117}
118
119void SkMatrixPE::flatten(SkWriteBuffer& buffer) const {
120 buffer.writeMatrix(fMatrix);
121}
122
123sk_sp<SkFlattenable> SkMatrixPE::CreateProc(SkReadBuffer& buffer) {
124 SkMatrix mx;
125 buffer.readMatrix(&mx);
126 return buffer.isValid() ? SkMatrixPathEffect::Make(mx) : nullptr;
127}
128
129//////////////////////////////////////////////////////////////////////////////////////////////////
130
131sk_sp<SkPathEffect> SkStrokePathEffect::Make(SkScalar width, SkPaint::Join join, SkPaint::Cap cap,
132 SkScalar miter) {
133 if (!SkScalarsAreFinite(width, miter) || width < 0 || miter < 0) {
134 return nullptr;
135 }
136 return sk_sp<SkPathEffect>(new SkStrokePE(width, join, cap, miter));
137}
138
139SkStrokePE::SkStrokePE(SkScalar width, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
140 : fWidth(width), fMiter(miter), fJoin(join), fCap(cap) {}
141
Mike Reed6d10f8b2018-08-16 13:22:16 -0400142bool SkStrokePE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const {
Mike Reed0ef539a2018-07-18 13:28:42 -0400143 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
144 rec.setStrokeStyle(fWidth);
145 rec.setStrokeParams(fCap, fJoin, fMiter);
146 return rec.applyToPath(dst, src);
147}
148
Michael Ludwig4e1c1a72021-05-11 11:39:36 -0400149bool SkStrokePE::computeFastBounds(SkRect* bounds) const {
150 if (bounds) {
151 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
152 rec.setStrokeStyle(fWidth);
153 rec.setStrokeParams(fCap, fJoin, fMiter);
154 bounds->outset(rec.getInflationRadius(), rec.getInflationRadius());
155 }
156 return true;
157}
158
Mike Reed0ef539a2018-07-18 13:28:42 -0400159void SkStrokePE::flatten(SkWriteBuffer& buffer) const {
160 buffer.writeScalar(fWidth);
161 buffer.writeScalar(fMiter);
162 buffer.write32(fJoin);
163 buffer.write32(fCap);
164}
165
166sk_sp<SkFlattenable> SkStrokePE::CreateProc(SkReadBuffer& buffer) {
167 SkScalar width = buffer.readScalar();
168 SkScalar miter = buffer.readScalar();
169 SkPaint::Join join = buffer.read32LE(SkPaint::kLast_Join);
170 SkPaint::Cap cap = buffer.read32LE(SkPaint::kLast_Cap);
171 return buffer.isValid() ? SkStrokePathEffect::Make(width, join, cap, miter) : nullptr;
172}
173
Mike Reed3e843122020-05-20 09:55:58 -0400174//////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reed0ef539a2018-07-18 13:28:42 -0400175
Mike Reed3e843122020-05-20 09:55:58 -0400176#include "include/effects/SkStrokeAndFillPathEffect.h"
177#include "src/core/SkPathPriv.h"
178
179sk_sp<SkPathEffect> SkStrokeAndFillPathEffect::Make() {
Mike Reedb6d158a2020-05-23 09:06:51 -0400180 static SkPathEffect* strokeAndFill = new SkStrokeAndFillPE;
181 return sk_ref_sp(strokeAndFill);
Mike Reed3e843122020-05-20 09:55:58 -0400182}
183
184void SkStrokeAndFillPE::flatten(SkWriteBuffer&) const {}
185
Mike Reed9ded74e2020-05-20 17:01:56 -0400186static bool known_to_be_opposite_directions(const SkPath& a, const SkPath& b) {
Mike Reed85f51b22020-08-30 10:32:06 -0400187 auto a_dir = SkPathPriv::ComputeFirstDirection(a),
188 b_dir = SkPathPriv::ComputeFirstDirection(b);
Mike Reed9ded74e2020-05-20 17:01:56 -0400189
Mike Reed3872c982020-08-29 17:46:51 -0400190 return (a_dir == SkPathFirstDirection::kCCW &&
191 b_dir == SkPathFirstDirection::kCW)
Mike Reed9ded74e2020-05-20 17:01:56 -0400192 ||
Mike Reed3872c982020-08-29 17:46:51 -0400193 (a_dir == SkPathFirstDirection::kCW &&
194 b_dir == SkPathFirstDirection::kCCW);
Mike Reed9ded74e2020-05-20 17:01:56 -0400195}
196
Mike Reed3e843122020-05-20 09:55:58 -0400197bool SkStrokeAndFillPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
198 const SkRect*) const {
199 // This one is weird, since we exist to allow this paint-style to go away. If we see it,
200 // just let the normal machine run its course.
201 if (rec->getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
202 *dst = src;
203 return true;
204 }
205
206 if (rec->getStyle() == SkStrokeRec::kStroke_Style) {
207 if (!rec->applyToPath(dst, src)) {
208 return false;
209 }
Mike Reed9ded74e2020-05-20 17:01:56 -0400210
211 if (known_to_be_opposite_directions(src, *dst)) {
Mike Reed3e843122020-05-20 09:55:58 -0400212 dst->reverseAddPath(src);
213 } else {
214 dst->addPath(src);
215 }
216 } else {
217 *dst = src;
218 }
219 rec->setFillStyle();
220 return true;
221}
222
223sk_sp<SkFlattenable> SkStrokeAndFillPE::CreateProc(SkReadBuffer& buffer) {
224 return SkStrokeAndFillPathEffect::Make();
225}