blob: ba7a80f3473a9792fa21d1b8503e609bc306ed56 [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
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000075void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src,
76 const LayerInfo& info) {
77
78 uint32_t mask = info.fFlagsMask;
79 dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask));
80
81 dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
82
83 BitFlags bits = info.fPaintBits;
reed@google.com0716c632011-04-12 18:32:06 +000084
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000085 if (0 == bits) {
86 return;
87 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000088 if (kEntirePaint_Bits == bits) {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000089 // we've already computed these, so save it from the assignment
90 uint32_t f = dst->getFlags();
reed@google.com0716c632011-04-12 18:32:06 +000091 SkColor c = dst->getColor();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000092 *dst = src;
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000093 dst->setFlags(f);
reed@google.com0716c632011-04-12 18:32:06 +000094 dst->setColor(c);
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000095 return;
96 }
97
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000098 if (bits & kStyle_Bit) {
99 dst->setStyle(src.getStyle());
100 dst->setStrokeWidth(src.getStrokeWidth());
101 dst->setStrokeMiter(src.getStrokeMiter());
102 dst->setStrokeCap(src.getStrokeCap());
103 dst->setStrokeJoin(src.getStrokeJoin());
104 }
105
106 if (bits & kTextSkewX_Bit) {
107 dst->setTextSkewX(src.getTextSkewX());
108 }
109
110 if (bits & kPathEffect_Bit) {
111 dst->setPathEffect(src.getPathEffect());
112 }
113 if (bits & kMaskFilter_Bit) {
114 dst->setMaskFilter(src.getMaskFilter());
115 }
116 if (bits & kShader_Bit) {
117 dst->setShader(src.getShader());
118 }
119 if (bits & kColorFilter_Bit) {
120 dst->setColorFilter(src.getColorFilter());
121 }
122 if (bits & kXfermode_Bit) {
123 dst->setXfermode(src.getXfermode());
124 }
125
126 // we never copy these
127#if 0
128 dst->setFlags(src.getFlags());
129 dst->setTypeface(src.getTypeface());
130 dst->setTextSize(src.getTextSize());
131 dst->setTextScaleX(src.getTextScaleX());
132 dst->setTextSkewX(src.getTextSkewX());
133 dst->setRasterizer(src.getRasterizer());
134 dst->setLooper(src.getLooper());
135 dst->setTextEncoding(src.getTextEncoding());
136 dst->setHinting(src.getHinting());
137#endif
138}
139
reed@google.com0716c632011-04-12 18:32:06 +0000140// Should we add this to canvas?
141static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
142 SkMatrix m = canvas->getTotalMatrix();
143 m.postTranslate(dx, dy);
144 canvas->setMatrix(m);
145}
146
reed@google.com4e2b3d32011-04-07 14:18:59 +0000147bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
148 canvas->restore();
149 if (NULL == fCurrRec) {
150 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000153 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
reed@google.com0716c632011-04-12 18:32:06 +0000154
reed@google.com4e2b3d32011-04-07 14:18:59 +0000155 canvas->save(SkCanvas::kMatrix_SaveFlag);
reed@google.com0716c632011-04-12 18:32:06 +0000156 if (fCurrRec->fInfo.fPostTranslate) {
157 postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
158 fCurrRec->fInfo.fOffset.fY);
159 } else {
160 canvas->translate(fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY);
161 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000162 fCurrRec = fCurrRec->fNext;
163
reed@google.com4e2b3d32011-04-07 14:18:59 +0000164 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165}
166
167SkLayerDrawLooper::Rec* SkLayerDrawLooper::Rec::Reverse(Rec* head) {
168 Rec* rec = head;
169 Rec* prev = NULL;
170 while (rec) {
171 Rec* next = rec->fNext;
172 rec->fNext = prev;
173 prev = rec;
174 rec = next;
175 }
176 return prev;
177}
178
179///////////////////////////////////////////////////////////////////////////////
180
181void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) {
182 this->INHERITED::flatten(buffer);
183
184#ifdef SK_DEBUG
185 {
186 Rec* rec = fRecs;
187 int count = 0;
188 while (rec) {
189 rec = rec->fNext;
190 count += 1;
191 }
192 SkASSERT(count == fCount);
193 }
194#endif
195
196 buffer.writeInt(fCount);
197
198 Rec* rec = fRecs;
199 for (int i = 0; i < fCount; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000200 buffer.writeInt(rec->fInfo.fPaintBits);
201 buffer.writeInt(rec->fInfo.fColorMode);
202 buffer.writeScalar(rec->fInfo.fOffset.fX);
203 buffer.writeScalar(rec->fInfo.fOffset.fY);
204 buffer.writeBool(rec->fInfo.fPostTranslate);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 rec->fPaint.flatten(buffer);
206 rec = rec->fNext;
207 }
208}
209
210SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
vandebo@chromium.org3c898182011-06-22 05:01:28 +0000211 : INHERITED(buffer),
212 fRecs(NULL),
213 fCount(0),
214 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 int count = buffer.readInt();
216
217 for (int i = 0; i < count; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000218 LayerInfo info;
219 info.fPaintBits = buffer.readInt();
220 info.fColorMode = (SkXfermode::Mode)buffer.readInt();
221 info.fOffset.fX = buffer.readScalar();
222 info.fOffset.fY = buffer.readScalar();
223 info.fPostTranslate = buffer.readBool();
224 this->addLayer(info)->unflatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 }
226 SkASSERT(count == fCount);
227
228 // we're in reverse order, so fix it now
229 fRecs = Rec::Reverse(fRecs);
230
231#ifdef SK_DEBUG
232 {
233 Rec* rec = fRecs;
234 int n = 0;
235 while (rec) {
236 rec = rec->fNext;
237 n += 1;
238 }
239 SkASSERT(count == n);
240 }
241#endif
242}
243
244///////////////////////////////////////////////////////////////////////////////
245
246static SkFlattenable::Registrar gReg("SkLayerDrawLooper",
247 SkLayerDrawLooper::CreateProc);