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