1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h"
9cb93a386Sopenharmony_ci#include "include/effects/SkOpPathEffect.h"
10cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h"
11cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h"
12cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h"
13cb93a386Sopenharmony_ci#include "src/effects/SkOpPE.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkMergePathEffect::Make(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two,
16cb93a386Sopenharmony_ci                                            SkPathOp op) {
17cb93a386Sopenharmony_ci    return sk_sp<SkPathEffect>(new SkOpPE(std::move(one), std::move(two), op));
18cb93a386Sopenharmony_ci}
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ciSkOpPE::SkOpPE(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two, SkPathOp op)
21cb93a386Sopenharmony_ci    : fOne(std::move(one)), fTwo(std::move(two)), fOp(op) {}
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_cibool SkOpPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
24cb93a386Sopenharmony_ci                          const SkRect* cull, const SkMatrix& ctm) const {
25cb93a386Sopenharmony_ci    SkPath one, two;
26cb93a386Sopenharmony_ci    if (fOne) {
27cb93a386Sopenharmony_ci        if (!fOne->filterPath(&one, src, rec, cull, ctm)) {
28cb93a386Sopenharmony_ci            return false;
29cb93a386Sopenharmony_ci        }
30cb93a386Sopenharmony_ci    } else {
31cb93a386Sopenharmony_ci        one = src;
32cb93a386Sopenharmony_ci    }
33cb93a386Sopenharmony_ci    if (fTwo) {
34cb93a386Sopenharmony_ci        if (!fTwo->filterPath(&two, src, rec, cull, ctm)) {
35cb93a386Sopenharmony_ci            return false;
36cb93a386Sopenharmony_ci        }
37cb93a386Sopenharmony_ci    } else {
38cb93a386Sopenharmony_ci        two = src;
39cb93a386Sopenharmony_ci    }
40cb93a386Sopenharmony_ci    return Op(one, two, fOp, dst);
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_cibool SkOpPE::computeFastBounds(SkRect* bounds) const {
44cb93a386Sopenharmony_ci    if (!bounds) {
45cb93a386Sopenharmony_ci        return (!SkToBool(fOne) || as_PEB(fOne)->computeFastBounds(nullptr)) &&
46cb93a386Sopenharmony_ci               (!SkToBool(fTwo) || as_PEB(fTwo)->computeFastBounds(nullptr));
47cb93a386Sopenharmony_ci    }
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    // bounds will hold the result of the fOne while b2 holds the result of fTwo's fast bounds
50cb93a386Sopenharmony_ci    SkRect b2 = *bounds;
51cb93a386Sopenharmony_ci    if (fOne && !as_PEB(fOne)->computeFastBounds(bounds)) {
52cb93a386Sopenharmony_ci        return false;
53cb93a386Sopenharmony_ci    }
54cb93a386Sopenharmony_ci    if (fTwo && !as_PEB(fTwo)->computeFastBounds(&b2)) {
55cb93a386Sopenharmony_ci        return false;
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    switch (fOp) {
59cb93a386Sopenharmony_ci        case SkPathOp::kIntersect_SkPathOp:
60cb93a386Sopenharmony_ci            if (!bounds->intersect(b2)) {
61cb93a386Sopenharmony_ci                bounds->setEmpty();
62cb93a386Sopenharmony_ci            }
63cb93a386Sopenharmony_ci            break;
64cb93a386Sopenharmony_ci        case SkPathOp::kDifference_SkPathOp:
65cb93a386Sopenharmony_ci            // (one - two) conservatively leaves one's bounds unmodified
66cb93a386Sopenharmony_ci            break;
67cb93a386Sopenharmony_ci        case SkPathOp::kReverseDifference_SkPathOp:
68cb93a386Sopenharmony_ci            // (two - one) conservatively leaves two's bounds unmodified
69cb93a386Sopenharmony_ci            *bounds = b2;
70cb93a386Sopenharmony_ci            break;
71cb93a386Sopenharmony_ci        case SkPathOp::kXOR_SkPathOp:
72cb93a386Sopenharmony_ci            // fall through to union since XOR computes a subset of regular OR
73cb93a386Sopenharmony_ci        case SkPathOp::kUnion_SkPathOp:
74cb93a386Sopenharmony_ci            bounds->join(b2);
75cb93a386Sopenharmony_ci            break;
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    return true;
79cb93a386Sopenharmony_ci}
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_civoid SkOpPE::flatten(SkWriteBuffer& buffer) const {
82cb93a386Sopenharmony_ci    buffer.writeFlattenable(fOne.get());
83cb93a386Sopenharmony_ci    buffer.writeFlattenable(fTwo.get());
84cb93a386Sopenharmony_ci    buffer.write32(fOp);
85cb93a386Sopenharmony_ci}
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_cisk_sp<SkFlattenable> SkOpPE::CreateProc(SkReadBuffer& buffer) {
88cb93a386Sopenharmony_ci    auto one = buffer.readPathEffect();
89cb93a386Sopenharmony_ci    auto two = buffer.readPathEffect();
90cb93a386Sopenharmony_ci    SkPathOp op = buffer.read32LE(kReverseDifference_SkPathOp);
91cb93a386Sopenharmony_ci    return buffer.isValid() ? SkMergePathEffect::Make(std::move(one), std::move(two), op) : nullptr;
92cb93a386Sopenharmony_ci}
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkMatrixPathEffect::MakeTranslate(SkScalar dx, SkScalar dy) {
97cb93a386Sopenharmony_ci    if (!SkScalarsAreFinite(dx, dy)) {
98cb93a386Sopenharmony_ci        return nullptr;
99cb93a386Sopenharmony_ci    }
100cb93a386Sopenharmony_ci    return sk_sp<SkPathEffect>(new SkMatrixPE(SkMatrix::Translate(dx, dy)));
101cb93a386Sopenharmony_ci}
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkMatrixPathEffect::Make(const SkMatrix& matrix) {
104cb93a386Sopenharmony_ci    if (!matrix.isFinite()) {
105cb93a386Sopenharmony_ci        return nullptr;
106cb93a386Sopenharmony_ci    }
107cb93a386Sopenharmony_ci    return sk_sp<SkPathEffect>(new SkMatrixPE(matrix));
108cb93a386Sopenharmony_ci}
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ciSkMatrixPE::SkMatrixPE(const SkMatrix& matrix) : fMatrix(matrix) {
111cb93a386Sopenharmony_ci    SkASSERT(matrix.isFinite());
112cb93a386Sopenharmony_ci}
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_cibool SkMatrixPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
115cb93a386Sopenharmony_ci                              const SkMatrix&) const {
116cb93a386Sopenharmony_ci    src.transform(fMatrix, dst);
117cb93a386Sopenharmony_ci    return true;
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_civoid SkMatrixPE::flatten(SkWriteBuffer& buffer) const {
121cb93a386Sopenharmony_ci    buffer.writeMatrix(fMatrix);
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_cisk_sp<SkFlattenable> SkMatrixPE::CreateProc(SkReadBuffer& buffer) {
125cb93a386Sopenharmony_ci    SkMatrix mx;
126cb93a386Sopenharmony_ci    buffer.readMatrix(&mx);
127cb93a386Sopenharmony_ci    return buffer.isValid() ? SkMatrixPathEffect::Make(mx) : nullptr;
128cb93a386Sopenharmony_ci}
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkStrokePathEffect::Make(SkScalar width, SkPaint::Join join, SkPaint::Cap cap,
133cb93a386Sopenharmony_ci                                             SkScalar miter) {
134cb93a386Sopenharmony_ci    if (!SkScalarsAreFinite(width, miter) || width < 0 || miter < 0) {
135cb93a386Sopenharmony_ci        return nullptr;
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci    return sk_sp<SkPathEffect>(new SkStrokePE(width, join, cap, miter));
138cb93a386Sopenharmony_ci}
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ciSkStrokePE::SkStrokePE(SkScalar width, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
141cb93a386Sopenharmony_ci    : fWidth(width), fMiter(miter), fJoin(join), fCap(cap) {}
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_cibool SkStrokePE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
144cb93a386Sopenharmony_ci                              const SkMatrix&) const {
145cb93a386Sopenharmony_ci    SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
146cb93a386Sopenharmony_ci    rec.setStrokeStyle(fWidth);
147cb93a386Sopenharmony_ci    rec.setStrokeParams(fCap, fJoin, fMiter);
148cb93a386Sopenharmony_ci    return rec.applyToPath(dst, src);
149cb93a386Sopenharmony_ci}
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_cibool SkStrokePE::computeFastBounds(SkRect* bounds) const {
152cb93a386Sopenharmony_ci    if (bounds) {
153cb93a386Sopenharmony_ci        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
154cb93a386Sopenharmony_ci        rec.setStrokeStyle(fWidth);
155cb93a386Sopenharmony_ci        rec.setStrokeParams(fCap, fJoin, fMiter);
156cb93a386Sopenharmony_ci        bounds->outset(rec.getInflationRadius(), rec.getInflationRadius());
157cb93a386Sopenharmony_ci    }
158cb93a386Sopenharmony_ci    return true;
159cb93a386Sopenharmony_ci}
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_civoid SkStrokePE::flatten(SkWriteBuffer& buffer) const {
162cb93a386Sopenharmony_ci    buffer.writeScalar(fWidth);
163cb93a386Sopenharmony_ci    buffer.writeScalar(fMiter);
164cb93a386Sopenharmony_ci    buffer.write32(fJoin);
165cb93a386Sopenharmony_ci    buffer.write32(fCap);
166cb93a386Sopenharmony_ci}
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_cisk_sp<SkFlattenable> SkStrokePE::CreateProc(SkReadBuffer& buffer) {
169cb93a386Sopenharmony_ci    SkScalar width = buffer.readScalar();
170cb93a386Sopenharmony_ci    SkScalar miter = buffer.readScalar();
171cb93a386Sopenharmony_ci    SkPaint::Join join = buffer.read32LE(SkPaint::kLast_Join);
172cb93a386Sopenharmony_ci    SkPaint::Cap cap = buffer.read32LE(SkPaint::kLast_Cap);
173cb93a386Sopenharmony_ci    return buffer.isValid() ? SkStrokePathEffect::Make(width, join, cap, miter) : nullptr;
174cb93a386Sopenharmony_ci}
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci#include "include/effects/SkStrokeAndFillPathEffect.h"
179cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkStrokeAndFillPathEffect::Make() {
182cb93a386Sopenharmony_ci    static SkPathEffect* strokeAndFill = new SkStrokeAndFillPE;
183cb93a386Sopenharmony_ci    return sk_ref_sp(strokeAndFill);
184cb93a386Sopenharmony_ci}
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_civoid SkStrokeAndFillPE::flatten(SkWriteBuffer&) const {}
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_cistatic bool known_to_be_opposite_directions(const SkPath& a, const SkPath& b) {
189cb93a386Sopenharmony_ci    auto a_dir = SkPathPriv::ComputeFirstDirection(a),
190cb93a386Sopenharmony_ci         b_dir = SkPathPriv::ComputeFirstDirection(b);
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci    return (a_dir == SkPathFirstDirection::kCCW &&
193cb93a386Sopenharmony_ci            b_dir == SkPathFirstDirection::kCW)
194cb93a386Sopenharmony_ci            ||
195cb93a386Sopenharmony_ci           (a_dir == SkPathFirstDirection::kCW &&
196cb93a386Sopenharmony_ci            b_dir == SkPathFirstDirection::kCCW);
197cb93a386Sopenharmony_ci}
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_cibool SkStrokeAndFillPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
200cb93a386Sopenharmony_ci                                     const SkRect*, const SkMatrix&) const {
201cb93a386Sopenharmony_ci    // This one is weird, since we exist to allow this paint-style to go away. If we see it,
202cb93a386Sopenharmony_ci    // just let the normal machine run its course.
203cb93a386Sopenharmony_ci    if (rec->getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
204cb93a386Sopenharmony_ci        *dst = src;
205cb93a386Sopenharmony_ci        return true;
206cb93a386Sopenharmony_ci    }
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci    if (rec->getStyle() == SkStrokeRec::kStroke_Style) {
209cb93a386Sopenharmony_ci        if (!rec->applyToPath(dst, src)) {
210cb93a386Sopenharmony_ci            return false;
211cb93a386Sopenharmony_ci        }
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci        if (known_to_be_opposite_directions(src, *dst)) {
214cb93a386Sopenharmony_ci            dst->reverseAddPath(src);
215cb93a386Sopenharmony_ci        } else {
216cb93a386Sopenharmony_ci            dst->addPath(src);
217cb93a386Sopenharmony_ci        }
218cb93a386Sopenharmony_ci    } else {
219cb93a386Sopenharmony_ci        *dst = src;
220cb93a386Sopenharmony_ci    }
221cb93a386Sopenharmony_ci    rec->setFillStyle();
222cb93a386Sopenharmony_ci    return true;
223cb93a386Sopenharmony_ci}
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_cisk_sp<SkFlattenable> SkStrokeAndFillPE::CreateProc(SkReadBuffer& buffer) {
226cb93a386Sopenharmony_ci    return SkStrokeAndFillPathEffect::Make();
227cb93a386Sopenharmony_ci}
228