blob: 34aaad899ab1425a20d862cf84b0ee31cdaf6f71 [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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000010#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkLayerDrawLooper.h"
robertphillips@google.com4991b8f2013-01-28 20:21:59 +000012#include "SkString.h"
13#include "SkStringUtils.h"
reed@google.com0716c632011-04-12 18:32:06 +000014#include "SkUnPreMultiply.h"
15
robertphillips@google.com0456e0b2012-06-27 14:03:26 +000016SK_DEFINE_INST_COUNT(SkLayerDrawLooper)
17
reed@google.com0716c632011-04-12 18:32:06 +000018SkLayerDrawLooper::LayerInfo::LayerInfo() {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000019 fFlagsMask = 0; // ignore our paint flags
20 fPaintBits = 0; // ignore our paint fields
reed@google.com0716c632011-04-12 18:32:06 +000021 fColorMode = SkXfermode::kDst_Mode; // ignore our color
22 fOffset.set(0, 0);
23 fPostTranslate = false;
24}
reed@android.com8a1c16f2008-12-17 15:59:43 +000025
vandebo@chromium.org3c898182011-06-22 05:01:28 +000026SkLayerDrawLooper::SkLayerDrawLooper()
27 : fRecs(NULL),
28 fCount(0),
29 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000030}
31
32SkLayerDrawLooper::~SkLayerDrawLooper() {
33 Rec* rec = fRecs;
34 while (rec) {
35 Rec* next = rec->fNext;
36 SkDELETE(rec);
37 rec = next;
38 }
39}
reed@google.com0716c632011-04-12 18:32:06 +000040
41SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 fCount += 1;
43
44 Rec* rec = SkNEW(Rec);
45 rec->fNext = fRecs;
reed@google.com0716c632011-04-12 18:32:06 +000046 rec->fInfo = info;
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 fRecs = rec;
48
49 return &rec->fPaint;
50}
51
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000052void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) {
reed@google.com0716c632011-04-12 18:32:06 +000053 LayerInfo info;
54
55 info.fOffset.set(dx, dy);
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000056 (void)this->addLayer(info);
reed@google.com0716c632011-04-12 18:32:06 +000057}
58
reed@google.com4e2b3d32011-04-07 14:18:59 +000059void SkLayerDrawLooper::init(SkCanvas* canvas) {
60 fCurrRec = fRecs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 canvas->save(SkCanvas::kMatrix_SaveFlag);
62}
63
reed@google.com0716c632011-04-12 18:32:06 +000064static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) {
65 switch (mode) {
66 case SkXfermode::kSrc_Mode:
67 return src;
68 case SkXfermode::kDst_Mode:
69 return dst;
70 default: {
71 SkPMColor pmS = SkPreMultiplyColor(src);
72 SkPMColor pmD = SkPreMultiplyColor(dst);
73 SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD);
74 return SkUnPreMultiply::PMColorToColor(result);
75 }
76 }
77}
78
reed@google.com84260582011-11-21 16:42:10 +000079// Even with kEntirePaint_Bits, we always ensure that the master paint's
80// text-encoding is respected, since that controls how we interpret the
81// text/length parameters of a draw[Pos]Text call.
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000082void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src,
83 const LayerInfo& info) {
84
85 uint32_t mask = info.fFlagsMask;
86 dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask));
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000087 dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
88
89 BitFlags bits = info.fPaintBits;
reed@google.com84260582011-11-21 16:42:10 +000090 SkPaint::TextEncoding encoding = dst->getTextEncoding();
reed@google.com0716c632011-04-12 18:32:06 +000091
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000092 if (0 == bits) {
93 return;
94 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000095 if (kEntirePaint_Bits == bits) {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000096 // we've already computed these, so save it from the assignment
97 uint32_t f = dst->getFlags();
reed@google.com0716c632011-04-12 18:32:06 +000098 SkColor c = dst->getColor();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000099 *dst = src;
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000100 dst->setFlags(f);
reed@google.com0716c632011-04-12 18:32:06 +0000101 dst->setColor(c);
reed@google.com84260582011-11-21 16:42:10 +0000102 dst->setTextEncoding(encoding);
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000103 return;
104 }
105
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000106 if (bits & kStyle_Bit) {
107 dst->setStyle(src.getStyle());
108 dst->setStrokeWidth(src.getStrokeWidth());
109 dst->setStrokeMiter(src.getStrokeMiter());
110 dst->setStrokeCap(src.getStrokeCap());
111 dst->setStrokeJoin(src.getStrokeJoin());
112 }
113
114 if (bits & kTextSkewX_Bit) {
115 dst->setTextSkewX(src.getTextSkewX());
116 }
117
118 if (bits & kPathEffect_Bit) {
119 dst->setPathEffect(src.getPathEffect());
120 }
121 if (bits & kMaskFilter_Bit) {
122 dst->setMaskFilter(src.getMaskFilter());
123 }
124 if (bits & kShader_Bit) {
125 dst->setShader(src.getShader());
126 }
127 if (bits & kColorFilter_Bit) {
128 dst->setColorFilter(src.getColorFilter());
129 }
130 if (bits & kXfermode_Bit) {
131 dst->setXfermode(src.getXfermode());
132 }
133
reed@google.com84260582011-11-21 16:42:10 +0000134 // we don't override these
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000135#if 0
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000136 dst->setTypeface(src.getTypeface());
137 dst->setTextSize(src.getTextSize());
138 dst->setTextScaleX(src.getTextScaleX());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000139 dst->setRasterizer(src.getRasterizer());
140 dst->setLooper(src.getLooper());
141 dst->setTextEncoding(src.getTextEncoding());
142 dst->setHinting(src.getHinting());
143#endif
144}
145
reed@google.com0716c632011-04-12 18:32:06 +0000146// Should we add this to canvas?
147static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
148 SkMatrix m = canvas->getTotalMatrix();
149 m.postTranslate(dx, dy);
150 canvas->setMatrix(m);
151}
152
reed@google.com4e2b3d32011-04-07 14:18:59 +0000153bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
154 canvas->restore();
155 if (NULL == fCurrRec) {
156 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000159 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
reed@google.com0716c632011-04-12 18:32:06 +0000160
reed@google.com4e2b3d32011-04-07 14:18:59 +0000161 canvas->save(SkCanvas::kMatrix_SaveFlag);
reed@google.com0716c632011-04-12 18:32:06 +0000162 if (fCurrRec->fInfo.fPostTranslate) {
163 postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
164 fCurrRec->fInfo.fOffset.fY);
165 } else {
166 canvas->translate(fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY);
167 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000168 fCurrRec = fCurrRec->fNext;
169
reed@google.com4e2b3d32011-04-07 14:18:59 +0000170 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171}
172
173SkLayerDrawLooper::Rec* SkLayerDrawLooper::Rec::Reverse(Rec* head) {
174 Rec* rec = head;
175 Rec* prev = NULL;
176 while (rec) {
177 Rec* next = rec->fNext;
178 rec->fNext = prev;
179 prev = rec;
180 rec = next;
181 }
182 return prev;
183}
184
185///////////////////////////////////////////////////////////////////////////////
186
djsollen@google.com54924242012-03-29 15:18:04 +0000187void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 this->INHERITED::flatten(buffer);
189
190#ifdef SK_DEBUG
191 {
192 Rec* rec = fRecs;
193 int count = 0;
194 while (rec) {
195 rec = rec->fNext;
196 count += 1;
197 }
198 SkASSERT(count == fCount);
199 }
200#endif
201
202 buffer.writeInt(fCount);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 Rec* rec = fRecs;
205 for (int i = 0; i < fCount; i++) {
reed@google.com076f4c92012-07-31 14:32:38 +0000206 buffer.writeInt(rec->fInfo.fFlagsMask);
reed@google.com0716c632011-04-12 18:32:06 +0000207 buffer.writeInt(rec->fInfo.fPaintBits);
208 buffer.writeInt(rec->fInfo.fColorMode);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000209 buffer.writePoint(rec->fInfo.fOffset);
reed@google.com0716c632011-04-12 18:32:06 +0000210 buffer.writeBool(rec->fInfo.fPostTranslate);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000211 buffer.writePaint(rec->fPaint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 rec = rec->fNext;
213 }
214}
215
216SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
vandebo@chromium.org3c898182011-06-22 05:01:28 +0000217 : INHERITED(buffer),
218 fRecs(NULL),
219 fCount(0),
220 fCurrRec(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 int count = buffer.readInt();
222
223 for (int i = 0; i < count; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000224 LayerInfo info;
reed@google.com076f4c92012-07-31 14:32:38 +0000225 info.fFlagsMask = buffer.readInt();
reed@google.com0716c632011-04-12 18:32:06 +0000226 info.fPaintBits = buffer.readInt();
227 info.fColorMode = (SkXfermode::Mode)buffer.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000228 buffer.readPoint(&info.fOffset);
reed@google.com0716c632011-04-12 18:32:06 +0000229 info.fPostTranslate = buffer.readBool();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000230 buffer.readPaint(this->addLayer(info));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 }
232 SkASSERT(count == fCount);
233
234 // we're in reverse order, so fix it now
235 fRecs = Rec::Reverse(fRecs);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237#ifdef SK_DEBUG
238 {
239 Rec* rec = fRecs;
240 int n = 0;
241 while (rec) {
242 rec = rec->fNext;
243 n += 1;
244 }
245 SkASSERT(count == n);
246 }
247#endif
248}
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000249
250#ifdef SK_DEVELOPER
251void SkLayerDrawLooper::toString(SkString* str) const {
252 str->appendf("SkLayerDrawLooper (%d): ", fCount);
253
254 Rec* rec = fRecs;
255 for (int i = 0; i < fCount; i++) {
256 str->appendf("%d: ", i);
257
258 str->append("flagsMask: (");
259 if (0 == rec->fInfo.fFlagsMask) {
260 str->append("None");
261 } else {
262 bool needSeparator = false;
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000263 SkAddFlagToString(str, SkToBool(SkPaint::kAntiAlias_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000264 "AntiAlias", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000265 SkAddFlagToString(str, SkToBool(SkPaint::kFilterBitmap_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000266 "FilterBitmap", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000267 SkAddFlagToString(str, SkToBool(SkPaint::kDither_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000268 "Dither", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000269 SkAddFlagToString(str, SkToBool(SkPaint::kUnderlineText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000270 "UnderlineText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000271 SkAddFlagToString(str, SkToBool(SkPaint::kStrikeThruText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000272 "StrikeThruText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000273 SkAddFlagToString(str, SkToBool(SkPaint::kFakeBoldText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000274 "FakeBoldText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000275 SkAddFlagToString(str, SkToBool(SkPaint::kLinearText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000276 "LinearText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000277 SkAddFlagToString(str, SkToBool(SkPaint::kSubpixelText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000278 "SubpixelText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000279 SkAddFlagToString(str, SkToBool(SkPaint::kDevKernText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000280 "DevKernText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000281 SkAddFlagToString(str, SkToBool(SkPaint::kLCDRenderText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000282 "LCDRenderText", &needSeparator);
283 SkAddFlagToString(str, SkToBool(SkPaint::kEmbeddedBitmapText_Flag & rec->fInfo.fFlagsMask),
284 "EmbeddedBitmapText", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000285 SkAddFlagToString(str, SkToBool(SkPaint::kAutoHinting_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000286 "Autohinted", &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000287 SkAddFlagToString(str, SkToBool(SkPaint::kVerticalText_Flag & rec->fInfo.fFlagsMask),
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000288 "VerticalText", &needSeparator);
289 SkAddFlagToString(str, SkToBool(SkPaint::kGenA8FromLCD_Flag & rec->fInfo.fFlagsMask),
290 "GenA8FromLCD", &needSeparator);
291 }
292 str->append(") ");
293
294 str->append("paintBits: (");
295 if (0 == rec->fInfo.fPaintBits) {
296 str->append("None");
297 } else if (kEntirePaint_Bits == rec->fInfo.fPaintBits) {
298 str->append("EntirePaint");
299 } else {
300 bool needSeparator = false;
301 SkAddFlagToString(str, SkToBool(kStyle_Bit & rec->fInfo.fPaintBits), "Style",
302 &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000303 SkAddFlagToString(str, SkToBool(kTextSkewX_Bit & rec->fInfo.fPaintBits), "TextSkewX",
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000304 &needSeparator);
305 SkAddFlagToString(str, SkToBool(kPathEffect_Bit & rec->fInfo.fPaintBits), "PathEffect",
306 &needSeparator);
307 SkAddFlagToString(str, SkToBool(kMaskFilter_Bit & rec->fInfo.fPaintBits), "MaskFilter",
308 &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000309 SkAddFlagToString(str, SkToBool(kShader_Bit & rec->fInfo.fPaintBits), "Shader",
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000310 &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000311 SkAddFlagToString(str, SkToBool(kColorFilter_Bit & rec->fInfo.fPaintBits), "ColorFilter",
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000312 &needSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000313 SkAddFlagToString(str, SkToBool(kXfermode_Bit & rec->fInfo.fPaintBits), "Xfermode",
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000314 &needSeparator);
315 }
316 str->append(") ");
317
318 static const char* gModeStrings[SkXfermode::kLastMode+1] = {
319 "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn",
320 "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus",
321 "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge",
322 "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion"
323 };
324
325 str->appendf("mode: %s ", gModeStrings[rec->fInfo.fColorMode]);
326
327 str->append("offset: (");
328 str->appendScalar(rec->fInfo.fOffset.fX);
329 str->append(", ");
330 str->appendScalar(rec->fInfo.fOffset.fY);
331 str->append(") ");
332
333 str->append("postTranslate: ");
334 if (rec->fInfo.fPostTranslate) {
335 str->append("true ");
336 } else {
337 str->append("false ");
338 }
339
robertphillips@google.com791f12e2013-02-14 13:53:53 +0000340 rec->fPaint.toString(str);
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000341 rec = rec->fNext;
342 }
343}
344#endif