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