SkLayerDrawLooper.cpp revision fbfcd5602128ec010c82cb733c9cdc0a3254f9f3
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 "SkPaint.h"
13#include "SkUnPreMultiply.h"
14
15SK_DEFINE_INST_COUNT(SkLayerDrawLooper)
16
17SkLayerDrawLooper::LayerInfo::LayerInfo() {
18    fFlagsMask = 0;                     // ignore our paint flags
19    fPaintBits = 0;                     // ignore our paint fields
20    fColorMode = SkXfermode::kDst_Mode; // ignore our color
21    fOffset.set(0, 0);
22    fPostTranslate = false;
23}
24
25SkLayerDrawLooper::SkLayerDrawLooper()
26        : fRecs(NULL),
27          fCount(0),
28          fCurrRec(NULL) {
29}
30
31SkLayerDrawLooper::~SkLayerDrawLooper() {
32    Rec* rec = fRecs;
33    while (rec) {
34        Rec* next = rec->fNext;
35        SkDELETE(rec);
36        rec = next;
37    }
38}
39
40SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) {
41    fCount += 1;
42
43    Rec* rec = SkNEW(Rec);
44    rec->fNext = fRecs;
45    rec->fInfo = info;
46    fRecs = rec;
47
48    return &rec->fPaint;
49}
50
51void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) {
52    LayerInfo info;
53
54    info.fOffset.set(dx, dy);
55    (void)this->addLayer(info);
56}
57
58void SkLayerDrawLooper::init(SkCanvas* canvas) {
59    fCurrRec = fRecs;
60    canvas->save(SkCanvas::kMatrix_SaveFlag);
61}
62
63static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) {
64    switch (mode) {
65        case SkXfermode::kSrc_Mode:
66            return src;
67        case SkXfermode::kDst_Mode:
68            return dst;
69        default: {
70            SkPMColor pmS = SkPreMultiplyColor(src);
71            SkPMColor pmD = SkPreMultiplyColor(dst);
72            SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD);
73            return SkUnPreMultiply::PMColorToColor(result);
74        }
75    }
76}
77
78// Even with kEntirePaint_Bits, we always ensure that the master paint's
79// text-encoding is respected, since that controls how we interpret the
80// text/length parameters of a draw[Pos]Text call.
81void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src,
82                                  const LayerInfo& info) {
83
84    uint32_t mask = info.fFlagsMask;
85    dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask));
86    dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
87
88    BitFlags bits = info.fPaintBits;
89    SkPaint::TextEncoding encoding = dst->getTextEncoding();
90
91    if (0 == bits) {
92        return;
93    }
94    if (kEntirePaint_Bits == bits) {
95        // we've already computed these, so save it from the assignment
96        uint32_t f = dst->getFlags();
97        SkColor c = dst->getColor();
98        *dst = src;
99        dst->setFlags(f);
100        dst->setColor(c);
101        dst->setTextEncoding(encoding);
102        return;
103    }
104
105    if (bits & kStyle_Bit) {
106        dst->setStyle(src.getStyle());
107        dst->setStrokeWidth(src.getStrokeWidth());
108        dst->setStrokeMiter(src.getStrokeMiter());
109        dst->setStrokeCap(src.getStrokeCap());
110        dst->setStrokeJoin(src.getStrokeJoin());
111    }
112
113    if (bits & kTextSkewX_Bit) {
114        dst->setTextSkewX(src.getTextSkewX());
115    }
116
117    if (bits & kPathEffect_Bit) {
118        dst->setPathEffect(src.getPathEffect());
119    }
120    if (bits & kMaskFilter_Bit) {
121        dst->setMaskFilter(src.getMaskFilter());
122    }
123    if (bits & kShader_Bit) {
124        dst->setShader(src.getShader());
125    }
126    if (bits & kColorFilter_Bit) {
127        dst->setColorFilter(src.getColorFilter());
128    }
129    if (bits & kXfermode_Bit) {
130        dst->setXfermode(src.getXfermode());
131    }
132
133    // we don't override these
134#if 0
135    dst->setTypeface(src.getTypeface());
136    dst->setTextSize(src.getTextSize());
137    dst->setTextScaleX(src.getTextScaleX());
138    dst->setRasterizer(src.getRasterizer());
139    dst->setLooper(src.getLooper());
140    dst->setTextEncoding(src.getTextEncoding());
141    dst->setHinting(src.getHinting());
142#endif
143}
144
145// Should we add this to canvas?
146static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
147    SkMatrix m = canvas->getTotalMatrix();
148    m.postTranslate(dx, dy);
149    canvas->setMatrix(m);
150}
151
152bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
153    canvas->restore();
154    if (NULL == fCurrRec) {
155        return false;
156    }
157
158    ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
159
160    canvas->save(SkCanvas::kMatrix_SaveFlag);
161    if (fCurrRec->fInfo.fPostTranslate) {
162        postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
163                      fCurrRec->fInfo.fOffset.fY);
164    } else {
165        canvas->translate(fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY);
166    }
167    fCurrRec = fCurrRec->fNext;
168
169    return true;
170}
171
172SkLayerDrawLooper::Rec* SkLayerDrawLooper::Rec::Reverse(Rec* head) {
173    Rec* rec = head;
174    Rec* prev = NULL;
175    while (rec) {
176        Rec* next = rec->fNext;
177        rec->fNext = prev;
178        prev = rec;
179        rec = next;
180    }
181    return prev;
182}
183
184///////////////////////////////////////////////////////////////////////////////
185
186void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) const {
187    this->INHERITED::flatten(buffer);
188
189#ifdef SK_DEBUG
190    {
191        Rec* rec = fRecs;
192        int count = 0;
193        while (rec) {
194            rec = rec->fNext;
195            count += 1;
196        }
197        SkASSERT(count == fCount);
198    }
199#endif
200
201    buffer.writeInt(fCount);
202
203    Rec* rec = fRecs;
204    for (int i = 0; i < fCount; i++) {
205        buffer.writeInt(rec->fInfo.fFlagsMask);
206        buffer.writeInt(rec->fInfo.fPaintBits);
207        buffer.writeInt(rec->fInfo.fColorMode);
208        buffer.writePoint(rec->fInfo.fOffset);
209        buffer.writeBool(rec->fInfo.fPostTranslate);
210        buffer.writePaint(rec->fPaint);
211        rec = rec->fNext;
212    }
213}
214
215SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
216        : INHERITED(buffer),
217          fRecs(NULL),
218          fCount(0),
219          fCurrRec(NULL) {
220    int count = buffer.readInt();
221
222    for (int i = 0; i < count; i++) {
223        LayerInfo info;
224        info.fFlagsMask = buffer.readInt();
225        info.fPaintBits = buffer.readInt();
226        info.fColorMode = (SkXfermode::Mode)buffer.readInt();
227        buffer.readPoint(&info.fOffset);
228        info.fPostTranslate = buffer.readBool();
229        buffer.readPaint(this->addLayer(info));
230    }
231    SkASSERT(count == fCount);
232
233    // we're in reverse order, so fix it now
234    fRecs = Rec::Reverse(fRecs);
235
236#ifdef SK_DEBUG
237    {
238        Rec* rec = fRecs;
239        int n = 0;
240        while (rec) {
241            rec = rec->fNext;
242            n += 1;
243        }
244        SkASSERT(count == n);
245    }
246#endif
247}
248
249///////////////////////////////////////////////////////////////////////////////
250
251SK_DEFINE_FLATTENABLE_REGISTRAR(SkLayerDrawLooper)
252