• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "SkArenaAlloc.h"
8 #include "SkBlurDrawLooper.h"
9 #include "SkBlurMaskFilter.h"
10 #include "SkCanvas.h"
11 #include "SkColorSpaceXformer.h"
12 #include "SkColor.h"
13 #include "SkReadBuffer.h"
14 #include "SkWriteBuffer.h"
15 #include "SkLayerDrawLooper.h"
16 #include "SkString.h"
17 #include "SkStringUtils.h"
18 #include "SkUnPreMultiply.h"
19 #include "SkXfermodePriv.h"
20 
LayerInfo()21 SkLayerDrawLooper::LayerInfo::LayerInfo() {
22     fPaintBits = 0;                     // ignore our paint fields
23     fColorMode = SkBlendMode::kDst;     // ignore our color
24     fOffset.set(0, 0);
25     fPostTranslate = false;
26 }
27 
SkLayerDrawLooper()28 SkLayerDrawLooper::SkLayerDrawLooper()
29         : fRecs(nullptr),
30           fCount(0) {
31 }
32 
~SkLayerDrawLooper()33 SkLayerDrawLooper::~SkLayerDrawLooper() {
34     Rec* rec = fRecs;
35     while (rec) {
36         Rec* next = rec->fNext;
37         delete rec;
38         rec = next;
39     }
40 }
41 
42 SkLayerDrawLooper::Context*
makeContext(SkCanvas * canvas,SkArenaAlloc * alloc) const43 SkLayerDrawLooper::makeContext(SkCanvas* canvas, SkArenaAlloc* alloc) const {
44     canvas->save();
45     return alloc->make<LayerDrawLooperContext>(this);
46 }
47 
xferColor(SkColor src,SkColor dst,SkBlendMode mode)48 static SkColor xferColor(SkColor src, SkColor dst, SkBlendMode mode) {
49     switch (mode) {
50         case SkBlendMode::kSrc:
51             return src;
52         case SkBlendMode::kDst:
53             return dst;
54         default: {
55             SkPMColor pmS = SkPreMultiplyColor(src);
56             SkPMColor pmD = SkPreMultiplyColor(dst);
57             SkXfermode::Peek(mode)->xfer32(&pmD, &pmS, 1, nullptr);
58             return SkUnPreMultiply::PMColorToColor(pmD);
59         }
60     }
61 }
62 
63 // Even with kEntirePaint_Bits, we always ensure that the master paint's
64 // text-encoding is respected, since that controls how we interpret the
65 // text/length parameters of a draw[Pos]Text call.
ApplyInfo(SkPaint * dst,const SkPaint & src,const LayerInfo & info)66 void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
67         SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
68     SkColor srcColor = src.getColor();
69 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
70     // The framework may respect the alpha value on the original paint.
71     // Match this legacy behavior.
72     if (SkColorGetA(srcColor) == 255) {
73         srcColor = SkColorSetA(srcColor, dst->getAlpha());
74     }
75 #endif
76     dst->setColor(xferColor(srcColor, dst->getColor(), (SkBlendMode)info.fColorMode));
77 
78     BitFlags bits = info.fPaintBits;
79     SkPaint::TextEncoding encoding = dst->getTextEncoding();
80 
81     if (0 == bits) {
82         return;
83     }
84     if (kEntirePaint_Bits == bits) {
85         // we've already computed these, so save it from the assignment
86         uint32_t f = dst->getFlags();
87         SkColor c = dst->getColor();
88         *dst = src;
89         dst->setFlags(f);
90         dst->setColor(c);
91         dst->setTextEncoding(encoding);
92         return;
93     }
94 
95     if (bits & kStyle_Bit) {
96         dst->setStyle(src.getStyle());
97         dst->setStrokeWidth(src.getStrokeWidth());
98         dst->setStrokeMiter(src.getStrokeMiter());
99         dst->setStrokeCap(src.getStrokeCap());
100         dst->setStrokeJoin(src.getStrokeJoin());
101     }
102 
103     if (bits & kTextSkewX_Bit) {
104         dst->setTextSkewX(src.getTextSkewX());
105     }
106 
107     if (bits & kPathEffect_Bit) {
108         dst->setPathEffect(src.refPathEffect());
109     }
110     if (bits & kMaskFilter_Bit) {
111         dst->setMaskFilter(src.refMaskFilter());
112     }
113     if (bits & kShader_Bit) {
114         dst->setShader(src.refShader());
115     }
116     if (bits & kColorFilter_Bit) {
117         dst->setColorFilter(src.refColorFilter());
118     }
119     if (bits & kXfermode_Bit) {
120         dst->setBlendMode(src.getBlendMode());
121     }
122 
123     // we don't override these
124 #if 0
125     dst->setTypeface(src.getTypeface());
126     dst->setTextSize(src.getTextSize());
127     dst->setTextScaleX(src.getTextScaleX());
128     dst->setRasterizer(src.getRasterizer());
129     dst->setLooper(src.getLooper());
130     dst->setTextEncoding(src.getTextEncoding());
131     dst->setHinting(src.getHinting());
132 #endif
133 }
134 
135 // Should we add this to canvas?
postTranslate(SkCanvas * canvas,SkScalar dx,SkScalar dy)136 static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
137     SkMatrix m = canvas->getTotalMatrix();
138     m.postTranslate(dx, dy);
139     canvas->setMatrix(m);
140 }
141 
LayerDrawLooperContext(const SkLayerDrawLooper * looper)142 SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
143         const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
144 
next(SkCanvas * canvas,SkPaint * paint)145 bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas,
146                                                      SkPaint* paint) {
147     canvas->restore();
148     if (nullptr == fCurrRec) {
149         return false;
150     }
151 
152     ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
153 
154     canvas->save();
155     if (fCurrRec->fInfo.fPostTranslate) {
156         postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
157                       fCurrRec->fInfo.fOffset.fY);
158     } else {
159         canvas->translate(fCurrRec->fInfo.fOffset.fX,
160                           fCurrRec->fInfo.fOffset.fY);
161     }
162     fCurrRec = fCurrRec->fNext;
163 
164     return true;
165 }
166 
asABlurShadow(BlurShadowRec * bsRec) const167 bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
168     if (fCount != 2) {
169         return false;
170     }
171     const Rec* rec = fRecs;
172 
173     // bottom layer needs to be just blur(maskfilter)
174     if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
175         return false;
176     }
177     if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
178         return false;
179     }
180     const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
181     if (nullptr == mf) {
182         return false;
183     }
184     SkMaskFilter::BlurRec maskBlur;
185     if (!mf->asABlur(&maskBlur)) {
186         return false;
187     }
188 
189     rec = rec->fNext;
190     // top layer needs to be "plain"
191     if (rec->fInfo.fPaintBits) {
192         return false;
193     }
194     if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
195         return false;
196     }
197     if (!rec->fInfo.fOffset.equals(0, 0)) {
198         return false;
199     }
200 
201     if (bsRec) {
202         bsRec->fSigma = maskBlur.fSigma;
203         bsRec->fOffset = fRecs->fInfo.fOffset;
204         bsRec->fColor = fRecs->fPaint.getColor();
205         bsRec->fStyle = maskBlur.fStyle;
206         bsRec->fQuality = maskBlur.fQuality;
207     }
208     return true;
209 }
210 
onMakeColorSpace(SkColorSpaceXformer * xformer) const211 sk_sp<SkDrawLooper> SkLayerDrawLooper::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
212     if (!fCount) {
213         return sk_ref_sp(const_cast<SkLayerDrawLooper*>(this));
214     }
215 
216     auto looper = sk_sp<SkLayerDrawLooper>(new SkLayerDrawLooper());
217     looper->fCount = fCount;
218 
219     Rec* oldRec = fRecs;
220     Rec* newTopRec = new Rec();
221     newTopRec->fInfo = oldRec->fInfo;
222     newTopRec->fPaint = xformer->apply(oldRec->fPaint);
223     newTopRec->fNext = nullptr;
224 
225     Rec* prevNewRec = newTopRec;
226     oldRec = oldRec->fNext;
227     while (oldRec) {
228         Rec* newRec = new Rec();
229         newRec->fInfo = oldRec->fInfo;
230         newRec->fPaint = xformer->apply(oldRec->fPaint);
231         newRec->fNext = nullptr;
232         prevNewRec->fNext = newRec;
233 
234         prevNewRec = newRec;
235         oldRec = oldRec->fNext;
236     }
237 
238     looper->fRecs = newTopRec;
239     return std::move(looper);
240 }
241 
242 ///////////////////////////////////////////////////////////////////////////////
243 
flatten(SkWriteBuffer & buffer) const244 void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
245     buffer.writeInt(fCount);
246 
247     Rec* rec = fRecs;
248     for (int i = 0; i < fCount; i++) {
249         // Legacy "flagsmask" field -- now ignored, remove when we bump version
250         buffer.writeInt(0);
251 
252         buffer.writeInt(rec->fInfo.fPaintBits);
253         buffer.writeInt((int)rec->fInfo.fColorMode);
254         buffer.writePoint(rec->fInfo.fOffset);
255         buffer.writeBool(rec->fInfo.fPostTranslate);
256         buffer.writePaint(rec->fPaint);
257         rec = rec->fNext;
258     }
259 }
260 
CreateProc(SkReadBuffer & buffer)261 sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
262     int count = buffer.readInt();
263 
264     Builder builder;
265     for (int i = 0; i < count; i++) {
266         LayerInfo info;
267         // Legacy "flagsmask" field -- now ignored, remove when we bump version
268         (void)buffer.readInt();
269 
270         info.fPaintBits = buffer.readInt();
271         info.fColorMode = (SkBlendMode)buffer.readInt();
272         buffer.readPoint(&info.fOffset);
273         info.fPostTranslate = buffer.readBool();
274         buffer.readPaint(builder.addLayerOnTop(info));
275     }
276     return builder.detach();
277 }
278 
279 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const280 void SkLayerDrawLooper::toString(SkString* str) const {
281     str->appendf("SkLayerDrawLooper (%d): ", fCount);
282 
283     Rec* rec = fRecs;
284     for (int i = 0; i < fCount; i++) {
285         str->appendf("%d: paintBits: (", i);
286         if (0 == rec->fInfo.fPaintBits) {
287             str->append("None");
288         } else if (kEntirePaint_Bits == rec->fInfo.fPaintBits) {
289             str->append("EntirePaint");
290         } else {
291             bool needSeparator = false;
292             SkAddFlagToString(str, SkToBool(kStyle_Bit & rec->fInfo.fPaintBits), "Style",
293                               &needSeparator);
294             SkAddFlagToString(str, SkToBool(kTextSkewX_Bit & rec->fInfo.fPaintBits), "TextSkewX",
295                               &needSeparator);
296             SkAddFlagToString(str, SkToBool(kPathEffect_Bit & rec->fInfo.fPaintBits), "PathEffect",
297                               &needSeparator);
298             SkAddFlagToString(str, SkToBool(kMaskFilter_Bit & rec->fInfo.fPaintBits), "MaskFilter",
299                               &needSeparator);
300             SkAddFlagToString(str, SkToBool(kShader_Bit & rec->fInfo.fPaintBits), "Shader",
301                               &needSeparator);
302             SkAddFlagToString(str, SkToBool(kColorFilter_Bit & rec->fInfo.fPaintBits), "ColorFilter",
303                               &needSeparator);
304             SkAddFlagToString(str, SkToBool(kXfermode_Bit & rec->fInfo.fPaintBits), "Xfermode",
305                               &needSeparator);
306         }
307         str->append(") ");
308 
309         static const char* gModeStrings[(int)SkBlendMode::kLastMode+1] = {
310             "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn",
311             "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus",
312             "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge",
313             "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion"
314         };
315 
316         str->appendf("mode: %s ", gModeStrings[(int)rec->fInfo.fColorMode]);
317 
318         str->append("offset: (");
319         str->appendScalar(rec->fInfo.fOffset.fX);
320         str->append(", ");
321         str->appendScalar(rec->fInfo.fOffset.fY);
322         str->append(") ");
323 
324         str->append("postTranslate: ");
325         if (rec->fInfo.fPostTranslate) {
326             str->append("true ");
327         } else {
328             str->append("false ");
329         }
330 
331         rec->fPaint.toString(str);
332         rec = rec->fNext;
333     }
334 }
335 #endif
336 
Builder()337 SkLayerDrawLooper::Builder::Builder()
338         : fRecs(nullptr),
339           fTopRec(nullptr),
340           fCount(0) {
341 }
342 
~Builder()343 SkLayerDrawLooper::Builder::~Builder() {
344     Rec* rec = fRecs;
345     while (rec) {
346         Rec* next = rec->fNext;
347         delete rec;
348         rec = next;
349     }
350 }
351 
addLayer(const LayerInfo & info)352 SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
353     fCount += 1;
354 
355     Rec* rec = new Rec;
356     rec->fNext = fRecs;
357     rec->fInfo = info;
358     fRecs = rec;
359     if (nullptr == fTopRec) {
360         fTopRec = rec;
361     }
362 
363     return &rec->fPaint;
364 }
365 
addLayer(SkScalar dx,SkScalar dy)366 void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
367     LayerInfo info;
368 
369     info.fOffset.set(dx, dy);
370     (void)this->addLayer(info);
371 }
372 
addLayerOnTop(const LayerInfo & info)373 SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
374     fCount += 1;
375 
376     Rec* rec = new Rec;
377     rec->fNext = nullptr;
378     rec->fInfo = info;
379     if (nullptr == fRecs) {
380         fRecs = rec;
381     } else {
382         SkASSERT(fTopRec);
383         fTopRec->fNext = rec;
384     }
385     fTopRec = rec;
386 
387     return &rec->fPaint;
388 }
389 
detach()390 sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
391     SkLayerDrawLooper* looper = new SkLayerDrawLooper;
392     looper->fCount = fCount;
393     looper->fRecs = fRecs;
394 
395     fCount = 0;
396     fRecs = nullptr;
397     fTopRec = nullptr;
398 
399     return sk_sp<SkDrawLooper>(looper);
400 }
401 
Make(SkColor color,SkScalar sigma,SkScalar dx,SkScalar dy)402 sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
403 {
404     sk_sp<SkMaskFilter> blur = nullptr;
405     if (sigma > 0.0f) {
406         blur = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, sigma, SkBlurMaskFilter::kNone_BlurFlag);
407     }
408 
409     SkLayerDrawLooper::Builder builder;
410 
411     // First layer
412     SkLayerDrawLooper::LayerInfo defaultLayer;
413     builder.addLayer(defaultLayer);
414 
415     // Blur layer
416     SkLayerDrawLooper::LayerInfo blurInfo;
417     blurInfo.fColorMode = SkBlendMode::kSrc;
418     blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
419     blurInfo.fOffset = SkVector::Make(dx, dy);
420     SkPaint* paint = builder.addLayer(blurInfo);
421     paint->setMaskFilter(std::move(blur));
422     paint->setColor(color);
423 
424     return builder.detach();
425 }
426