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 "SkArenaAlloc.h"
8#include "SkBlurDrawLooper.h"
9#include "SkBlurMaskFilter.h"
10#include "SkCanvas.h"
11#include "SkColorSpaceXformer.h"
12#include "SkColor.h"
13#include "SkMaskFilterBase.h"
14#include "SkReadBuffer.h"
15#include "SkWriteBuffer.h"
16#include "SkLayerDrawLooper.h"
17#include "SkString.h"
18#include "SkStringUtils.h"
19#include "SkUnPreMultiply.h"
20#include "SkXfermodePriv.h"
21
22SkLayerDrawLooper::LayerInfo::LayerInfo() {
23    fPaintBits = 0;                     // ignore our paint fields
24    fColorMode = SkBlendMode::kDst;     // ignore our color
25    fOffset.set(0, 0);
26    fPostTranslate = false;
27}
28
29SkLayerDrawLooper::SkLayerDrawLooper()
30        : fRecs(nullptr),
31          fCount(0) {
32}
33
34SkLayerDrawLooper::~SkLayerDrawLooper() {
35    Rec* rec = fRecs;
36    while (rec) {
37        Rec* next = rec->fNext;
38        delete rec;
39        rec = next;
40    }
41}
42
43SkLayerDrawLooper::Context*
44SkLayerDrawLooper::makeContext(SkCanvas* canvas, SkArenaAlloc* alloc) const {
45    canvas->save();
46    return alloc->make<LayerDrawLooperContext>(this);
47}
48
49static SkColor xferColor(SkColor src, SkColor dst, SkBlendMode mode) {
50    switch (mode) {
51        case SkBlendMode::kSrc:
52            return src;
53        case SkBlendMode::kDst:
54            return dst;
55        default: {
56            SkPMColor pmS = SkPreMultiplyColor(src);
57            SkPMColor pmD = SkPreMultiplyColor(dst);
58            SkXfermode::Peek(mode)->xfer32(&pmD, &pmS, 1, nullptr);
59            return SkUnPreMultiply::PMColorToColor(pmD);
60        }
61    }
62}
63
64// Even with kEntirePaint_Bits, we always ensure that the master paint's
65// text-encoding is respected, since that controls how we interpret the
66// text/length parameters of a draw[Pos]Text call.
67void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
68        SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
69    SkColor srcColor = src.getColor();
70#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
71    // The framework may respect the alpha value on the original paint.
72    // Match this legacy behavior.
73    if (SkColorGetA(srcColor) == 255) {
74        srcColor = SkColorSetA(srcColor, dst->getAlpha());
75    }
76#endif
77    dst->setColor(xferColor(srcColor, dst->getColor(), (SkBlendMode)info.fColorMode));
78
79    BitFlags bits = info.fPaintBits;
80    SkPaint::TextEncoding encoding = dst->getTextEncoding();
81
82    if (0 == bits) {
83        return;
84    }
85    if (kEntirePaint_Bits == bits) {
86        // we've already computed these, so save it from the assignment
87        uint32_t f = dst->getFlags();
88        SkColor c = dst->getColor();
89        *dst = src;
90        dst->setFlags(f);
91        dst->setColor(c);
92        dst->setTextEncoding(encoding);
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 & kTextSkewX_Bit) {
105        dst->setTextSkewX(src.getTextSkewX());
106    }
107
108    if (bits & kPathEffect_Bit) {
109        dst->setPathEffect(src.refPathEffect());
110    }
111    if (bits & kMaskFilter_Bit) {
112        dst->setMaskFilter(src.refMaskFilter());
113    }
114    if (bits & kShader_Bit) {
115        dst->setShader(src.refShader());
116    }
117    if (bits & kColorFilter_Bit) {
118        dst->setColorFilter(src.refColorFilter());
119    }
120    if (bits & kXfermode_Bit) {
121        dst->setBlendMode(src.getBlendMode());
122    }
123
124    // we don't override these
125#if 0
126    dst->setTypeface(src.getTypeface());
127    dst->setTextSize(src.getTextSize());
128    dst->setTextScaleX(src.getTextScaleX());
129    dst->setRasterizer(src.getRasterizer());
130    dst->setLooper(src.getLooper());
131    dst->setTextEncoding(src.getTextEncoding());
132    dst->setHinting(src.getHinting());
133#endif
134}
135
136// Should we add this to canvas?
137static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
138    SkMatrix m = canvas->getTotalMatrix();
139    m.postTranslate(dx, dy);
140    canvas->setMatrix(m);
141}
142
143SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
144        const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
145
146bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas,
147                                                     SkPaint* paint) {
148    canvas->restore();
149    if (nullptr == fCurrRec) {
150        return false;
151    }
152
153    ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
154
155    canvas->save();
156    if (fCurrRec->fInfo.fPostTranslate) {
157        postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
158                      fCurrRec->fInfo.fOffset.fY);
159    } else {
160        canvas->translate(fCurrRec->fInfo.fOffset.fX,
161                          fCurrRec->fInfo.fOffset.fY);
162    }
163    fCurrRec = fCurrRec->fNext;
164
165    return true;
166}
167
168bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
169    if (fCount != 2) {
170        return false;
171    }
172    const Rec* rec = fRecs;
173
174    // bottom layer needs to be just blur(maskfilter)
175    if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
176        return false;
177    }
178    if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
179        return false;
180    }
181    const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
182    if (nullptr == mf) {
183        return false;
184    }
185    SkMaskFilterBase::BlurRec maskBlur;
186    if (!as_MFB(mf)->asABlur(&maskBlur)) {
187        return false;
188    }
189
190    rec = rec->fNext;
191    // top layer needs to be "plain"
192    if (rec->fInfo.fPaintBits) {
193        return false;
194    }
195    if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
196        return false;
197    }
198    if (!rec->fInfo.fOffset.equals(0, 0)) {
199        return false;
200    }
201
202    if (bsRec) {
203        bsRec->fSigma = maskBlur.fSigma;
204        bsRec->fOffset = fRecs->fInfo.fOffset;
205        bsRec->fColor = fRecs->fPaint.getColor();
206        bsRec->fStyle = maskBlur.fStyle;
207        bsRec->fQuality = maskBlur.fQuality;
208    }
209    return true;
210}
211
212sk_sp<SkDrawLooper> SkLayerDrawLooper::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
213    if (!fCount) {
214        return sk_ref_sp(const_cast<SkLayerDrawLooper*>(this));
215    }
216
217    auto looper = sk_sp<SkLayerDrawLooper>(new SkLayerDrawLooper());
218    looper->fCount = fCount;
219
220    Rec* oldRec = fRecs;
221    Rec* newTopRec = new Rec();
222    newTopRec->fInfo = oldRec->fInfo;
223    newTopRec->fPaint = xformer->apply(oldRec->fPaint);
224    newTopRec->fNext = nullptr;
225
226    Rec* prevNewRec = newTopRec;
227    oldRec = oldRec->fNext;
228    while (oldRec) {
229        Rec* newRec = new Rec();
230        newRec->fInfo = oldRec->fInfo;
231        newRec->fPaint = xformer->apply(oldRec->fPaint);
232        newRec->fNext = nullptr;
233        prevNewRec->fNext = newRec;
234
235        prevNewRec = newRec;
236        oldRec = oldRec->fNext;
237    }
238
239    looper->fRecs = newTopRec;
240    return std::move(looper);
241}
242
243///////////////////////////////////////////////////////////////////////////////
244
245void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
246    buffer.writeInt(fCount);
247
248    Rec* rec = fRecs;
249    for (int i = 0; i < fCount; i++) {
250        // Legacy "flagsmask" field -- now ignored, remove when we bump version
251        buffer.writeInt(0);
252
253        buffer.writeInt(rec->fInfo.fPaintBits);
254        buffer.writeInt((int)rec->fInfo.fColorMode);
255        buffer.writePoint(rec->fInfo.fOffset);
256        buffer.writeBool(rec->fInfo.fPostTranslate);
257        buffer.writePaint(rec->fPaint);
258        rec = rec->fNext;
259    }
260}
261
262sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
263    int count = buffer.readInt();
264
265    Builder builder;
266    for (int i = 0; i < count; i++) {
267        LayerInfo info;
268        // Legacy "flagsmask" field -- now ignored, remove when we bump version
269        (void)buffer.readInt();
270
271        info.fPaintBits = buffer.readInt();
272        info.fColorMode = (SkBlendMode)buffer.readInt();
273        buffer.readPoint(&info.fOffset);
274        info.fPostTranslate = buffer.readBool();
275        buffer.readPaint(builder.addLayerOnTop(info));
276    }
277    return builder.detach();
278}
279
280#ifndef SK_IGNORE_TO_STRING
281void SkLayerDrawLooper::toString(SkString* str) const {
282    str->appendf("SkLayerDrawLooper (%d): ", fCount);
283
284    Rec* rec = fRecs;
285    for (int i = 0; i < fCount; i++) {
286        str->appendf("%d: paintBits: (", i);
287        if (0 == rec->fInfo.fPaintBits) {
288            str->append("None");
289        } else if (kEntirePaint_Bits == rec->fInfo.fPaintBits) {
290            str->append("EntirePaint");
291        } else {
292            bool needSeparator = false;
293            SkAddFlagToString(str, SkToBool(kStyle_Bit & rec->fInfo.fPaintBits), "Style",
294                              &needSeparator);
295            SkAddFlagToString(str, SkToBool(kTextSkewX_Bit & rec->fInfo.fPaintBits), "TextSkewX",
296                              &needSeparator);
297            SkAddFlagToString(str, SkToBool(kPathEffect_Bit & rec->fInfo.fPaintBits), "PathEffect",
298                              &needSeparator);
299            SkAddFlagToString(str, SkToBool(kMaskFilter_Bit & rec->fInfo.fPaintBits), "MaskFilter",
300                              &needSeparator);
301            SkAddFlagToString(str, SkToBool(kShader_Bit & rec->fInfo.fPaintBits), "Shader",
302                              &needSeparator);
303            SkAddFlagToString(str, SkToBool(kColorFilter_Bit & rec->fInfo.fPaintBits), "ColorFilter",
304                              &needSeparator);
305            SkAddFlagToString(str, SkToBool(kXfermode_Bit & rec->fInfo.fPaintBits), "Xfermode",
306                              &needSeparator);
307        }
308        str->append(") ");
309
310        static const char* gModeStrings[(int)SkBlendMode::kLastMode+1] = {
311            "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn",
312            "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus",
313            "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge",
314            "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion"
315        };
316
317        str->appendf("mode: %s ", gModeStrings[(int)rec->fInfo.fColorMode]);
318
319        str->append("offset: (");
320        str->appendScalar(rec->fInfo.fOffset.fX);
321        str->append(", ");
322        str->appendScalar(rec->fInfo.fOffset.fY);
323        str->append(") ");
324
325        str->append("postTranslate: ");
326        if (rec->fInfo.fPostTranslate) {
327            str->append("true ");
328        } else {
329            str->append("false ");
330        }
331
332        rec->fPaint.toString(str);
333        rec = rec->fNext;
334    }
335}
336#endif
337
338SkLayerDrawLooper::Builder::Builder()
339        : fRecs(nullptr),
340          fTopRec(nullptr),
341          fCount(0) {
342}
343
344SkLayerDrawLooper::Builder::~Builder() {
345    Rec* rec = fRecs;
346    while (rec) {
347        Rec* next = rec->fNext;
348        delete rec;
349        rec = next;
350    }
351}
352
353SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
354    fCount += 1;
355
356    Rec* rec = new Rec;
357    rec->fNext = fRecs;
358    rec->fInfo = info;
359    fRecs = rec;
360    if (nullptr == fTopRec) {
361        fTopRec = rec;
362    }
363
364    return &rec->fPaint;
365}
366
367void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
368    LayerInfo info;
369
370    info.fOffset.set(dx, dy);
371    (void)this->addLayer(info);
372}
373
374SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
375    fCount += 1;
376
377    Rec* rec = new Rec;
378    rec->fNext = nullptr;
379    rec->fInfo = info;
380    if (nullptr == fRecs) {
381        fRecs = rec;
382    } else {
383        SkASSERT(fTopRec);
384        fTopRec->fNext = rec;
385    }
386    fTopRec = rec;
387
388    return &rec->fPaint;
389}
390
391sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
392    SkLayerDrawLooper* looper = new SkLayerDrawLooper;
393    looper->fCount = fCount;
394    looper->fRecs = fRecs;
395
396    fCount = 0;
397    fRecs = nullptr;
398    fTopRec = nullptr;
399
400    return sk_sp<SkDrawLooper>(looper);
401}
402
403sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
404{
405    sk_sp<SkMaskFilter> blur = nullptr;
406    if (sigma > 0.0f) {
407        blur = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, sigma, SkBlurMaskFilter::kNone_BlurFlag);
408    }
409
410    SkLayerDrawLooper::Builder builder;
411
412    // First layer
413    SkLayerDrawLooper::LayerInfo defaultLayer;
414    builder.addLayer(defaultLayer);
415
416    // Blur layer
417    SkLayerDrawLooper::LayerInfo blurInfo;
418    blurInfo.fColorMode = SkBlendMode::kSrc;
419    blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
420    blurInfo.fOffset = SkVector::Make(dx, dy);
421    SkPaint* paint = builder.addLayer(blurInfo);
422    paint->setMaskFilter(std::move(blur));
423    paint->setColor(color);
424
425    return builder.detach();
426}
427