blob: 58127d3ba7a5ab44a00c03e274139b0629fd9f04 [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"
Herb Derbyac04fef2017-01-13 17:34:33 -050012#include "SkArenaAlloc.h"
reeddb873d82015-03-01 19:53:47 -080013#include "SkModeColorFilter.h"
Mike Klein744908e2016-11-11 12:51:36 -050014#include "SkPM4fPriv.h"
Mike Klein96b333a2016-10-12 11:05:05 -040015#include "SkRasterPipeline.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000016#include "SkReadBuffer.h"
17#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#include "SkUtils.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000019#include "SkString.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000020#include "SkValidationUtils.h"
reeddd9ffea2016-02-18 12:39:14 -080021#include "SkPM4f.h"
reed@google.com31b30442014-02-06 20:59:47 +000022
reedc7141eb2016-01-11 13:08:59 -080023//////////////////////////////////////////////////////////////////////////////////////////////////
24
25#ifndef SK_IGNORE_TO_STRING
26void SkModeColorFilter::toString(SkString* str) const {
27 str->append("SkModeColorFilter: color: 0x");
28 str->appendHex(fColor);
29 str->append(" mode: ");
30 str->append(SkXfermode::ModeName(fMode));
31}
32#endif
33
Mike Reedfaba3712016-11-03 14:45:31 -040034bool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
reeddb873d82015-03-01 19:53:47 -080035 if (color) {
36 *color = fColor;
reed@google.com43c50c82011-04-14 15:50:52 +000037 }
reeddb873d82015-03-01 19:53:47 -080038 if (mode) {
Mike Reedfaba3712016-11-03 14:45:31 -040039 *mode = fMode;
reed@google.com8b0d0f62012-06-04 18:10:33 +000040 }
reeddb873d82015-03-01 19:53:47 -080041 return true;
42}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000043
reeddb873d82015-03-01 19:53:47 -080044uint32_t SkModeColorFilter::getFlags() const {
reedc5b12282016-02-19 13:38:53 -080045 uint32_t flags = 0;
reed62a320c2015-03-24 06:35:23 -070046 switch (fMode) {
Mike Reed7d954ad2016-10-28 15:42:34 -040047 case SkBlendMode::kDst: //!< [Da, Dc]
48 case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc]
reed31255652016-02-08 12:56:56 -080049 flags |= kAlphaUnchanged_Flag;
reed62a320c2015-03-24 06:35:23 -070050 default:
51 break;
52 }
reed31255652016-02-08 12:56:56 -080053 return flags;
reeddb873d82015-03-01 19:53:47 -080054}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000055
reeddb873d82015-03-01 19:53:47 -080056void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
57 SkPMColor color = fPMColor;
58 SkXfermodeProc proc = fProc;
halcanary9d524f22016-03-29 09:03:52 -070059
reed31255652016-02-08 12:56:56 -080060 for (int i = 0; i < count; i++) {
61 result[i] = proc(color, shader[i]);
62 }
63}
mtklein95cc0122015-04-27 15:11:01 -070064
reed31255652016-02-08 12:56:56 -080065void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
Mike Reed6a015542016-11-09 10:38:09 -050066 SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode);
Mike Klein744908e2016-11-11 12:51:36 -050067 auto pm4f = SkColor4f::FromColor(fColor).premul();
reeddb873d82015-03-01 19:53:47 -080068 for (int i = 0; i < count; i++) {
Mike Klein744908e2016-11-11 12:51:36 -050069 result[i] = proc(pm4f, shader[i]);
reed@google.com8b0d0f62012-06-04 18:10:33 +000070 }
reeddb873d82015-03-01 19:53:47 -080071}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000072
reeddb873d82015-03-01 19:53:47 -080073void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
74 buffer.writeColor(fColor);
Mike Reed7d954ad2016-10-28 15:42:34 -040075 buffer.writeUInt((int)fMode);
reeddb873d82015-03-01 19:53:47 -080076}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000077
reeddb873d82015-03-01 19:53:47 -080078void SkModeColorFilter::updateCache() {
79 fPMColor = SkPreMultiplyColor(fColor);
Mike Reed6a015542016-11-09 10:38:09 -050080 fProc = SkXfermode::GetProc(fMode);
reeddb873d82015-03-01 19:53:47 -080081}
reed@android.com8a1c16f2008-12-17 15:59:43 +000082
reed60c9b582016-04-03 09:11:13 -070083sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070084 SkColor color = buffer.readColor();
Mike Reed7d954ad2016-10-28 15:42:34 -040085 SkBlendMode mode = (SkBlendMode)buffer.readUInt();
reed60c9b582016-04-03 09:11:13 -070086 return SkColorFilter::MakeModeFilter(color, mode);
reed9fa60da2014-08-21 07:59:51 -070087}
88
Mike Klein744908e2016-11-11 12:51:36 -050089bool SkModeColorFilter::onAppendStages(SkRasterPipeline* p,
90 SkColorSpace* dst,
Herb Derbyac04fef2017-01-13 17:34:33 -050091 SkArenaAlloc* scratch,
Mike Klein744908e2016-11-11 12:51:36 -050092 bool shaderIsOpaque) const {
Mike Klein526525a2016-11-15 17:58:33 +000093 auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
Mike Klein744908e2016-11-11 12:51:36 -050094
Mike Kleinc5093412016-11-04 16:36:39 -040095 p->append(SkRasterPipeline::move_src_dst);
Mike Klein744908e2016-11-11 12:51:36 -050096 p->append(SkRasterPipeline::constant_color, color);
Mike Klein130863e2016-10-27 11:29:36 -040097 auto mode = (SkBlendMode)fMode;
98 if (!SkBlendMode_AppendStages(mode, p)) {
99 return false;
100 }
Mike Kleineea7c162016-11-03 10:20:35 -0400101 if (SkBlendMode_CanOverflow(mode)) { p->append(SkRasterPipeline::clamp_a); }
Mike Klein130863e2016-10-27 11:29:36 -0400102 return true;
Mike Klein96b333a2016-10-12 11:05:05 -0400103}
104
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000105///////////////////////////////////////////////////////////////////////////////
106#if SK_SUPPORT_GPU
107#include "GrBlend.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800108#include "GrInvariantOutput.h"
bsalomonae4738f2015-09-15 15:33:27 -0700109#include "effects/GrXfermodeFragmentProcessor.h"
110#include "effects/GrConstColorProcessor.h"
joshualitteb2a6762014-12-04 11:35:33 -0800111#include "SkGr.h"
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000112
Brian Osman618d3042016-10-25 10:51:28 -0400113sk_sp<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
114 GrContext*, SkColorSpace* dstColorSpace) const {
Mike Reed7d954ad2016-10-28 15:42:34 -0400115 if (SkBlendMode::kDst == fMode) {
bsalomone25eea42015-09-29 06:38:55 -0700116 return nullptr;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000117 }
bsalomone25eea42015-09-29 06:38:55 -0700118
bungeman06ca8ec2016-06-09 08:01:03 -0700119 sk_sp<GrFragmentProcessor> constFP(
Brian Osman618d3042016-10-25 10:51:28 -0400120 GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace),
bungeman06ca8ec2016-06-09 08:01:03 -0700121 GrConstColorProcessor::kIgnore_InputMode));
122 sk_sp<GrFragmentProcessor> fp(
123 GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode));
bsalomone25eea42015-09-29 06:38:55 -0700124 if (!fp) {
125 return nullptr;
126 }
127#ifdef SK_DEBUG
128 // With a solid color input this should always be able to compute the blended color
129 // (at least for coeff modes)
Mike Reed7d954ad2016-10-28 15:42:34 -0400130 if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
bsalomone25eea42015-09-29 06:38:55 -0700131 static SkRandom gRand;
Brian Salomonaab259e2017-01-17 10:44:34 -0500132 GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags);
bsalomone25eea42015-09-29 06:38:55 -0700133 fp->computeInvariantOutput(&io);
134 SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags);
135 }
136#endif
137 return fp;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000138}
139
140#endif
141
142///////////////////////////////////////////////////////////////////////////////
143
reedc7141eb2016-01-11 13:08:59 -0800144class Src_SkModeColorFilter final : public SkModeColorFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145public:
Mike Reed7d954ad2016-10-28 15:42:34 -0400146 Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrc) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147
mtklein36352bf2015-03-25 18:17:31 -0700148 void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
reed@google.com8b0d0f62012-06-04 18:10:33 +0000149 sk_memset32(result, this->getPMColor(), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 }
151
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000152private:
reed@google.com43c50c82011-04-14 15:50:52 +0000153 typedef SkModeColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154};
155
reedc7141eb2016-01-11 13:08:59 -0800156class SrcOver_SkModeColorFilter final : public SkModeColorFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157public:
Mike Reed7d954ad2016-10-28 15:42:34 -0400158 SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrcOver) { }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159
mtklein36352bf2015-03-25 18:17:31 -0700160 void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
mtklein95cc0122015-04-27 15:11:01 -0700161 SkBlitRow::Color32(result, shader, count, this->getPMColor());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 }
163
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000164private:
reed@google.com43c50c82011-04-14 15:50:52 +0000165 typedef SkModeColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166};
167
reed@google.com43c50c82011-04-14 15:50:52 +0000168///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
Mike Reed7d954ad2016-10-28 15:42:34 -0400170sk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) {
reed9fa60da2014-08-21 07:59:51 -0700171 if (!SkIsValidMode(mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700172 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700173 }
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 unsigned alpha = SkColorGetA(color);
176
177 // first collaps some modes if possible
178
Mike Reed7d954ad2016-10-28 15:42:34 -0400179 if (SkBlendMode::kClear == mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 color = 0;
Mike Reed7d954ad2016-10-28 15:42:34 -0400181 mode = SkBlendMode::kSrc;
182 } else if (SkBlendMode::kSrcOver == mode) {
reed@android.com845fdac2009-06-23 03:01:32 +0000183 if (0 == alpha) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400184 mode = SkBlendMode::kDst;
reed@android.com845fdac2009-06-23 03:01:32 +0000185 } else if (255 == alpha) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400186 mode = SkBlendMode::kSrc;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 }
188 // else just stay srcover
189 }
190
191 // weed out combinations that are noops, and just return null
Mike Reed7d954ad2016-10-28 15:42:34 -0400192 if (SkBlendMode::kDst == mode ||
193 (0 == alpha && (SkBlendMode::kSrcOver == mode ||
194 SkBlendMode::kDstOver == mode ||
195 SkBlendMode::kDstOut == mode ||
196 SkBlendMode::kSrcATop == mode ||
197 SkBlendMode::kXor == mode ||
198 SkBlendMode::kDarken == mode)) ||
199 (0xFF == alpha && SkBlendMode::kDstIn == mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700200 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400204 case SkBlendMode::kSrc:
reedd053ce92016-03-22 10:17:23 -0700205 return sk_make_sp<Src_SkModeColorFilter>(color);
Mike Reed7d954ad2016-10-28 15:42:34 -0400206 case SkBlendMode::kSrcOver:
reedd053ce92016-03-22 10:17:23 -0700207 return sk_make_sp<SrcOver_SkModeColorFilter>(color);
reed@google.com43c50c82011-04-14 15:50:52 +0000208 default:
reedd053ce92016-03-22 10:17:23 -0700209 return SkModeColorFilter::Make(color, mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 }
211}