blob: b837fc0d1b6a06ccf2ed35ec2e3a58f13f6b1a53 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkCanvas.h"
reed@google.com0716c632011-04-12 18:32:06 +00002#include "SkColor.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00003#include "SkLayerDrawLooper.h"
4#include "SkPaint.h"
reed@google.com0716c632011-04-12 18:32:06 +00005#include "SkUnPreMultiply.h"
6
7SkLayerDrawLooper::LayerInfo::LayerInfo() {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +00008 fFlagsMask = 0; // ignore our paint flags
9 fPaintBits = 0; // ignore our paint fields
reed@google.com0716c632011-04-12 18:32:06 +000010 fColorMode = SkXfermode::kDst_Mode; // ignore our color
11 fOffset.set(0, 0);
12 fPostTranslate = false;
13}
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
vandebo@chromium.org3c898182011-06-22 05:01:28 +000015SkLayerDrawLooper::SkLayerDrawLooper()
16 : fRecs(NULL),
17 fCount(0),
18 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000019}
20
21SkLayerDrawLooper::~SkLayerDrawLooper() {
22 Rec* rec = fRecs;
23 while (rec) {
24 Rec* next = rec->fNext;
25 SkDELETE(rec);
26 rec = next;
27 }
28}
reed@google.com0716c632011-04-12 18:32:06 +000029
30SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 fCount += 1;
32
33 Rec* rec = SkNEW(Rec);
34 rec->fNext = fRecs;
reed@google.com0716c632011-04-12 18:32:06 +000035 rec->fInfo = info;
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 fRecs = rec;
37
38 return &rec->fPaint;
39}
40
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000041void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) {
reed@google.com0716c632011-04-12 18:32:06 +000042 LayerInfo info;
43
44 info.fOffset.set(dx, dy);
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000045 (void)this->addLayer(info);
reed@google.com0716c632011-04-12 18:32:06 +000046}
47
reed@google.com4e2b3d32011-04-07 14:18:59 +000048void SkLayerDrawLooper::init(SkCanvas* canvas) {
49 fCurrRec = fRecs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 canvas->save(SkCanvas::kMatrix_SaveFlag);
51}
52
reed@google.com0716c632011-04-12 18:32:06 +000053static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) {
54 switch (mode) {
55 case SkXfermode::kSrc_Mode:
56 return src;
57 case SkXfermode::kDst_Mode:
58 return dst;
59 default: {
60 SkPMColor pmS = SkPreMultiplyColor(src);
61 SkPMColor pmD = SkPreMultiplyColor(dst);
62 SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD);
63 return SkUnPreMultiply::PMColorToColor(result);
64 }
65 }
66}
67
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000068void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src,
69 const LayerInfo& info) {
70
71 uint32_t mask = info.fFlagsMask;
72 dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask));
73
74 dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
75
76 BitFlags bits = info.fPaintBits;
reed@google.com0716c632011-04-12 18:32:06 +000077
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000078 if (0 == bits) {
79 return;
80 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000081 if (kEntirePaint_Bits == bits) {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000082 // we've already computed these, so save it from the assignment
83 uint32_t f = dst->getFlags();
reed@google.com0716c632011-04-12 18:32:06 +000084 SkColor c = dst->getColor();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000085 *dst = src;
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000086 dst->setFlags(f);
reed@google.com0716c632011-04-12 18:32:06 +000087 dst->setColor(c);
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000088 return;
89 }
90
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000091 if (bits & kStyle_Bit) {
92 dst->setStyle(src.getStyle());
93 dst->setStrokeWidth(src.getStrokeWidth());
94 dst->setStrokeMiter(src.getStrokeMiter());
95 dst->setStrokeCap(src.getStrokeCap());
96 dst->setStrokeJoin(src.getStrokeJoin());
97 }
98
99 if (bits & kTextSkewX_Bit) {
100 dst->setTextSkewX(src.getTextSkewX());
101 }
102
103 if (bits & kPathEffect_Bit) {
104 dst->setPathEffect(src.getPathEffect());
105 }
106 if (bits & kMaskFilter_Bit) {
107 dst->setMaskFilter(src.getMaskFilter());
108 }
109 if (bits & kShader_Bit) {
110 dst->setShader(src.getShader());
111 }
112 if (bits & kColorFilter_Bit) {
113 dst->setColorFilter(src.getColorFilter());
114 }
115 if (bits & kXfermode_Bit) {
116 dst->setXfermode(src.getXfermode());
117 }
118
119 // we never copy these
120#if 0
121 dst->setFlags(src.getFlags());
122 dst->setTypeface(src.getTypeface());
123 dst->setTextSize(src.getTextSize());
124 dst->setTextScaleX(src.getTextScaleX());
125 dst->setTextSkewX(src.getTextSkewX());
126 dst->setRasterizer(src.getRasterizer());
127 dst->setLooper(src.getLooper());
128 dst->setTextEncoding(src.getTextEncoding());
129 dst->setHinting(src.getHinting());
130#endif
131}
132
reed@google.com0716c632011-04-12 18:32:06 +0000133// Should we add this to canvas?
134static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
135 SkMatrix m = canvas->getTotalMatrix();
136 m.postTranslate(dx, dy);
137 canvas->setMatrix(m);
138}
139
reed@google.com4e2b3d32011-04-07 14:18:59 +0000140bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
141 canvas->restore();
142 if (NULL == fCurrRec) {
143 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000146 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
reed@google.com0716c632011-04-12 18:32:06 +0000147
reed@google.com4e2b3d32011-04-07 14:18:59 +0000148 canvas->save(SkCanvas::kMatrix_SaveFlag);
reed@google.com0716c632011-04-12 18:32:06 +0000149 if (fCurrRec->fInfo.fPostTranslate) {
150 postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
151 fCurrRec->fInfo.fOffset.fY);
152 } else {
153 canvas->translate(fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY);
154 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000155 fCurrRec = fCurrRec->fNext;
156
reed@google.com4e2b3d32011-04-07 14:18:59 +0000157 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158}
159
160SkLayerDrawLooper::Rec* SkLayerDrawLooper::Rec::Reverse(Rec* head) {
161 Rec* rec = head;
162 Rec* prev = NULL;
163 while (rec) {
164 Rec* next = rec->fNext;
165 rec->fNext = prev;
166 prev = rec;
167 rec = next;
168 }
169 return prev;
170}
171
172///////////////////////////////////////////////////////////////////////////////
173
174void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) {
175 this->INHERITED::flatten(buffer);
176
177#ifdef SK_DEBUG
178 {
179 Rec* rec = fRecs;
180 int count = 0;
181 while (rec) {
182 rec = rec->fNext;
183 count += 1;
184 }
185 SkASSERT(count == fCount);
186 }
187#endif
188
189 buffer.writeInt(fCount);
190
191 Rec* rec = fRecs;
192 for (int i = 0; i < fCount; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000193 buffer.writeInt(rec->fInfo.fPaintBits);
194 buffer.writeInt(rec->fInfo.fColorMode);
195 buffer.writeScalar(rec->fInfo.fOffset.fX);
196 buffer.writeScalar(rec->fInfo.fOffset.fY);
197 buffer.writeBool(rec->fInfo.fPostTranslate);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 rec->fPaint.flatten(buffer);
199 rec = rec->fNext;
200 }
201}
202
203SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
vandebo@chromium.org3c898182011-06-22 05:01:28 +0000204 : INHERITED(buffer),
205 fRecs(NULL),
206 fCount(0),
207 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 int count = buffer.readInt();
209
210 for (int i = 0; i < count; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000211 LayerInfo info;
212 info.fPaintBits = buffer.readInt();
213 info.fColorMode = (SkXfermode::Mode)buffer.readInt();
214 info.fOffset.fX = buffer.readScalar();
215 info.fOffset.fY = buffer.readScalar();
216 info.fPostTranslate = buffer.readBool();
217 this->addLayer(info)->unflatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 }
219 SkASSERT(count == fCount);
220
221 // we're in reverse order, so fix it now
222 fRecs = Rec::Reverse(fRecs);
223
224#ifdef SK_DEBUG
225 {
226 Rec* rec = fRecs;
227 int n = 0;
228 while (rec) {
229 rec = rec->fNext;
230 n += 1;
231 }
232 SkASSERT(count == n);
233 }
234#endif
235}
236
237///////////////////////////////////////////////////////////////////////////////
238
239static SkFlattenable::Registrar gReg("SkLayerDrawLooper",
240 SkLayerDrawLooper::CreateProc);