• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "include/core/SkStrokeRec.h"
9 #include "include/effects/SkOpPathEffect.h"
10 #include "src/core/SkReadBuffer.h"
11 #include "src/core/SkRectPriv.h"
12 #include "src/core/SkWriteBuffer.h"
13 #include "src/effects/SkOpPE.h"
14 
Make(sk_sp<SkPathEffect> one,sk_sp<SkPathEffect> two,SkPathOp op)15 sk_sp<SkPathEffect> SkMergePathEffect::Make(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two,
16                                             SkPathOp op) {
17     return sk_sp<SkPathEffect>(new SkOpPE(std::move(one), std::move(two), op));
18 }
19 
SkOpPE(sk_sp<SkPathEffect> one,sk_sp<SkPathEffect> two,SkPathOp op)20 SkOpPE::SkOpPE(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two, SkPathOp op)
21     : fOne(std::move(one)), fTwo(std::move(two)), fOp(op) {}
22 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cull,const SkMatrix & ctm) const23 bool SkOpPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
24                           const SkRect* cull, const SkMatrix& ctm) const {
25     SkPath one, two;
26     if (fOne) {
27         if (!fOne->filterPath(&one, src, rec, cull, ctm)) {
28             return false;
29         }
30     } else {
31         one = src;
32     }
33     if (fTwo) {
34         if (!fTwo->filterPath(&two, src, rec, cull, ctm)) {
35             return false;
36         }
37     } else {
38         two = src;
39     }
40     return Op(one, two, fOp, dst);
41 }
42 
computeFastBounds(SkRect * bounds) const43 bool SkOpPE::computeFastBounds(SkRect* bounds) const {
44     if (!bounds) {
45         return (!SkToBool(fOne) || as_PEB(fOne)->computeFastBounds(nullptr)) &&
46                (!SkToBool(fTwo) || as_PEB(fTwo)->computeFastBounds(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 && !as_PEB(fOne)->computeFastBounds(bounds)) {
52         return false;
53     }
54     if (fTwo && !as_PEB(fTwo)->computeFastBounds(&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 
flatten(SkWriteBuffer & buffer) const81 void SkOpPE::flatten(SkWriteBuffer& buffer) const {
82     buffer.writeFlattenable(fOne.get());
83     buffer.writeFlattenable(fTwo.get());
84     buffer.write32(fOp);
85 }
86 
CreateProc(SkReadBuffer & buffer)87 sk_sp<SkFlattenable> SkOpPE::CreateProc(SkReadBuffer& buffer) {
88     auto one = buffer.readPathEffect();
89     auto two = buffer.readPathEffect();
90     SkPathOp op = buffer.read32LE(kReverseDifference_SkPathOp);
91     return buffer.isValid() ? SkMergePathEffect::Make(std::move(one), std::move(two), op) : nullptr;
92 }
93 
94 //////////////////////////////////////////////////////////////////////////////////////////////////
95 
MakeTranslate(SkScalar dx,SkScalar dy)96 sk_sp<SkPathEffect> SkMatrixPathEffect::MakeTranslate(SkScalar dx, SkScalar dy) {
97     if (!SkScalarsAreFinite(dx, dy)) {
98         return nullptr;
99     }
100     return sk_sp<SkPathEffect>(new SkMatrixPE(SkMatrix::Translate(dx, dy)));
101 }
102 
Make(const SkMatrix & matrix)103 sk_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 
SkMatrixPE(const SkMatrix & matrix)110 SkMatrixPE::SkMatrixPE(const SkMatrix& matrix) : fMatrix(matrix) {
111     SkASSERT(matrix.isFinite());
112 }
113 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *,const SkMatrix &) const114 bool SkMatrixPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
115                               const SkMatrix&) const {
116     src.transform(fMatrix, dst);
117     return true;
118 }
119 
flatten(SkWriteBuffer & buffer) const120 void SkMatrixPE::flatten(SkWriteBuffer& buffer) const {
121     buffer.writeMatrix(fMatrix);
122 }
123 
CreateProc(SkReadBuffer & buffer)124 sk_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 
Make(SkScalar width,SkPaint::Join join,SkPaint::Cap cap,SkScalar miter)132 sk_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 
SkStrokePE(SkScalar width,SkPaint::Join join,SkPaint::Cap cap,SkScalar miter)140 SkStrokePE::SkStrokePE(SkScalar width, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
141     : fWidth(width), fMiter(miter), fJoin(join), fCap(cap) {}
142 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *,const SkMatrix &) const143 bool SkStrokePE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
144                               const SkMatrix&) const {
145     SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
146     rec.setStrokeStyle(fWidth);
147     rec.setStrokeParams(fCap, fJoin, fMiter);
148     return rec.applyToPath(dst, src);
149 }
150 
computeFastBounds(SkRect * bounds) const151 bool 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 
flatten(SkWriteBuffer & buffer) const161 void SkStrokePE::flatten(SkWriteBuffer& buffer) const {
162     buffer.writeScalar(fWidth);
163     buffer.writeScalar(fMiter);
164     buffer.write32(fJoin);
165     buffer.write32(fCap);
166 }
167 
CreateProc(SkReadBuffer & buffer)168 sk_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 
176 //////////////////////////////////////////////////////////////////////////////////////////////////
177 
178 #include "include/effects/SkStrokeAndFillPathEffect.h"
179 #include "src/core/SkPathPriv.h"
180 
Make()181 sk_sp<SkPathEffect> SkStrokeAndFillPathEffect::Make() {
182     static SkPathEffect* strokeAndFill = new SkStrokeAndFillPE;
183     return sk_ref_sp(strokeAndFill);
184 }
185 
flatten(SkWriteBuffer &) const186 void SkStrokeAndFillPE::flatten(SkWriteBuffer&) const {}
187 
known_to_be_opposite_directions(const SkPath & a,const SkPath & b)188 static bool known_to_be_opposite_directions(const SkPath& a, const SkPath& b) {
189     auto a_dir = SkPathPriv::ComputeFirstDirection(a),
190          b_dir = SkPathPriv::ComputeFirstDirection(b);
191 
192     return (a_dir == SkPathFirstDirection::kCCW &&
193             b_dir == SkPathFirstDirection::kCW)
194             ||
195            (a_dir == SkPathFirstDirection::kCW &&
196             b_dir == SkPathFirstDirection::kCCW);
197 }
198 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect *,const SkMatrix &) const199 bool SkStrokeAndFillPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
200                                      const SkRect*, const SkMatrix&) const {
201     // 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         }
212 
213         if (known_to_be_opposite_directions(src, *dst)) {
214             dst->reverseAddPath(src);
215         } else {
216             dst->addPath(src);
217         }
218     } else {
219         *dst = src;
220     }
221     rec->setFillStyle();
222     return true;
223 }
224 
CreateProc(SkReadBuffer & buffer)225 sk_sp<SkFlattenable> SkStrokeAndFillPE::CreateProc(SkReadBuffer& buffer) {
226     return SkStrokeAndFillPathEffect::Make();
227 }
228