blob: acfd3282759eab65c7eaab2c6deefb3951fa73c1 [file] [log] [blame]
reed@android.com845fdac2009-06-23 03:01:32 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com845fdac2009-06-23 03:01:32 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com845fdac2009-06-23 03:01:32 +00006 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00007
reed@android.comc4cae852009-09-23 15:06:10 +00008#include "SkBlitRow.h"
Mike Kleine902f8d2016-10-26 15:32:26 -04009#include "SkBlendModePriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkColorFilter.h"
11#include "SkColorPriv.h"
reeddb873d82015-03-01 19:53:47 -080012#include "SkModeColorFilter.h"
Mike Klein96b333a2016-10-12 11:05:05 -040013#include "SkRasterPipeline.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
15#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkUtils.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000017#include "SkString.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000018#include "SkValidationUtils.h"
reeddd9ffea2016-02-18 12:39:14 -080019#include "SkPM4f.h"
reed@google.com31b30442014-02-06 20:59:47 +000020
reedc7141eb2016-01-11 13:08:59 -080021//////////////////////////////////////////////////////////////////////////////////////////////////
22
23#ifndef SK_IGNORE_TO_STRING
24void SkModeColorFilter::toString(SkString* str) const {
25 str->append("SkModeColorFilter: color: 0x");
26 str->appendHex(fColor);
27 str->append(" mode: ");
28 str->append(SkXfermode::ModeName(fMode));
29}
30#endif
31
Mike Reed7d954ad2016-10-28 15:42:34 -040032bool SkModeColorFilter::asColorMode(SkColor* color, SK_XFERMODE_MODE_PARAM* mode) const {
reeddb873d82015-03-01 19:53:47 -080033 if (color) {
34 *color = fColor;
reed@google.com43c50c82011-04-14 15:50:52 +000035 }
reeddb873d82015-03-01 19:53:47 -080036 if (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -040037 *mode = (SK_XFERMODE_MODE_PARAM)fMode;
reed@google.com8b0d0f62012-06-04 18:10:33 +000038 }
reeddb873d82015-03-01 19:53:47 -080039 return true;
40}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000041
reeddb873d82015-03-01 19:53:47 -080042uint32_t SkModeColorFilter::getFlags() const {
reedc5b12282016-02-19 13:38:53 -080043 uint32_t flags = 0;
reed62a320c2015-03-24 06:35:23 -070044 switch (fMode) {
Mike Reed7d954ad2016-10-28 15:42:34 -040045 case SkBlendMode::kDst: //!< [Da, Dc]
46 case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc]
reed31255652016-02-08 12:56:56 -080047 flags |= kAlphaUnchanged_Flag;
reed62a320c2015-03-24 06:35:23 -070048 default:
49 break;
50 }
reed31255652016-02-08 12:56:56 -080051 return flags;
reeddb873d82015-03-01 19:53:47 -080052}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000053
reeddb873d82015-03-01 19:53:47 -080054void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
55 SkPMColor color = fPMColor;
56 SkXfermodeProc proc = fProc;
halcanary9d524f22016-03-29 09:03:52 -070057
reed31255652016-02-08 12:56:56 -080058 for (int i = 0; i < count; i++) {
59 result[i] = proc(color, shader[i]);
60 }
61}
mtklein95cc0122015-04-27 15:11:01 -070062
reed31255652016-02-08 12:56:56 -080063void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
Mike Reed7d954ad2016-10-28 15:42:34 -040064 SkXfermodeProc4f proc = SkXfermode::GetProc4f((SkXfermode::Mode)fMode);
halcanary9d524f22016-03-29 09:03:52 -070065
reeddb873d82015-03-01 19:53:47 -080066 for (int i = 0; i < count; i++) {
Mike Klein96b333a2016-10-12 11:05:05 -040067 result[i] = proc(fPM4f, shader[i]);
reed@google.com8b0d0f62012-06-04 18:10:33 +000068 }
reeddb873d82015-03-01 19:53:47 -080069}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000070
reeddb873d82015-03-01 19:53:47 -080071void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
72 buffer.writeColor(fColor);
Mike Reed7d954ad2016-10-28 15:42:34 -040073 buffer.writeUInt((int)fMode);
reeddb873d82015-03-01 19:53:47 -080074}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000075
reeddb873d82015-03-01 19:53:47 -080076void SkModeColorFilter::updateCache() {
77 fPMColor = SkPreMultiplyColor(fColor);
Mike Reed7d954ad2016-10-28 15:42:34 -040078 fProc = SkXfermode::GetProc((SkXfermode::Mode)fMode);
Matt Sarettdf3fbd62016-10-17 13:52:49 -040079 fPM4f = SkColor4f::FromColor(fColor).premul();
reeddb873d82015-03-01 19:53:47 -080080}
reed@android.com8a1c16f2008-12-17 15:59:43 +000081
reed60c9b582016-04-03 09:11:13 -070082sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070083 SkColor color = buffer.readColor();
Mike Reed7d954ad2016-10-28 15:42:34 -040084 SkBlendMode mode = (SkBlendMode)buffer.readUInt();
reed60c9b582016-04-03 09:11:13 -070085 return SkColorFilter::MakeModeFilter(color, mode);
reed9fa60da2014-08-21 07:59:51 -070086}
87
Mike Klein96b333a2016-10-12 11:05:05 -040088bool SkModeColorFilter::onAppendStages(SkRasterPipeline* p) const {
89 // TODO: For some modes we can cut a stage by loading the fPM4f into dr,dg,db,da
90 // and applying the opposite xfermode, e.g. dst-in instead of src-in.
91 p->append(SkRasterPipeline::swap_src_dst);
92 p->append(SkRasterPipeline::constant_color, &fPM4f);
Mike Klein130863e2016-10-27 11:29:36 -040093 auto mode = (SkBlendMode)fMode;
94 if (!SkBlendMode_AppendStages(mode, p)) {
95 return false;
96 }
97 if (SkBlendMode_CanOverflow(mode)) { p->append(SkRasterPipeline::clamp_1); }
98 return true;
Mike Klein96b333a2016-10-12 11:05:05 -040099}
100
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000101///////////////////////////////////////////////////////////////////////////////
102#if SK_SUPPORT_GPU
103#include "GrBlend.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800104#include "GrInvariantOutput.h"
bsalomonae4738f2015-09-15 15:33:27 -0700105#include "effects/GrXfermodeFragmentProcessor.h"
106#include "effects/GrConstColorProcessor.h"
joshualitteb2a6762014-12-04 11:35:33 -0800107#include "SkGr.h"
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000108
Brian Osman618d3042016-10-25 10:51:28 -0400109sk_sp<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
110 GrContext*, SkColorSpace* dstColorSpace) const {
Mike Reed7d954ad2016-10-28 15:42:34 -0400111 if (SkBlendMode::kDst == fMode) {
bsalomone25eea42015-09-29 06:38:55 -0700112 return nullptr;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000113 }
bsalomone25eea42015-09-29 06:38:55 -0700114
bungeman06ca8ec2016-06-09 08:01:03 -0700115 sk_sp<GrFragmentProcessor> constFP(
Brian Osman618d3042016-10-25 10:51:28 -0400116 GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace),
bungeman06ca8ec2016-06-09 08:01:03 -0700117 GrConstColorProcessor::kIgnore_InputMode));
118 sk_sp<GrFragmentProcessor> fp(
119 GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode));
bsalomone25eea42015-09-29 06:38:55 -0700120 if (!fp) {
121 return nullptr;
122 }
123#ifdef SK_DEBUG
124 // With a solid color input this should always be able to compute the blended color
125 // (at least for coeff modes)
Mike Reed7d954ad2016-10-28 15:42:34 -0400126 if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
bsalomone25eea42015-09-29 06:38:55 -0700127 static SkRandom gRand;
128 GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags,
129 false);
130 fp->computeInvariantOutput(&io);
131 SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags);
132 }
133#endif
134 return fp;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000135}
136
137#endif
138
139///////////////////////////////////////////////////////////////////////////////
140
reedc7141eb2016-01-11 13:08:59 -0800141class Src_SkModeColorFilter final : public SkModeColorFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142public:
Mike Reed7d954ad2016-10-28 15:42:34 -0400143 Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrc) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144
mtklein36352bf2015-03-25 18:17:31 -0700145 void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
reed@google.com8b0d0f62012-06-04 18:10:33 +0000146 sk_memset32(result, this->getPMColor(), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 }
148
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000149private:
reed@google.com43c50c82011-04-14 15:50:52 +0000150 typedef SkModeColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151};
152
reedc7141eb2016-01-11 13:08:59 -0800153class SrcOver_SkModeColorFilter final : public SkModeColorFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154public:
Mike Reed7d954ad2016-10-28 15:42:34 -0400155 SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrcOver) { }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156
mtklein36352bf2015-03-25 18:17:31 -0700157 void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
mtklein95cc0122015-04-27 15:11:01 -0700158 SkBlitRow::Color32(result, shader, count, this->getPMColor());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 }
160
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000161private:
reed@google.com43c50c82011-04-14 15:50:52 +0000162 typedef SkModeColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163};
164
reed@google.com43c50c82011-04-14 15:50:52 +0000165///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166
Mike Reed7d954ad2016-10-28 15:42:34 -0400167sk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) {
reed9fa60da2014-08-21 07:59:51 -0700168 if (!SkIsValidMode(mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700169 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700170 }
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 unsigned alpha = SkColorGetA(color);
173
174 // first collaps some modes if possible
175
Mike Reed7d954ad2016-10-28 15:42:34 -0400176 if (SkBlendMode::kClear == mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 color = 0;
Mike Reed7d954ad2016-10-28 15:42:34 -0400178 mode = SkBlendMode::kSrc;
179 } else if (SkBlendMode::kSrcOver == mode) {
reed@android.com845fdac2009-06-23 03:01:32 +0000180 if (0 == alpha) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400181 mode = SkBlendMode::kDst;
reed@android.com845fdac2009-06-23 03:01:32 +0000182 } else if (255 == alpha) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400183 mode = SkBlendMode::kSrc;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 }
185 // else just stay srcover
186 }
187
188 // weed out combinations that are noops, and just return null
Mike Reed7d954ad2016-10-28 15:42:34 -0400189 if (SkBlendMode::kDst == mode ||
190 (0 == alpha && (SkBlendMode::kSrcOver == mode ||
191 SkBlendMode::kDstOver == mode ||
192 SkBlendMode::kDstOut == mode ||
193 SkBlendMode::kSrcATop == mode ||
194 SkBlendMode::kXor == mode ||
195 SkBlendMode::kDarken == mode)) ||
196 (0xFF == alpha && SkBlendMode::kDstIn == mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700197 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000199
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400201 case SkBlendMode::kSrc:
reedd053ce92016-03-22 10:17:23 -0700202 return sk_make_sp<Src_SkModeColorFilter>(color);
Mike Reed7d954ad2016-10-28 15:42:34 -0400203 case SkBlendMode::kSrcOver:
reedd053ce92016-03-22 10:17:23 -0700204 return sk_make_sp<SrcOver_SkModeColorFilter>(color);
reed@google.com43c50c82011-04-14 15:50:52 +0000205 default:
reedd053ce92016-03-22 10:17:23 -0700206 return SkModeColorFilter::Make(color, mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 }
208}