1 
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  */
8 #include "SkCanvas.h"
9 #include "SkColor.h"
10 #include "SkReadBuffer.h"
11 #include "SkWriteBuffer.h"
12 #include "SkLayerDrawLooper.h"
13 #include "SkString.h"
14 #include "SkStringUtils.h"
15 #include "SkUnPreMultiply.h"
16 
LayerInfo()17 SkLayerDrawLooper::LayerInfo::LayerInfo() {
18     fPaintBits = 0;                     // ignore our paint fields
19     fColorMode = SkXfermode::kDst_Mode; // ignore our color
20     fOffset.set(0, 0);
21     fPostTranslate = false;
22 }
23 
SkLayerDrawLooper()24 SkLayerDrawLooper::SkLayerDrawLooper()
25         : fRecs(NULL),
26           fTopRec(NULL),
27           fCount(0) {
28 }
29 
~SkLayerDrawLooper()30 SkLayerDrawLooper::~SkLayerDrawLooper() {
31     Rec* rec = fRecs;
32     while (rec) {
33         Rec* next = rec->fNext;
34         SkDELETE(rec);
35         rec = next;
36     }
37 }
38 
createContext(SkCanvas * canvas,void * storage) const39 SkLayerDrawLooper::Context* SkLayerDrawLooper::createContext(SkCanvas* canvas, void* storage) const {
40     canvas->save();
41     return SkNEW_PLACEMENT_ARGS(storage, LayerDrawLooperContext, (this));
42 }
43 
xferColor(SkColor src,SkColor dst,SkXfermode::Mode mode)44 static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) {
45     switch (mode) {
46         case SkXfermode::kSrc_Mode:
47             return src;
48         case SkXfermode::kDst_Mode:
49             return dst;
50         default: {
51             SkPMColor pmS = SkPreMultiplyColor(src);
52             SkPMColor pmD = SkPreMultiplyColor(dst);
53             SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD);
54             return SkUnPreMultiply::PMColorToColor(result);
55         }
56     }
57 }
58 
59 // Even with kEntirePaint_Bits, we always ensure that the master paint's
60 // text-encoding is respected, since that controls how we interpret the
61 // text/length parameters of a draw[Pos]Text call.
ApplyInfo(SkPaint * dst,const SkPaint & src,const LayerInfo & info)62 void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
63         SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
64 
65     dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
66 
67     BitFlags bits = info.fPaintBits;
68     SkPaint::TextEncoding encoding = dst->getTextEncoding();
69 
70     if (0 == bits) {
71         return;
72     }
73     if (kEntirePaint_Bits == bits) {
74         // we've already computed these, so save it from the assignment
75         uint32_t f = dst->getFlags();
76         SkColor c = dst->getColor();
77         *dst = src;
78         dst->setFlags(f);
79         dst->setColor(c);
80         dst->setTextEncoding(encoding);
81         return;
82     }
83 
84     if (bits & kStyle_Bit) {
85         dst->setStyle(src.getStyle());
86         dst->setStrokeWidth(src.getStrokeWidth());
87         dst->setStrokeMiter(src.getStrokeMiter());
88         dst->setStrokeCap(src.getStrokeCap());
89         dst->setStrokeJoin(src.getStrokeJoin());
90     }
91 
92     if (bits & kTextSkewX_Bit) {
93         dst->setTextSkewX(src.getTextSkewX());
94     }
95 
96     if (bits & kPathEffect_Bit) {
97         dst->setPathEffect(src.getPathEffect());
98     }
99     if (bits & kMaskFilter_Bit) {
100         dst->setMaskFilter(src.getMaskFilter());
101     }
102     if (bits & kShader_Bit) {
103         dst->setShader(src.getShader());
104     }
105     if (bits & kColorFilter_Bit) {
106         dst->setColorFilter(src.getColorFilter());
107     }
108     if (bits & kXfermode_Bit) {
109         dst->setXfermode(src.getXfermode());
110     }
111 
112     // we don't override these
113 #if 0
114     dst->setTypeface(src.getTypeface());
115     dst->setTextSize(src.getTextSize());
116     dst->setTextScaleX(src.getTextScaleX());
117     dst->setRasterizer(src.getRasterizer());
118     dst->setLooper(src.getLooper());
119     dst->setTextEncoding(src.getTextEncoding());
120     dst->setHinting(src.getHinting());
121 #endif
122 }
123 
124 // Should we add this to canvas?
postTranslate(SkCanvas * canvas,SkScalar dx,SkScalar dy)125 static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
126     SkMatrix m = canvas->getTotalMatrix();
127     m.postTranslate(dx, dy);
128     canvas->setMatrix(m);
129 }
130 
LayerDrawLooperContext(const SkLayerDrawLooper * looper)131 SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
132         const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
133 
next(SkCanvas * canvas,SkPaint * paint)134 bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas,
135                                                      SkPaint* paint) {
136     canvas->restore();
137     if (NULL == fCurrRec) {
138         return false;
139     }
140 
141     ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
142 
143     canvas->save();
144     if (fCurrRec->fInfo.fPostTranslate) {
145         postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
146                       fCurrRec->fInfo.fOffset.fY);
147     } else {
148         canvas->translate(fCurrRec->fInfo.fOffset.fX,
149                           fCurrRec->fInfo.fOffset.fY);
150     }
151     fCurrRec = fCurrRec->fNext;
152 
153     return true;
154 }
155 
asABlurShadow(BlurShadowRec * bsRec) const156 bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
157     if (fCount != 2) {
158         return false;
159     }
160     const Rec* rec = fRecs;
161 
162     // bottom layer needs to be just blur(maskfilter)
163     if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
164         return false;
165     }
166     if (SkXfermode::kSrc_Mode != rec->fInfo.fColorMode) {
167         return false;
168     }
169     const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
170     if (NULL == mf) {
171         return false;
172     }
173     SkMaskFilter::BlurRec maskBlur;
174     if (!mf->asABlur(&maskBlur)) {
175         return false;
176     }
177 
178     rec = rec->fNext;
179     // top layer needs to be "plain"
180     if (rec->fInfo.fPaintBits) {
181         return false;
182     }
183     if (SkXfermode::kDst_Mode != rec->fInfo.fColorMode) {
184         return false;
185     }
186     if (!rec->fInfo.fOffset.equals(0, 0)) {
187         return false;
188     }
189 
190     if (bsRec) {
191         bsRec->fSigma = maskBlur.fSigma;
192         bsRec->fOffset = fRecs->fInfo.fOffset;
193         bsRec->fColor = fRecs->fPaint.getColor();
194         bsRec->fStyle = maskBlur.fStyle;
195         bsRec->fQuality = maskBlur.fQuality;
196     }
197     return true;
198 }
199 
200 ///////////////////////////////////////////////////////////////////////////////
201 
flatten(SkWriteBuffer & buffer) const202 void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
203     buffer.writeInt(fCount);
204 
205     Rec* rec = fRecs;
206     for (int i = 0; i < fCount; i++) {
207         // Legacy "flagsmask" field -- now ignored, remove when we bump version
208         buffer.writeInt(0);
209 
210         buffer.writeInt(rec->fInfo.fPaintBits);
211         buffer.writeInt(rec->fInfo.fColorMode);
212         buffer.writePoint(rec->fInfo.fOffset);
213         buffer.writeBool(rec->fInfo.fPostTranslate);
214         buffer.writePaint(rec->fPaint);
215         rec = rec->fNext;
216     }
217 }
218 
CreateProc(SkReadBuffer & buffer)219 SkFlattenable* SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
220     int count = buffer.readInt();
221 
222     Builder builder;
223     for (int i = 0; i < count; i++) {
224         LayerInfo info;
225         // Legacy "flagsmask" field -- now ignored, remove when we bump version
226         (void)buffer.readInt();
227 
228         info.fPaintBits = buffer.readInt();
229         info.fColorMode = (SkXfermode::Mode)buffer.readInt();
230         buffer.readPoint(&info.fOffset);
231         info.fPostTranslate = buffer.readBool();
232         buffer.readPaint(builder.addLayerOnTop(info));
233     }
234     return builder.detachLooper();
235 }
236 
237 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const238 void SkLayerDrawLooper::toString(SkString* str) const {
239     str->appendf("SkLayerDrawLooper (%d): ", fCount);
240 
241     Rec* rec = fRecs;
242     for (int i = 0; i < fCount; i++) {
243         str->appendf("%d: paintBits: (", i);
244         if (0 == rec->fInfo.fPaintBits) {
245             str->append("None");
246         } else if (kEntirePaint_Bits == rec->fInfo.fPaintBits) {
247             str->append("EntirePaint");
248         } else {
249             bool needSeparator = false;
250             SkAddFlagToString(str, SkToBool(kStyle_Bit & rec->fInfo.fPaintBits), "Style",
251                               &needSeparator);
252             SkAddFlagToString(str, SkToBool(kTextSkewX_Bit & rec->fInfo.fPaintBits), "TextSkewX",
253                               &needSeparator);
254             SkAddFlagToString(str, SkToBool(kPathEffect_Bit & rec->fInfo.fPaintBits), "PathEffect",
255                               &needSeparator);
256             SkAddFlagToString(str, SkToBool(kMaskFilter_Bit & rec->fInfo.fPaintBits), "MaskFilter",
257                               &needSeparator);
258             SkAddFlagToString(str, SkToBool(kShader_Bit & rec->fInfo.fPaintBits), "Shader",
259                               &needSeparator);
260             SkAddFlagToString(str, SkToBool(kColorFilter_Bit & rec->fInfo.fPaintBits), "ColorFilter",
261                               &needSeparator);
262             SkAddFlagToString(str, SkToBool(kXfermode_Bit & rec->fInfo.fPaintBits), "Xfermode",
263                               &needSeparator);
264         }
265         str->append(") ");
266 
267         static const char* gModeStrings[SkXfermode::kLastMode+1] = {
268             "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn",
269             "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus",
270             "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge",
271             "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion"
272         };
273 
274         str->appendf("mode: %s ", gModeStrings[rec->fInfo.fColorMode]);
275 
276         str->append("offset: (");
277         str->appendScalar(rec->fInfo.fOffset.fX);
278         str->append(", ");
279         str->appendScalar(rec->fInfo.fOffset.fY);
280         str->append(") ");
281 
282         str->append("postTranslate: ");
283         if (rec->fInfo.fPostTranslate) {
284             str->append("true ");
285         } else {
286             str->append("false ");
287         }
288 
289         rec->fPaint.toString(str);
290         rec = rec->fNext;
291     }
292 }
293 #endif
294 
Builder()295 SkLayerDrawLooper::Builder::Builder()
296         : fRecs(NULL),
297           fTopRec(NULL),
298           fCount(0) {
299 }
300 
~Builder()301 SkLayerDrawLooper::Builder::~Builder() {
302     Rec* rec = fRecs;
303     while (rec) {
304         Rec* next = rec->fNext;
305         SkDELETE(rec);
306         rec = next;
307     }
308 }
309 
addLayer(const LayerInfo & info)310 SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
311     fCount += 1;
312 
313     Rec* rec = SkNEW(Rec);
314     rec->fNext = fRecs;
315     rec->fInfo = info;
316     fRecs = rec;
317     if (NULL == fTopRec) {
318         fTopRec = rec;
319     }
320 
321     return &rec->fPaint;
322 }
323 
addLayer(SkScalar dx,SkScalar dy)324 void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
325     LayerInfo info;
326 
327     info.fOffset.set(dx, dy);
328     (void)this->addLayer(info);
329 }
330 
addLayerOnTop(const LayerInfo & info)331 SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
332     fCount += 1;
333 
334     Rec* rec = SkNEW(Rec);
335     rec->fNext = NULL;
336     rec->fInfo = info;
337     if (NULL == fRecs) {
338         fRecs = rec;
339     } else {
340         SkASSERT(fTopRec);
341         fTopRec->fNext = rec;
342     }
343     fTopRec = rec;
344 
345     return &rec->fPaint;
346 }
347 
detachLooper()348 SkLayerDrawLooper* SkLayerDrawLooper::Builder::detachLooper() {
349     SkLayerDrawLooper* looper = SkNEW(SkLayerDrawLooper);
350     looper->fCount = fCount;
351     looper->fRecs = fRecs;
352 
353     fCount = 0;
354     fRecs = NULL;
355     fTopRec = NULL;
356 
357     return looper;
358 }
359