blob: acb3e8891f767a8bea8d42926991beb7dcab86f9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkCanvas.h"
reed@google.com0716c632011-04-12 18:32:06 +00009#include "SkColor.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkLayerDrawLooper.h"
11#include "SkPaint.h"
reed@google.com0716c632011-04-12 18:32:06 +000012#include "SkUnPreMultiply.h"
13
14SkLayerDrawLooper::LayerInfo::LayerInfo() {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000015 fFlagsMask = 0; // ignore our paint flags
16 fPaintBits = 0; // ignore our paint fields
reed@google.com0716c632011-04-12 18:32:06 +000017 fColorMode = SkXfermode::kDst_Mode; // ignore our color
18 fOffset.set(0, 0);
19 fPostTranslate = false;
20}
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
vandebo@chromium.org3c898182011-06-22 05:01:28 +000022SkLayerDrawLooper::SkLayerDrawLooper()
23 : fRecs(NULL),
24 fCount(0),
25 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000026}
27
28SkLayerDrawLooper::~SkLayerDrawLooper() {
29 Rec* rec = fRecs;
30 while (rec) {
31 Rec* next = rec->fNext;
32 SkDELETE(rec);
33 rec = next;
34 }
35}
reed@google.com0716c632011-04-12 18:32:06 +000036
37SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 fCount += 1;
39
40 Rec* rec = SkNEW(Rec);
41 rec->fNext = fRecs;
reed@google.com0716c632011-04-12 18:32:06 +000042 rec->fInfo = info;
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 fRecs = rec;
44
45 return &rec->fPaint;
46}
47
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000048void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) {
reed@google.com0716c632011-04-12 18:32:06 +000049 LayerInfo info;
50
51 info.fOffset.set(dx, dy);
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000052 (void)this->addLayer(info);
reed@google.com0716c632011-04-12 18:32:06 +000053}
54
reed@google.com4e2b3d32011-04-07 14:18:59 +000055void SkLayerDrawLooper::init(SkCanvas* canvas) {
56 fCurrRec = fRecs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 canvas->save(SkCanvas::kMatrix_SaveFlag);
58}
59
reed@google.com0716c632011-04-12 18:32:06 +000060static 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
reed@google.com84260582011-11-21 16:42:10 +000075// 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.
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000078void 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));
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000083 dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
84
85 BitFlags bits = info.fPaintBits;
reed@google.com84260582011-11-21 16:42:10 +000086 SkPaint::TextEncoding encoding = dst->getTextEncoding();
reed@google.com0716c632011-04-12 18:32:06 +000087
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000088 if (0 == bits) {
89 return;
90 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000091 if (kEntirePaint_Bits == bits) {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000092 // we've already computed these, so save it from the assignment
93 uint32_t f = dst->getFlags();
reed@google.com0716c632011-04-12 18:32:06 +000094 SkColor c = dst->getColor();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000095 *dst = src;
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000096 dst->setFlags(f);
reed@google.com0716c632011-04-12 18:32:06 +000097 dst->setColor(c);
reed@google.com84260582011-11-21 16:42:10 +000098 dst->setTextEncoding(encoding);
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000099 return;
100 }
101
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000102 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
reed@google.com84260582011-11-21 16:42:10 +0000130 // we don't override these
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000131#if 0
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000132 dst->setTypeface(src.getTypeface());
133 dst->setTextSize(src.getTextSize());
134 dst->setTextScaleX(src.getTextScaleX());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000135 dst->setRasterizer(src.getRasterizer());
136 dst->setLooper(src.getLooper());
137 dst->setTextEncoding(src.getTextEncoding());
138 dst->setHinting(src.getHinting());
139#endif
140}
141
reed@google.com0716c632011-04-12 18:32:06 +0000142// 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
reed@google.com4e2b3d32011-04-07 14:18:59 +0000149bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
150 canvas->restore();
151 if (NULL == fCurrRec) {
152 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000155 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
reed@google.com0716c632011-04-12 18:32:06 +0000156
reed@google.com4e2b3d32011-04-07 14:18:59 +0000157 canvas->save(SkCanvas::kMatrix_SaveFlag);
reed@google.com0716c632011-04-12 18:32:06 +0000158 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 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000164 fCurrRec = fCurrRec->fNext;
165
reed@google.com4e2b3d32011-04-07 14:18:59 +0000166 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167}
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) {
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++) {
reed@google.com0716c632011-04-12 18:32:06 +0000202 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 rec->fPaint.flatten(buffer);
208 rec = rec->fNext;
209 }
210}
211
212SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
vandebo@chromium.org3c898182011-06-22 05:01:28 +0000213 : INHERITED(buffer),
214 fRecs(NULL),
215 fCount(0),
216 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 int count = buffer.readInt();
218
219 for (int i = 0; i < count; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000220 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 }
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
caryclark@google.comd26147a2011-12-15 14:16:43 +0000248SK_DEFINE_FLATTENABLE_REGISTRAR(SkLayerDrawLooper)