blob: dd9a978f5df849a17e20ceccfa717cd63fed2bc4 [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"
Mike Reedec9d0e82021-05-21 17:42:14 -04009#include "include/effects/SkOpPathEffect.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,
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -040024 const SkRect* cull, const SkMatrix& ctm) const {
Mike Reed0ef539a2018-07-18 13:28:42 -040025 SkPath one, two;
26 if (fOne) {
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -040027 if (!fOne->filterPath(&one, src, rec, cull, ctm)) {
Mike Reed0ef539a2018-07-18 13:28:42 -040028 return false;
29 }
30 } else {
31 one = src;
32 }
33 if (fTwo) {
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -040034 if (!fTwo->filterPath(&two, src, rec, cull, ctm)) {
Mike Reed0ef539a2018-07-18 13:28:42 -040035 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) {
Mike Reedec9d0e82021-05-21 17:42:14 -040045 return (!SkToBool(fOne) || as_PEB(fOne)->computeFastBounds(nullptr)) &&
46 (!SkToBool(fTwo) || as_PEB(fTwo)->computeFastBounds(nullptr));
Michael Ludwig4e1c1a72021-05-11 11:39:36 -040047 }
48
49 // bounds will hold the result of the fOne while b2 holds the result of fTwo's fast bounds
50 SkRect b2 = *bounds;
Mike Reedec9d0e82021-05-21 17:42:14 -040051 if (fOne && !as_PEB(fOne)->computeFastBounds(bounds)) {
Michael Ludwig4e1c1a72021-05-11 11:39:36 -040052 return false;
53 }
Mike Reedec9d0e82021-05-21 17:42:14 -040054 if (fTwo && !as_PEB(fTwo)->computeFastBounds(&b2)) {
Michael Ludwig4e1c1a72021-05-11 11:39:36 -040055 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
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -0400114bool SkMatrixPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
115 const SkMatrix&) const {
Mike Reed0ef539a2018-07-18 13:28:42 -0400116 src.transform(fMatrix, dst);
117 return true;
118}
119
120void SkMatrixPE::flatten(SkWriteBuffer& buffer) const {
121 buffer.writeMatrix(fMatrix);
122}
123
124sk_sp<SkFlattenable> SkMatrixPE::CreateProc(SkReadBuffer& buffer) {
125 SkMatrix mx;
126 buffer.readMatrix(&mx);
127 return buffer.isValid() ? SkMatrixPathEffect::Make(mx) : nullptr;
128}
129
130//////////////////////////////////////////////////////////////////////////////////////////////////
131
132sk_sp<SkPathEffect> SkStrokePathEffect::Make(SkScalar width, SkPaint::Join join, SkPaint::Cap cap,
133 SkScalar miter) {
134 if (!SkScalarsAreFinite(width, miter) || width < 0 || miter < 0) {
135 return nullptr;
136 }
137 return sk_sp<SkPathEffect>(new SkStrokePE(width, join, cap, miter));
138}
139
140SkStrokePE::SkStrokePE(SkScalar width, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
141 : fWidth(width), fMiter(miter), fJoin(join), fCap(cap) {}
142
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -0400143bool SkStrokePE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
144 const SkMatrix&) const {
Mike Reed0ef539a2018-07-18 13:28:42 -0400145 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
146 rec.setStrokeStyle(fWidth);
147 rec.setStrokeParams(fCap, fJoin, fMiter);
148 return rec.applyToPath(dst, src);
149}
150
Michael Ludwig4e1c1a72021-05-11 11:39:36 -0400151bool SkStrokePE::computeFastBounds(SkRect* bounds) const {
152 if (bounds) {
153 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
154 rec.setStrokeStyle(fWidth);
155 rec.setStrokeParams(fCap, fJoin, fMiter);
156 bounds->outset(rec.getInflationRadius(), rec.getInflationRadius());
157 }
158 return true;
159}
160
Mike Reed0ef539a2018-07-18 13:28:42 -0400161void SkStrokePE::flatten(SkWriteBuffer& buffer) const {
162 buffer.writeScalar(fWidth);
163 buffer.writeScalar(fMiter);
164 buffer.write32(fJoin);
165 buffer.write32(fCap);
166}
167
168sk_sp<SkFlattenable> SkStrokePE::CreateProc(SkReadBuffer& buffer) {
169 SkScalar width = buffer.readScalar();
170 SkScalar miter = buffer.readScalar();
171 SkPaint::Join join = buffer.read32LE(SkPaint::kLast_Join);
172 SkPaint::Cap cap = buffer.read32LE(SkPaint::kLast_Cap);
173 return buffer.isValid() ? SkStrokePathEffect::Make(width, join, cap, miter) : nullptr;
174}
175
Mike Reed3e843122020-05-20 09:55:58 -0400176//////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reed0ef539a2018-07-18 13:28:42 -0400177
Mike Reed3e843122020-05-20 09:55:58 -0400178#include "include/effects/SkStrokeAndFillPathEffect.h"
179#include "src/core/SkPathPriv.h"
180
181sk_sp<SkPathEffect> SkStrokeAndFillPathEffect::Make() {
Mike Reedb6d158a2020-05-23 09:06:51 -0400182 static SkPathEffect* strokeAndFill = new SkStrokeAndFillPE;
183 return sk_ref_sp(strokeAndFill);
Mike Reed3e843122020-05-20 09:55:58 -0400184}
185
186void SkStrokeAndFillPE::flatten(SkWriteBuffer&) const {}
187
Mike Reed9ded74e2020-05-20 17:01:56 -0400188static bool known_to_be_opposite_directions(const SkPath& a, const SkPath& b) {
Mike Reed85f51b22020-08-30 10:32:06 -0400189 auto a_dir = SkPathPriv::ComputeFirstDirection(a),
190 b_dir = SkPathPriv::ComputeFirstDirection(b);
Mike Reed9ded74e2020-05-20 17:01:56 -0400191
Mike Reed3872c982020-08-29 17:46:51 -0400192 return (a_dir == SkPathFirstDirection::kCCW &&
193 b_dir == SkPathFirstDirection::kCW)
Mike Reed9ded74e2020-05-20 17:01:56 -0400194 ||
Mike Reed3872c982020-08-29 17:46:51 -0400195 (a_dir == SkPathFirstDirection::kCW &&
196 b_dir == SkPathFirstDirection::kCCW);
Mike Reed9ded74e2020-05-20 17:01:56 -0400197}
198
Mike Reed3e843122020-05-20 09:55:58 -0400199bool SkStrokeAndFillPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
Tyler Dennistonf8b7c1a2021-07-13 13:22:19 -0400200 const SkRect*, const SkMatrix&) const {
Mike Reed3e843122020-05-20 09:55:58 -0400201 // This one is weird, since we exist to allow this paint-style to go away. If we see it,
202 // just let the normal machine run its course.
203 if (rec->getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
204 *dst = src;
205 return true;
206 }
207
208 if (rec->getStyle() == SkStrokeRec::kStroke_Style) {
209 if (!rec->applyToPath(dst, src)) {
210 return false;
211 }
Mike Reed9ded74e2020-05-20 17:01:56 -0400212
213 if (known_to_be_opposite_directions(src, *dst)) {
Mike Reed3e843122020-05-20 09:55:58 -0400214 dst->reverseAddPath(src);
215 } else {
216 dst->addPath(src);
217 }
218 } else {
219 *dst = src;
220 }
221 rec->setFillStyle();
222 return true;
223}
224
225sk_sp<SkFlattenable> SkStrokeAndFillPE::CreateProc(SkReadBuffer& buffer) {
226 return SkStrokeAndFillPathEffect::Make();
227}