1/*
2 * Copyright 2011 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#include "include/core/SkCanvas.h"
8#include "include/core/SkColor.h"
9#include "include/core/SkMaskFilter.h"
10#include "include/core/SkString.h"
11#include "include/core/SkUnPreMultiply.h"
12#include "include/effects/SkBlurDrawLooper.h"
13#include "include/effects/SkLayerDrawLooper.h"
14#include "src/core/SkArenaAlloc.h"
15#include "src/core/SkBlendModePriv.h"
16#include "src/core/SkColorSpacePriv.h"
17#include "src/core/SkMaskFilterBase.h"
18#include "src/core/SkReadBuffer.h"
19#include "src/core/SkStringUtils.h"
20#include "src/core/SkWriteBuffer.h"
21#include "src/core/SkXfermodePriv.h"
22
23SkLayerDrawLooper::LayerInfo::LayerInfo() {
24 fPaintBits = 0; // ignore our paint fields
25 fColorMode = SkBlendMode::kDst; // ignore our color
26 fOffset.set(0, 0);
27 fPostTranslate = false;
28}
29
30SkLayerDrawLooper::SkLayerDrawLooper()
31 : fRecs(nullptr),
32 fCount(0) {
33}
34
35SkLayerDrawLooper::~SkLayerDrawLooper() {
36 Rec* rec = fRecs;
37 while (rec) {
38 Rec* next = rec->fNext;
39 delete rec;
40 rec = next;
41 }
42}
43
44SkLayerDrawLooper::Context*
45SkLayerDrawLooper::makeContext(SkArenaAlloc* alloc) const {
46 return alloc->make<LayerDrawLooperContext>(this);
47}
48
49static SkColor4f xferColor(const SkColor4f& src, const SkColor4f& dst, SkBlendMode mode) {
50 switch (mode) {
51 case SkBlendMode::kSrc:
52 return src;
53 case SkBlendMode::kDst:
54 return dst;
55 default: {
56 SkPMColor4f pmS = src.premul();
57 SkPMColor4f pmD = dst.premul();
58 return SkBlendMode_Apply(mode, pmS, pmD).unpremul();
59 }
60 }
61}
62
63// Even with kEntirePaint_Bits, we always ensure that the master paint's
64// text-encoding is respected, since that controls how we interpret the
65// text/length parameters of a draw[Pos]Text call.
66void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
67 SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
68 SkColor4f srcColor = src.getColor4f();
69#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
70 // The framework may respect the alpha value on the original paint.
71 // Match this legacy behavior.
72 if (src.getAlpha() == 255) {
73 srcColor.fA = dst->getColor4f().fA;
74 }
75#endif
76 dst->setColor4f(xferColor(srcColor, dst->getColor4f(), (SkBlendMode)info.fColorMode),
77 sk_srgb_singleton());
78
79 BitFlags bits = info.fPaintBits;
80
81 if (0 == bits) {
82 return;
83 }
84 if (kEntirePaint_Bits == bits) {
85 // we've already computed these, so save it from the assignment
86 bool aa = dst->isAntiAlias();
87 bool di = dst->isDither();
88 SkColor4f c = dst->getColor4f();
89 *dst = src;
90 dst->setAntiAlias(aa);
91 dst->setDither(di);
92 dst->setColor4f(c, sk_srgb_singleton());
93 return;
94 }
95
96 if (bits & kStyle_Bit) {
97 dst->setStyle(src.getStyle());
98 dst->setStrokeWidth(src.getStrokeWidth());
99 dst->setStrokeMiter(src.getStrokeMiter());
100 dst->setStrokeCap(src.getStrokeCap());
101 dst->setStrokeJoin(src.getStrokeJoin());
102 }
103
104 if (bits & kPathEffect_Bit) {
105 dst->setPathEffect(src.refPathEffect());
106 }
107 if (bits & kMaskFilter_Bit) {
108 dst->setMaskFilter(src.refMaskFilter());
109 }
110 if (bits & kShader_Bit) {
111 dst->setShader(src.refShader());
112 }
113 if (bits & kColorFilter_Bit) {
114 dst->setColorFilter(src.refColorFilter());
115 }
116 if (bits & kXfermode_Bit) {
117 dst->setBlendMode(src.getBlendMode());
118 }
119
120 // we don't override these
121#if 0
122 dst->setTypeface(src.getTypeface());
123 dst->setTextSize(src.getTextSize());
124 dst->setTextScaleX(src.getTextScaleX());
125 dst->setRasterizer(src.getRasterizer());
126 dst->setLooper(src.getLooper());
127 dst->setTextEncoding(src.getTextEncoding());
128 dst->setHinting(src.getHinting());
129#endif
130}
131
132SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
133 const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
134
135bool SkLayerDrawLooper::LayerDrawLooperContext::next(Info* info, SkPaint* paint) {
136 if (nullptr == fCurrRec) {
137 return false;
138 }
139
140 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
141
142 if (info) {
143 info->fTranslate = fCurrRec->fInfo.fOffset;
144 info->fApplyPostCTM = fCurrRec->fInfo.fPostTranslate;
145 }
146 fCurrRec = fCurrRec->fNext;
147 return true;
148}
149
150bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
151 if (fCount != 2) {
152 return false;
153 }
154 const Rec* rec = fRecs;
155
156 // bottom layer needs to be just blur(maskfilter)
157 if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
158 return false;
159 }
160 if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
161 return false;
162 }
163 const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
164 if (nullptr == mf) {
165 return false;
166 }
167 SkMaskFilterBase::BlurRec maskBlur;
168 if (!as_MFB(mf)->asABlur(&maskBlur)) {
169 return false;
170 }
171
172 rec = rec->fNext;
173 // top layer needs to be "plain"
174 if (rec->fInfo.fPaintBits) {
175 return false;
176 }
177 if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
178 return false;
179 }
180 if (!rec->fInfo.fOffset.equals(0, 0)) {
181 return false;
182 }
183
184 if (bsRec) {
185 bsRec->fSigma = maskBlur.fSigma;
186 bsRec->fOffset = fRecs->fInfo.fOffset;
187 // TODO: Update BlurShadowRec to use SkColor4f?
188 bsRec->fColor = fRecs->fPaint.getColor();
189 bsRec->fStyle = maskBlur.fStyle;
190 }
191 return true;
192}
193
194///////////////////////////////////////////////////////////////////////////////
195
196void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
197 buffer.writeInt(fCount);
198
199 Rec* rec = fRecs;
200 for (int i = 0; i < fCount; i++) {
201 // Legacy "flagsmask" field -- now ignored, remove when we bump version
202 buffer.writeInt(0);
203
204 buffer.writeInt(rec->fInfo.fPaintBits);
205 buffer.writeInt((int)rec->fInfo.fColorMode);
206 buffer.writePoint(rec->fInfo.fOffset);
207 buffer.writeBool(rec->fInfo.fPostTranslate);
208 buffer.writePaint(rec->fPaint);
209 rec = rec->fNext;
210 }
211}
212
213sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
214 int count = buffer.readInt();
215
216 Builder builder;
217 for (int i = 0; i < count; i++) {
218 LayerInfo info;
219 // Legacy "flagsmask" field -- now ignored, remove when we bump version
220 (void)buffer.readInt();
221
222 info.fPaintBits = buffer.readInt();
223 info.fColorMode = (SkBlendMode)buffer.readInt();
224 buffer.readPoint(&info.fOffset);
225 info.fPostTranslate = buffer.readBool();
226 buffer.readPaint(builder.addLayerOnTop(info), nullptr);
227 if (!buffer.isValid()) {
228 return nullptr;
229 }
230 }
231 return builder.detach();
232}
233
234SkLayerDrawLooper::Builder::Builder()
235 : fRecs(nullptr),
236 fTopRec(nullptr),
237 fCount(0) {
238}
239
240SkLayerDrawLooper::Builder::~Builder() {
241 Rec* rec = fRecs;
242 while (rec) {
243 Rec* next = rec->fNext;
244 delete rec;
245 rec = next;
246 }
247}
248
249SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
250 fCount += 1;
251
252 Rec* rec = new Rec;
253 rec->fNext = fRecs;
254 rec->fInfo = info;
255 fRecs = rec;
256 if (nullptr == fTopRec) {
257 fTopRec = rec;
258 }
259
260 return &rec->fPaint;
261}
262
263void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
264 LayerInfo info;
265
266 info.fOffset.set(dx, dy);
267 (void)this->addLayer(info);
268}
269
270SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
271 fCount += 1;
272
273 Rec* rec = new Rec;
274 rec->fNext = nullptr;
275 rec->fInfo = info;
276 if (nullptr == fRecs) {
277 fRecs = rec;
278 } else {
279 SkASSERT(fTopRec);
280 fTopRec->fNext = rec;
281 }
282 fTopRec = rec;
283
284 return &rec->fPaint;
285}
286
287sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
288 SkLayerDrawLooper* looper = new SkLayerDrawLooper;
289 looper->fCount = fCount;
290 looper->fRecs = fRecs;
291
292 fCount = 0;
293 fRecs = nullptr;
294 fTopRec = nullptr;
295
296 return sk_sp<SkDrawLooper>(looper);
297}
298
299sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
300{
301 return Make(SkColor4f::FromColor(color), sk_srgb_singleton(), sigma, dx, dy);
302}
303
304sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor4f color, SkColorSpace* cs,
305 SkScalar sigma, SkScalar dx, SkScalar dy)
306{
307 sk_sp<SkMaskFilter> blur = nullptr;
308 if (sigma > 0.0f) {
309 blur = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, true);
310 }
311
312 SkLayerDrawLooper::Builder builder;
313
314 // First layer
315 SkLayerDrawLooper::LayerInfo defaultLayer;
316 builder.addLayer(defaultLayer);
317
318 // Blur layer
319 SkLayerDrawLooper::LayerInfo blurInfo;
320 blurInfo.fColorMode = SkBlendMode::kSrc;
321 blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
322 blurInfo.fOffset = SkVector::Make(dx, dy);
323 SkPaint* paint = builder.addLayer(blurInfo);
324 paint->setMaskFilter(std::move(blur));
325 paint->setColor4f(color, cs);
326
327 return builder.detach();
328}
329