1 /* 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 8 #include "SkPathEffect.h" 9 #include "SkPath.h" 10 #include "SkReadBuffer.h" 11 #include "SkWriteBuffer.h" 12 13 /////////////////////////////////////////////////////////////////////////////// 14 15 bool SkPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, 16 const SkRect* bounds) const { 17 SkPath tmp, *tmpDst = dst; 18 if (dst == &src) { 19 tmpDst = &tmp; 20 } 21 if (this->onFilterPath(tmpDst, src, rec, bounds)) { 22 if (dst == &src) { 23 *dst = tmp; 24 } 25 return true; 26 } 27 return false; 28 } 29 30 void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) const { 31 *dst = this->onComputeFastBounds(src); 32 } 33 34 bool SkPathEffect::asPoints(PointData* results, const SkPath& src, 35 const SkStrokeRec& rec, const SkMatrix& mx, const SkRect* rect) const { 36 return this->onAsPoints(results, src, rec, mx, rect); 37 } 38 39 SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const { 40 return this->onAsADash(info); 41 } 42 43 /////////////////////////////////////////////////////////////////////////////// 44 45 /** \class SkPairPathEffect 46 47 Common baseclass for Compose and Sum. This subclass manages two pathEffects, 48 including flattening them. It does nothing in filterPath, and is only useful 49 for managing the lifetimes of its two arguments. 50 */ 51 class SkPairPathEffect : public SkPathEffect { 52 protected: 53 SkPairPathEffect(sk_sp<SkPathEffect> pe0, sk_sp<SkPathEffect> pe1) 54 : fPE0(std::move(pe0)), fPE1(std::move(pe1)) 55 { 56 SkASSERT(fPE0.get()); 57 SkASSERT(fPE1.get()); 58 } 59 60 void flatten(SkWriteBuffer& buffer) const override { 61 buffer.writeFlattenable(fPE0.get()); 62 buffer.writeFlattenable(fPE1.get()); 63 } 64 65 // these are visible to our subclasses 66 sk_sp<SkPathEffect> fPE0; 67 sk_sp<SkPathEffect> fPE1; 68 69 private: 70 typedef SkPathEffect INHERITED; 71 }; 72 73 /////////////////////////////////////////////////////////////////////////////////////////////////// 74 75 /** \class SkComposePathEffect 76 77 This subclass of SkPathEffect composes its two arguments, to create 78 a compound pathEffect. 79 */ 80 class SkComposePathEffect : public SkPairPathEffect { 81 public: 82 /** Construct a pathEffect whose effect is to apply first the inner pathEffect 83 and the the outer pathEffect (e.g. outer(inner(path))) 84 The reference counts for outer and inner are both incremented in the constructor, 85 and decremented in the destructor. 86 */ 87 static sk_sp<SkPathEffect> Make(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner) { 88 if (!outer) { 89 return inner; 90 } 91 if (!inner) { 92 return outer; 93 } 94 return sk_sp<SkPathEffect>(new SkComposePathEffect(outer, inner)); 95 } 96 97 protected: 98 SkComposePathEffect(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner) 99 : INHERITED(outer, inner) {} 100 101 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, 102 const SkRect* cullRect) const override { 103 SkPath tmp; 104 const SkPath* ptr = &src; 105 106 if (fPE1->filterPath(&tmp, src, rec, cullRect)) { 107 ptr = &tmp; 108 } 109 return fPE0->filterPath(dst, *ptr, rec, cullRect); 110 } 111 112 private: 113 SK_FLATTENABLE_HOOKS(SkComposePathEffect) 114 115 // illegal 116 SkComposePathEffect(const SkComposePathEffect&); 117 SkComposePathEffect& operator=(const SkComposePathEffect&); 118 friend class SkPathEffect; 119 120 typedef SkPairPathEffect INHERITED; 121 }; 122 123 sk_sp<SkFlattenable> SkComposePathEffect::CreateProc(SkReadBuffer& buffer) { 124 sk_sp<SkPathEffect> pe0(buffer.readPathEffect()); 125 sk_sp<SkPathEffect> pe1(buffer.readPathEffect()); 126 return SkComposePathEffect::Make(std::move(pe0), std::move(pe1)); 127 } 128 129 /////////////////////////////////////////////////////////////////////////////// 130 131 /** \class SkSumPathEffect 132 133 This subclass of SkPathEffect applies two pathEffects, one after the other. 134 Its filterPath() returns true if either of the effects succeeded. 135 */ 136 class SkSumPathEffect : public SkPairPathEffect { 137 public: 138 /** Construct a pathEffect whose effect is to apply two effects, in sequence. 139 (e.g. first(path) + second(path)) 140 The reference counts for first and second are both incremented in the constructor, 141 and decremented in the destructor. 142 */ 143 static sk_sp<SkPathEffect> Make(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) { 144 if (!first) { 145 return second; 146 } 147 if (!second) { 148 return first; 149 } 150 return sk_sp<SkPathEffect>(new SkSumPathEffect(first, second)); 151 } 152 153 SK_FLATTENABLE_HOOKS(SkSumPathEffect) 154 155 protected: 156 SkSumPathEffect(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) 157 : INHERITED(first, second) {} 158 159 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, 160 const SkRect* cullRect) const override { 161 // use bit-or so that we always call both, even if the first one succeeds 162 return fPE0->filterPath(dst, src, rec, cullRect) | 163 fPE1->filterPath(dst, src, rec, cullRect); 164 } 165 166 private: 167 // illegal 168 SkSumPathEffect(const SkSumPathEffect&); 169 SkSumPathEffect& operator=(const SkSumPathEffect&); 170 friend class SkPathEffect; 171 172 typedef SkPairPathEffect INHERITED; 173 }; 174 175 sk_sp<SkFlattenable> SkSumPathEffect::CreateProc(SkReadBuffer& buffer) { 176 sk_sp<SkPathEffect> pe0(buffer.readPathEffect()); 177 sk_sp<SkPathEffect> pe1(buffer.readPathEffect()); 178 return SkSumPathEffect::Make(pe0, pe1); 179 } 180 181 /////////////////////////////////////////////////////////////////////////////////////////////////// 182 183 sk_sp<SkPathEffect> SkPathEffect::MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) { 184 return SkSumPathEffect::Make(std::move(first), std::move(second)); 185 } 186 187 sk_sp<SkPathEffect> SkPathEffect::MakeCompose(sk_sp<SkPathEffect> outer, 188 sk_sp<SkPathEffect> inner) { 189 return SkComposePathEffect::Make(std::move(outer), std::move(inner)); 190 } 191 192 void SkPathEffect::RegisterFlattenables() { 193 SK_REGISTER_FLATTENABLE(SkComposePathEffect); 194 SK_REGISTER_FLATTENABLE(SkSumPathEffect); 195 } 196