blob: 63a5639476c887cee2352d811a8389c527d91be4 [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 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "include/core/SkCanvas.h"
8#include "include/core/SkColor.h"
9#include "include/core/SkMaskFilter.h"
10#include "include/core/SkString.h"
11#include "include/core/SkUnPreMultiply.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040012#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkBlendModePriv.h"
14#include "src/core/SkColorSpacePriv.h"
15#include "src/core/SkMaskFilterBase.h"
16#include "src/core/SkReadBuffer.h"
17#include "src/core/SkStringUtils.h"
18#include "src/core/SkWriteBuffer.h"
19#include "src/core/SkXfermodePriv.h"
reed@google.com0716c632011-04-12 18:32:06 +000020
Mike Reed1d622212021-02-04 20:11:25 -050021#ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
22
23#include "include/effects/SkBlurDrawLooper.h"
24#include "include/effects/SkLayerDrawLooper.h"
25
reed@google.com0716c632011-04-12 18:32:06 +000026SkLayerDrawLooper::LayerInfo::LayerInfo() {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000027 fPaintBits = 0; // ignore our paint fields
Mike Reedfaba3712016-11-03 14:45:31 -040028 fColorMode = SkBlendMode::kDst; // ignore our color
reed@google.com0716c632011-04-12 18:32:06 +000029 fOffset.set(0, 0);
30 fPostTranslate = false;
31}
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
vandebo@chromium.org3c898182011-06-22 05:01:28 +000033SkLayerDrawLooper::SkLayerDrawLooper()
halcanary96fcdcc2015-08-27 07:41:13 -070034 : fRecs(nullptr),
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000035 fCount(0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036}
37
38SkLayerDrawLooper::~SkLayerDrawLooper() {
39 Rec* rec = fRecs;
40 while (rec) {
41 Rec* next = rec->fNext;
halcanary385fe4d2015-08-26 13:07:48 -070042 delete rec;
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 rec = next;
44 }
45}
reed@google.com0716c632011-04-12 18:32:06 +000046
Herb Derby73fe7b02017-02-08 15:12:19 -050047SkLayerDrawLooper::Context*
Mike Reed59f2e462019-07-25 14:33:59 -040048SkLayerDrawLooper::makeContext(SkArenaAlloc* alloc) const {
Herb Derby73fe7b02017-02-08 15:12:19 -050049 return alloc->make<LayerDrawLooperContext>(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +000050}
51
Brian Osman9d1c88d2018-09-04 15:16:03 -040052static SkColor4f xferColor(const SkColor4f& src, const SkColor4f& dst, SkBlendMode mode) {
reed@google.com0716c632011-04-12 18:32:06 +000053 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -040054 case SkBlendMode::kSrc:
reed@google.com0716c632011-04-12 18:32:06 +000055 return src;
Mike Reed7d954ad2016-10-28 15:42:34 -040056 case SkBlendMode::kDst:
reed@google.com0716c632011-04-12 18:32:06 +000057 return dst;
58 default: {
Brian Osmand25b7c12018-09-21 16:01:59 -040059 SkPMColor4f pmS = src.premul();
60 SkPMColor4f pmD = dst.premul();
Brian Osman9d1c88d2018-09-04 15:16:03 -040061 return SkBlendMode_Apply(mode, pmS, pmD).unpremul();
reed@google.com0716c632011-04-12 18:32:06 +000062 }
63 }
64}
65
Leon Scroggins III1ff07062020-07-27 14:52:19 -040066// Even with kEntirePaint_Bits, we always ensure that the base paint's
reed@google.com84260582011-11-21 16:42:10 +000067// text-encoding is respected, since that controls how we interpret the
68// text/length parameters of a draw[Pos]Text call.
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000069void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
70 SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
Brian Osman9d1c88d2018-09-04 15:16:03 -040071 SkColor4f srcColor = src.getColor4f();
Matt Sarett56ea77a2017-03-28 15:27:06 -040072#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
73 // The framework may respect the alpha value on the original paint.
74 // Match this legacy behavior.
Brian Osman9d1c88d2018-09-04 15:16:03 -040075 if (src.getAlpha() == 255) {
76 srcColor.fA = dst->getColor4f().fA;
Matt Sarett56ea77a2017-03-28 15:27:06 -040077 }
78#endif
Brian Osman9d1c88d2018-09-04 15:16:03 -040079 dst->setColor4f(xferColor(srcColor, dst->getColor4f(), (SkBlendMode)info.fColorMode),
80 sk_srgb_singleton());
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000081
82 BitFlags bits = info.fPaintBits;
reed@google.com0716c632011-04-12 18:32:06 +000083
mike@reedtribe.org3c1225b2011-04-09 18:54:08 +000084 if (0 == bits) {
85 return;
86 }
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000087 if (kEntirePaint_Bits == bits) {
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +000088 // we've already computed these, so save it from the assignment
Mike Reedf738d422019-01-16 17:12:15 -050089 bool aa = dst->isAntiAlias();
90 bool di = dst->isDither();
Brian Osman9d1c88d2018-09-04 15:16:03 -040091 SkColor4f c = dst->getColor4f();
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000092 *dst = src;
Mike Reedf738d422019-01-16 17:12:15 -050093 dst->setAntiAlias(aa);
94 dst->setDither(di);
Brian Osman9d1c88d2018-09-04 15:16:03 -040095 dst->setColor4f(c, sk_srgb_singleton());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000096 return;
97 }
98
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +000099 if (bits & kStyle_Bit) {
100 dst->setStyle(src.getStyle());
101 dst->setStrokeWidth(src.getStrokeWidth());
102 dst->setStrokeMiter(src.getStrokeMiter());
103 dst->setStrokeCap(src.getStrokeCap());
104 dst->setStrokeJoin(src.getStrokeJoin());
105 }
106
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000107 if (bits & kPathEffect_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500108 dst->setPathEffect(src.refPathEffect());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000109 }
110 if (bits & kMaskFilter_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500111 dst->setMaskFilter(src.refMaskFilter());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000112 }
113 if (bits & kShader_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500114 dst->setShader(src.refShader());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000115 }
116 if (bits & kColorFilter_Bit) {
Mike Reed693fdbd2017-01-12 10:13:40 -0500117 dst->setColorFilter(src.refColorFilter());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000118 }
119 if (bits & kXfermode_Bit) {
Mike Reedcce0b602021-07-08 15:19:02 -0400120 dst->setBlender(src.refBlender());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000121 }
122
reed@google.com84260582011-11-21 16:42:10 +0000123 // we don't override these
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000124#if 0
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000125 dst->setTypeface(src.getTypeface());
126 dst->setTextSize(src.getTextSize());
127 dst->setTextScaleX(src.getTextScaleX());
mike@reedtribe.org0e2810b2011-04-08 02:41:54 +0000128 dst->setRasterizer(src.getRasterizer());
129 dst->setLooper(src.getLooper());
130 dst->setTextEncoding(src.getTextEncoding());
131 dst->setHinting(src.getHinting());
132#endif
133}
134
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000135SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
136 const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
137
Mike Reed59f2e462019-07-25 14:33:59 -0400138bool SkLayerDrawLooper::LayerDrawLooperContext::next(Info* info, SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -0700139 if (nullptr == fCurrRec) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000140 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142
mike@reedtribe.orga8282ef2011-04-14 01:22:45 +0000143 ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
reed@google.com0716c632011-04-12 18:32:06 +0000144
Mike Reed59f2e462019-07-25 14:33:59 -0400145 if (info) {
146 info->fTranslate = fCurrRec->fInfo.fOffset;
147 info->fApplyPostCTM = fCurrRec->fInfo.fPostTranslate;
reed@google.com0716c632011-04-12 18:32:06 +0000148 }
mike@reedtribe.orge5d0def2011-04-08 00:53:48 +0000149 fCurrRec = fCurrRec->fNext;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000150 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151}
152
reed@google.comdaaafa62014-04-29 15:20:16 +0000153bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
154 if (fCount != 2) {
155 return false;
156 }
157 const Rec* rec = fRecs;
158
159 // bottom layer needs to be just blur(maskfilter)
160 if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
161 return false;
162 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400163 if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000164 return false;
165 }
166 const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700167 if (nullptr == mf) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000168 return false;
169 }
Mike Reed80747ef2018-01-23 15:29:32 -0500170 SkMaskFilterBase::BlurRec maskBlur;
171 if (!as_MFB(mf)->asABlur(&maskBlur)) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000172 return false;
173 }
174
175 rec = rec->fNext;
176 // top layer needs to be "plain"
177 if (rec->fInfo.fPaintBits) {
178 return false;
179 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400180 if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
reed@google.comdaaafa62014-04-29 15:20:16 +0000181 return false;
182 }
183 if (!rec->fInfo.fOffset.equals(0, 0)) {
184 return false;
185 }
186
187 if (bsRec) {
188 bsRec->fSigma = maskBlur.fSigma;
189 bsRec->fOffset = fRecs->fInfo.fOffset;
Brian Osman9d1c88d2018-09-04 15:16:03 -0400190 // TODO: Update BlurShadowRec to use SkColor4f?
reed@google.comdaaafa62014-04-29 15:20:16 +0000191 bsRec->fColor = fRecs->fPaint.getColor();
192 bsRec->fStyle = maskBlur.fStyle;
reed@google.comdaaafa62014-04-29 15:20:16 +0000193 }
194 return true;
195}
196
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197///////////////////////////////////////////////////////////////////////////////
198
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000199void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 buffer.writeInt(fCount);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000201
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 Rec* rec = fRecs;
203 for (int i = 0; i < fCount; i++) {
reed@google.com842292f2014-02-28 15:38:22 +0000204 // Legacy "flagsmask" field -- now ignored, remove when we bump version
205 buffer.writeInt(0);
206
reed@google.com0716c632011-04-12 18:32:06 +0000207 buffer.writeInt(rec->fInfo.fPaintBits);
Mike Reed7d954ad2016-10-28 15:42:34 -0400208 buffer.writeInt((int)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
reed60c9b582016-04-03 09:11:13 -0700216sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 int count = buffer.readInt();
218
Kevin Lubick493f89e2020-09-14 08:37:35 -0400219#if defined(SK_BUILD_FOR_FUZZER)
220 if (count > 100) {
221 count = 100;
222 }
223#endif
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000224 Builder builder;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 for (int i = 0; i < count; i++) {
reed@google.com0716c632011-04-12 18:32:06 +0000226 LayerInfo info;
reed@google.com842292f2014-02-28 15:38:22 +0000227 // Legacy "flagsmask" field -- now ignored, remove when we bump version
reed@google.com48f31bd2014-02-27 14:27:44 +0000228 (void)buffer.readInt();
reed@google.com842292f2014-02-28 15:38:22 +0000229
reed@google.com0716c632011-04-12 18:32:06 +0000230 info.fPaintBits = buffer.readInt();
Mike Reedfaba3712016-11-03 14:45:31 -0400231 info.fColorMode = (SkBlendMode)buffer.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000232 buffer.readPoint(&info.fOffset);
reed@google.com0716c632011-04-12 18:32:06 +0000233 info.fPostTranslate = buffer.readBool();
Mike Reed22cada02021-08-09 10:46:33 -0400234 *builder.addLayerOnTop(info) = buffer.readPaint();
Kevin Lubickdaebae92018-05-17 11:29:10 -0400235 if (!buffer.isValid()) {
236 return nullptr;
237 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 }
reed60c9b582016-04-03 09:11:13 -0700239 return builder.detach();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240}
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000241
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000242SkLayerDrawLooper::Builder::Builder()
halcanary96fcdcc2015-08-27 07:41:13 -0700243 : fRecs(nullptr),
244 fTopRec(nullptr),
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000245 fCount(0) {
246}
247
248SkLayerDrawLooper::Builder::~Builder() {
249 Rec* rec = fRecs;
250 while (rec) {
251 Rec* next = rec->fNext;
halcanary385fe4d2015-08-26 13:07:48 -0700252 delete rec;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000253 rec = next;
254 }
255}
256
257SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
258 fCount += 1;
259
halcanary385fe4d2015-08-26 13:07:48 -0700260 Rec* rec = new Rec;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000261 rec->fNext = fRecs;
262 rec->fInfo = info;
263 fRecs = rec;
halcanary96fcdcc2015-08-27 07:41:13 -0700264 if (nullptr == fTopRec) {
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000265 fTopRec = rec;
266 }
267
268 return &rec->fPaint;
269}
270
271void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
272 LayerInfo info;
273
274 info.fOffset.set(dx, dy);
275 (void)this->addLayer(info);
276}
277
278SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
279 fCount += 1;
280
halcanary385fe4d2015-08-26 13:07:48 -0700281 Rec* rec = new Rec;
halcanary96fcdcc2015-08-27 07:41:13 -0700282 rec->fNext = nullptr;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000283 rec->fInfo = info;
halcanary96fcdcc2015-08-27 07:41:13 -0700284 if (nullptr == fRecs) {
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000285 fRecs = rec;
286 } else {
bsalomon49f085d2014-09-05 13:34:00 -0700287 SkASSERT(fTopRec);
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000288 fTopRec->fNext = rec;
289 }
290 fTopRec = rec;
291
292 return &rec->fPaint;
293}
294
reed7b380d02016-03-21 13:25:16 -0700295sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
halcanary385fe4d2015-08-26 13:07:48 -0700296 SkLayerDrawLooper* looper = new SkLayerDrawLooper;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000297 looper->fCount = fCount;
298 looper->fRecs = fRecs;
299
300 fCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700301 fRecs = nullptr;
302 fTopRec = nullptr;
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000303
reed7b380d02016-03-21 13:25:16 -0700304 return sk_sp<SkDrawLooper>(looper);
commit-bot@chromium.org74ba2f62014-02-14 10:06:42 +0000305}
Matt Sarett56ea77a2017-03-28 15:27:06 -0400306
307sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
308{
Leon Scroggins IIIe5481612019-01-09 15:57:34 -0500309 return Make(SkColor4f::FromColor(color), sk_srgb_singleton(), sigma, dx, dy);
310}
311
312sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor4f color, SkColorSpace* cs,
313 SkScalar sigma, SkScalar dx, SkScalar dy)
314{
Matt Sarett56ea77a2017-03-28 15:27:06 -0400315 sk_sp<SkMaskFilter> blur = nullptr;
316 if (sigma > 0.0f) {
Mike Reed18e75562018-03-12 14:03:47 -0400317 blur = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, true);
Matt Sarett56ea77a2017-03-28 15:27:06 -0400318 }
319
320 SkLayerDrawLooper::Builder builder;
321
322 // First layer
323 SkLayerDrawLooper::LayerInfo defaultLayer;
324 builder.addLayer(defaultLayer);
325
326 // Blur layer
327 SkLayerDrawLooper::LayerInfo blurInfo;
328 blurInfo.fColorMode = SkBlendMode::kSrc;
329 blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
330 blurInfo.fOffset = SkVector::Make(dx, dy);
331 SkPaint* paint = builder.addLayer(blurInfo);
332 paint->setMaskFilter(std::move(blur));
Leon Scroggins IIIe5481612019-01-09 15:57:34 -0500333 paint->setColor4f(color, cs);
Matt Sarett56ea77a2017-03-28 15:27:06 -0400334
335 return builder.detach();
336}
Mike Reed1d622212021-02-04 20:11:25 -0500337
338#endif