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