blob: b3f388657d9c6c8d396bf4dce783fd0b6cc60508 [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() {
8 fPaintBits = 0; // ignore out paint
9 fColorMode = SkXfermode::kDst_Mode; // ignore our color
10 fOffset.set(0, 0);
11 fPostTranslate = false;
12}
reed@android.com8a1c16f2008-12-17 15:59:43 +000013
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}
reed@google.com0716c632011-04-12 18:32:06 +000027
28SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 fCount += 1;
30
31 Rec* rec = SkNEW(Rec);
32 rec->fNext = fRecs;
reed@google.com0716c632011-04-12 18:32:06 +000033 rec->fInfo = info;
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 fRecs = rec;
35
36 return &rec->fPaint;
37}
38
reed@google.com0716c632011-04-12 18:32:06 +000039SkPaint* SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) {
40 LayerInfo info;
41
42 info.fOffset.set(dx, dy);
43 return this->addLayer(info);
44}
45
reed@google.com4e2b3d32011-04-07 14:18:59 +000046void SkLayerDrawLooper::init(SkCanvas* canvas) {
47 fCurrRec = fRecs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000048 canvas->save(SkCanvas::kMatrix_SaveFlag);
49}
50
reed@google.com0716c632011-04-12 18:32:06 +000051static 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
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000066void SkLayerDrawLooper::ApplyBits(SkPaint* dst, const SkPaint& src,
reed@google.com0716c632011-04-12 18:32:06 +000067 BitFlags bits, SkXfermode::Mode colorMode) {
68 dst->setColor(xferColor(src.getColor(), dst->getColor(), colorMode));
69
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000070 if (0 == bits) {
71 return;
72 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000073 if (kEntirePaint_Bits == bits) {
reed@google.com0716c632011-04-12 18:32:06 +000074 // we've already compute the color, so save it from the assignment
75 SkColor c = dst->getColor();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000076 *dst = src;
reed@google.com0716c632011-04-12 18:32:06 +000077 dst->setColor(c);
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000078 return;
79 }
80
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000081 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
reed@google.com0716c632011-04-12 18:32:06 +0000123// 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
reed@google.com4e2b3d32011-04-07 14:18:59 +0000130bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
131 canvas->restore();
132 if (NULL == fCurrRec) {
133 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135
reed@google.com0716c632011-04-12 18:32:06 +0000136 ApplyBits(paint, fCurrRec->fPaint, fCurrRec->fInfo.fPaintBits,
137 fCurrRec->fInfo.fColorMode);
138
reed@google.com4e2b3d32011-04-07 14:18:59 +0000139 canvas->save(SkCanvas::kMatrix_SaveFlag);
reed@google.com0716c632011-04-12 18:32:06 +0000140 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 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000146 fCurrRec = fCurrRec->fNext;
147
reed@google.com4e2b3d32011-04-07 14:18:59 +0000148 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149}
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++) {
reed@google.com0716c632011-04-12 18:32:06 +0000184 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 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++) {
reed@google.com0716c632011-04-12 18:32:06 +0000202 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
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);