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