blob: cd3f51bac326d367bbd02b6a2a1aa76b162c78ed [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
Herb Derby73fe7b02017-02-08 15:12:19 -05007#include "SkArenaAlloc.h"
Brian Osman9d1c88d2018-09-04 15:16:03 -04008#include "SkBlendModePriv.h"
Matt Sarett56ea77a2017-03-28 15:27:06 -04009#include "SkBlurDrawLooper.h"
Brian Osman9d1c88d2018-09-04 15:16:03 -040010#include "SkColorSpacePriv.h"
Mike Reed18e75562018-03-12 14:03:47 -040011#include "SkMaskFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkCanvas.h"
reed@google.com0716c632011-04-12 18:32:06 +000013#include "SkColor.h"
Mike Reed80747ef2018-01-23 15:29:32 -050014#include "SkMaskFilterBase.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000015#include "SkReadBuffer.h"
16#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkLayerDrawLooper.h"
robertphillips@google.com4991b8f2013-01-28 20:21:59 +000018#include "SkString.h"
19#include "SkStringUtils.h"
reed@google.com0716c632011-04-12 18:32:06 +000020#include "SkUnPreMultiply.h"
Mike Reed8d3f4432017-06-10 11:08:53 -040021#include "SkXfermodePriv.h"
reed@google.com0716c632011-04-12 18:32:06 +000022
23SkLayerDrawLooper::LayerInfo::LayerInfo() {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000024 fPaintBits = 0; // ignore our paint fields
Mike Reedfaba3712016-11-03 14:45:31 -040025 fColorMode = SkBlendMode::kDst; // ignore our color
reed@google.com0716c632011-04-12 18:32:06 +000026 fOffset.set(0, 0);
27 fPostTranslate = false;
28}
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
vandebo@chromium.org3c898182011-06-22 05:01:28 +000030SkLayerDrawLooper::SkLayerDrawLooper()
halcanary96fcdcc2015-08-27 07:41:13 -070031 : fRecs(nullptr),
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000032 fCount(0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
35SkLayerDrawLooper::~SkLayerDrawLooper() {
36 Rec* rec = fRecs;
37 while (rec) {
38 Rec* next = rec->fNext;
halcanary385fe4d2015-08-26 13:07:48 -070039 delete rec;
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 rec = next;
41 }
42}
reed@google.com0716c632011-04-12 18:32:06 +000043
Herb Derby73fe7b02017-02-08 15:12:19 -050044SkLayerDrawLooper::Context*
45SkLayerDrawLooper::makeContext(SkCanvas* canvas, SkArenaAlloc* alloc) const {
commit-bot@chromium.org091a5942014-04-18 14:19:31 +000046 canvas->save();
Herb Derby73fe7b02017-02-08 15:12:19 -050047 return alloc->make<LayerDrawLooperContext>(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +000048}
49
Brian Osman9d1c88d2018-09-04 15:16:03 -040050static SkColor4f xferColor(const SkColor4f& src, const SkColor4f& dst, SkBlendMode mode) {
reed@google.com0716c632011-04-12 18:32:06 +000051 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -040052 case SkBlendMode::kSrc:
reed@google.com0716c632011-04-12 18:32:06 +000053 return src;
Mike Reed7d954ad2016-10-28 15:42:34 -040054 case SkBlendMode::kDst:
reed@google.com0716c632011-04-12 18:32:06 +000055 return dst;
56 default: {
Brian Osmand25b7c12018-09-21 16:01:59 -040057 SkPMColor4f pmS = src.premul();
58 SkPMColor4f pmD = dst.premul();
Brian Osman9d1c88d2018-09-04 15:16:03 -040059 return SkBlendMode_Apply(mode, pmS, pmD).unpremul();
reed@google.com0716c632011-04-12 18:32:06 +000060 }
61 }
62}
63
reed@google.com84260582011-11-21 16:42:10 +000064// Even with kEntirePaint_Bits, we always ensure that the master paint's
65// text-encoding is respected, since that controls how we interpret the
66// text/length parameters of a draw[Pos]Text call.
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000067void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
68 SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
Brian Osman9d1c88d2018-09-04 15:16:03 -040069 SkColor4f srcColor = src.getColor4f();
Matt Sarett56ea77a2017-03-28 15:27:06 -040070#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
71 // The framework may respect the alpha value on the original paint.
72 // Match this legacy behavior.
Brian Osman9d1c88d2018-09-04 15:16:03 -040073 if (src.getAlpha() == 255) {
74 srcColor.fA = dst->getColor4f().fA;
Matt Sarett56ea77a2017-03-28 15:27:06 -040075 }
76#endif
Brian Osman9d1c88d2018-09-04 15:16:03 -040077 dst->setColor4f(xferColor(srcColor, dst->getColor4f(), (SkBlendMode)info.fColorMode),
78 sk_srgb_singleton());
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000079
80 BitFlags bits = info.fPaintBits;
reed@google.com0716c632011-04-12 18:32:06 +000081
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000082 if (0 == bits) {
83 return;
84 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000085 if (kEntirePaint_Bits == bits) {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000086 // we've already computed these, so save it from the assignment
Mike Reedf738d422019-01-16 17:12:15 -050087 bool aa = dst->isAntiAlias();
88 bool di = dst->isDither();
Brian Osman9d1c88d2018-09-04 15:16:03 -040089 SkColor4f c = dst->getColor4f();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000090 *dst = src;
Mike Reedf738d422019-01-16 17:12:15 -050091 dst->setAntiAlias(aa);
92 dst->setDither(di);
Brian Osman9d1c88d2018-09-04 15:16:03 -040093 dst->setColor4f(c, sk_srgb_singleton());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000094 return;
95 }
96
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000097 if (bits & kStyle_Bit) {
98 dst->setStyle(src.getStyle());
99 dst->setStrokeWidth(src.getStrokeWidth());
100 dst->setStrokeMiter(src.getStrokeMiter());
101 dst->setStrokeCap(src.getStrokeCap());
102 dst->setStrokeJoin(src.getStrokeJoin());
103 }
104
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000105 if (bits & kPathEffect_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500106 dst->setPathEffect(src.refPathEffect());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000107 }
108 if (bits & kMaskFilter_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500109 dst->setMaskFilter(src.refMaskFilter());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000110 }
111 if (bits & kShader_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500112 dst->setShader(src.refShader());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000113 }
114 if (bits & kColorFilter_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500115 dst->setColorFilter(src.refColorFilter());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000116 }
117 if (bits & kXfermode_Bit) {
reed374772b2016-10-05 17:33:02 -0700118 dst->setBlendMode(src.getBlendMode());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000119 }
120
reed@google.com84260582011-11-21 16:42:10 +0000121 // we don't override these
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000122#if 0
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000123 dst->setTypeface(src.getTypeface());
124 dst->setTextSize(src.getTextSize());
125 dst->setTextScaleX(src.getTextScaleX());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000126 dst->setRasterizer(src.getRasterizer());
127 dst->setLooper(src.getLooper());
128 dst->setTextEncoding(src.getTextEncoding());
129 dst->setHinting(src.getHinting());
130#endif
131}
132
reed@google.com0716c632011-04-12 18:32:06 +0000133// Should we add this to canvas?
134static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
135 SkMatrix m = canvas->getTotalMatrix();
136 m.postTranslate(dx, dy);
137 canvas->setMatrix(m);
138}
139
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000140SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
141 const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
142
143bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas,
144 SkPaint* paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000145 canvas->restore();
halcanary96fcdcc2015-08-27 07:41:13 -0700146 if (nullptr == fCurrRec) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000147 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000150 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
reed@google.com0716c632011-04-12 18:32:06 +0000151
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000152 canvas->save();
reed@google.com0716c632011-04-12 18:32:06 +0000153 if (fCurrRec->fInfo.fPostTranslate) {
154 postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
155 fCurrRec->fInfo.fOffset.fY);
156 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000157 canvas->translate(fCurrRec->fInfo.fOffset.fX,
158 fCurrRec->fInfo.fOffset.fY);
reed@google.com0716c632011-04-12 18:32:06 +0000159 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000160 fCurrRec = fCurrRec->fNext;
161
reed@google.com4e2b3d32011-04-07 14:18:59 +0000162 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163}
164
reed@google.comdaaafa62014-04-29 15:20:16 +0000165bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
166 if (fCount != 2) {
167 return false;
168 }
169 const Rec* rec = fRecs;
170
171 // bottom layer needs to be just blur(maskfilter)
172 if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
173 return false;
174 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400175 if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000176 return false;
177 }
178 const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700179 if (nullptr == mf) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000180 return false;
181 }
Mike Reed80747ef2018-01-23 15:29:32 -0500182 SkMaskFilterBase::BlurRec maskBlur;
183 if (!as_MFB(mf)->asABlur(&maskBlur)) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000184 return false;
185 }
186
187 rec = rec->fNext;
188 // top layer needs to be "plain"
189 if (rec->fInfo.fPaintBits) {
190 return false;
191 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400192 if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000193 return false;
194 }
195 if (!rec->fInfo.fOffset.equals(0, 0)) {
196 return false;
197 }
198
199 if (bsRec) {
200 bsRec->fSigma = maskBlur.fSigma;
201 bsRec->fOffset = fRecs->fInfo.fOffset;
Brian Osman9d1c88d2018-09-04 15:16:03 -0400202 // TODO: Update BlurShadowRec to use SkColor4f?
reed@google.comdaaafa62014-04-29 15:20:16 +0000203 bsRec->fColor = fRecs->fPaint.getColor();
204 bsRec->fStyle = maskBlur.fStyle;
reed@google.comdaaafa62014-04-29 15:20:16 +0000205 }
206 return true;
207}
208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209///////////////////////////////////////////////////////////////////////////////
210
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000211void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 buffer.writeInt(fCount);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000213
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 Rec* rec = fRecs;
215 for (int i = 0; i < fCount; i++) {
reed@google.com842292f2014-02-28 15:38:22 +0000216 // Legacy "flagsmask" field -- now ignored, remove when we bump version
217 buffer.writeInt(0);
218
reed@google.com0716c632011-04-12 18:32:06 +0000219 buffer.writeInt(rec->fInfo.fPaintBits);
Mike Reed7d954ad2016-10-28 15:42:34 -0400220 buffer.writeInt((int)rec->fInfo.fColorMode);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000221 buffer.writePoint(rec->fInfo.fOffset);
reed@google.com0716c632011-04-12 18:32:06 +0000222 buffer.writeBool(rec->fInfo.fPostTranslate);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000223 buffer.writePaint(rec->fPaint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 rec = rec->fNext;
225 }
226}
227
reed60c9b582016-04-03 09:11:13 -0700228sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 int count = buffer.readInt();
230
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000231 Builder builder;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 for (int i = 0; i < count; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000233 LayerInfo info;
reed@google.com842292f2014-02-28 15:38:22 +0000234 // Legacy "flagsmask" field -- now ignored, remove when we bump version
reed@google.com48f31bd2014-02-27 14:27:44 +0000235 (void)buffer.readInt();
reed@google.com842292f2014-02-28 15:38:22 +0000236
reed@google.com0716c632011-04-12 18:32:06 +0000237 info.fPaintBits = buffer.readInt();
Mike Reedfaba3712016-11-03 14:45:31 -0400238 info.fColorMode = (SkBlendMode)buffer.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000239 buffer.readPoint(&info.fOffset);
reed@google.com0716c632011-04-12 18:32:06 +0000240 info.fPostTranslate = buffer.readBool();
Mike Reed31ba6fe2019-01-14 17:36:54 -0500241 buffer.readPaint(builder.addLayerOnTop(info), nullptr);
Kevin Lubickdaebae92018-05-17 11:29:10 -0400242 if (!buffer.isValid()) {
243 return nullptr;
244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 }
reed60c9b582016-04-03 09:11:13 -0700246 return builder.detach();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247}
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000248
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000249SkLayerDrawLooper::Builder::Builder()
halcanary96fcdcc2015-08-27 07:41:13 -0700250 : fRecs(nullptr),
251 fTopRec(nullptr),
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000252 fCount(0) {
253}
254
255SkLayerDrawLooper::Builder::~Builder() {
256 Rec* rec = fRecs;
257 while (rec) {
258 Rec* next = rec->fNext;
halcanary385fe4d2015-08-26 13:07:48 -0700259 delete rec;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000260 rec = next;
261 }
262}
263
264SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
265 fCount += 1;
266
halcanary385fe4d2015-08-26 13:07:48 -0700267 Rec* rec = new Rec;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000268 rec->fNext = fRecs;
269 rec->fInfo = info;
270 fRecs = rec;
halcanary96fcdcc2015-08-27 07:41:13 -0700271 if (nullptr == fTopRec) {
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000272 fTopRec = rec;
273 }
274
275 return &rec->fPaint;
276}
277
278void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
279 LayerInfo info;
280
281 info.fOffset.set(dx, dy);
282 (void)this->addLayer(info);
283}
284
285SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
286 fCount += 1;
287
halcanary385fe4d2015-08-26 13:07:48 -0700288 Rec* rec = new Rec;
halcanary96fcdcc2015-08-27 07:41:13 -0700289 rec->fNext = nullptr;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000290 rec->fInfo = info;
halcanary96fcdcc2015-08-27 07:41:13 -0700291 if (nullptr == fRecs) {
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000292 fRecs = rec;
293 } else {
bsalomon49f085d2014-09-05 13:34:00 -0700294 SkASSERT(fTopRec);
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000295 fTopRec->fNext = rec;
296 }
297 fTopRec = rec;
298
299 return &rec->fPaint;
300}
301
reed7b380d02016-03-21 13:25:16 -0700302sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
halcanary385fe4d2015-08-26 13:07:48 -0700303 SkLayerDrawLooper* looper = new SkLayerDrawLooper;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000304 looper->fCount = fCount;
305 looper->fRecs = fRecs;
306
307 fCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700308 fRecs = nullptr;
309 fTopRec = nullptr;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000310
reed7b380d02016-03-21 13:25:16 -0700311 return sk_sp<SkDrawLooper>(looper);
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000312}
Matt Sarett56ea77a2017-03-28 15:27:06 -0400313
314sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
315{
Leon Scroggins IIIe5481612019-01-09 15:57:34 -0500316 return Make(SkColor4f::FromColor(color), sk_srgb_singleton(), sigma, dx, dy);
317}
318
319sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor4f color, SkColorSpace* cs,
320 SkScalar sigma, SkScalar dx, SkScalar dy)
321{
Matt Sarett56ea77a2017-03-28 15:27:06 -0400322 sk_sp<SkMaskFilter> blur = nullptr;
323 if (sigma > 0.0f) {
Mike Reed18e75562018-03-12 14:03:47 -0400324 blur = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, true);
Matt Sarett56ea77a2017-03-28 15:27:06 -0400325 }
326
327 SkLayerDrawLooper::Builder builder;
328
329 // First layer
330 SkLayerDrawLooper::LayerInfo defaultLayer;
331 builder.addLayer(defaultLayer);
332
333 // Blur layer
334 SkLayerDrawLooper::LayerInfo blurInfo;
335 blurInfo.fColorMode = SkBlendMode::kSrc;
336 blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
337 blurInfo.fOffset = SkVector::Make(dx, dy);
338 SkPaint* paint = builder.addLayer(blurInfo);
339 paint->setMaskFilter(std::move(blur));
Leon Scroggins IIIe5481612019-01-09 15:57:34 -0500340 paint->setColor4f(color, cs);
Matt Sarett56ea77a2017-03-28 15:27:06 -0400341
342 return builder.detach();
343}