1/* 2 * Copyright 2013 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 8#include "SkArithmeticMode.h" 9#include "SkColorPriv.h" 10#include "SkReadBuffer.h" 11#include "SkWriteBuffer.h" 12#include "SkString.h" 13#include "SkUnPreMultiply.h" 14#if SK_SUPPORT_GPU 15#include "SkArithmeticMode_gpu.h" 16#endif 17 18class SkArithmeticMode_scalar : public SkXfermode { 19public: 20 SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 21 bool enforcePMColor) { 22 fK[0] = k1; 23 fK[1] = k2; 24 fK[2] = k3; 25 fK[3] = k4; 26 fEnforcePMColor = enforcePMColor; 27 } 28 29 void xfer32(SkPMColor[], const SkPMColor[], int count, const SkAlpha[]) const override; 30 31 SK_TO_STRING_OVERRIDE() 32 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) 33 34#if SK_SUPPORT_GPU 35 const GrFragmentProcessor* getFragmentProcessorForImageFilter( 36 const GrFragmentProcessor* dst) const override; 37 GrXPFactory* asXPFactory() const override; 38#endif 39 40private: 41 void flatten(SkWriteBuffer& buffer) const override { 42 buffer.writeScalar(fK[0]); 43 buffer.writeScalar(fK[1]); 44 buffer.writeScalar(fK[2]); 45 buffer.writeScalar(fK[3]); 46 buffer.writeBool(fEnforcePMColor); 47 } 48 49 SkScalar fK[4]; 50 bool fEnforcePMColor; 51 52 friend class SkArithmeticMode; 53 54 typedef SkXfermode INHERITED; 55}; 56 57SkFlattenable* SkArithmeticMode_scalar::CreateProc(SkReadBuffer& buffer) { 58 const SkScalar k1 = buffer.readScalar(); 59 const SkScalar k2 = buffer.readScalar(); 60 const SkScalar k3 = buffer.readScalar(); 61 const SkScalar k4 = buffer.readScalar(); 62 const bool enforcePMColor = buffer.readBool(); 63 return SkArithmeticMode::Create(k1, k2, k3, k4, enforcePMColor); 64} 65 66static int pinToByte(int value) { 67 if (value < 0) { 68 value = 0; 69 } else if (value > 255) { 70 value = 255; 71 } 72 return value; 73} 74 75static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 76 int src, int dst) { 77 SkScalar result = SkScalarMul(k1, src * dst) + 78 SkScalarMul(k2, src) + 79 SkScalarMul(k3, dst) + 80 k4; 81 int res = SkScalarRoundToInt(result); 82 return pinToByte(res); 83} 84 85static int blend(int src, int dst, int scale) { 86 return dst + ((src - dst) * scale >> 8); 87} 88 89void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], 90 int count, const SkAlpha aaCoverage[]) const { 91 SkScalar k1 = fK[0] / 255; 92 SkScalar k2 = fK[1]; 93 SkScalar k3 = fK[2]; 94 SkScalar k4 = fK[3] * 255; 95 96 for (int i = 0; i < count; ++i) { 97 if ((nullptr == aaCoverage) || aaCoverage[i]) { 98 SkPMColor sc = src[i]; 99 SkPMColor dc = dst[i]; 100 101 int a, r, g, b; 102 103 a = arith(k1, k2, k3, k4, SkGetPackedA32(sc), SkGetPackedA32(dc)); 104 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 105 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 106 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 107 if (fEnforcePMColor) { 108 r = SkMin32(r, a); 109 g = SkMin32(g, a); 110 b = SkMin32(b, a); 111 } 112 113 // apply antialias coverage if necessary 114 if (aaCoverage && 0xFF != aaCoverage[i]) { 115 int scale = aaCoverage[i] + (aaCoverage[i] >> 7); 116 a = blend(a, SkGetPackedA32(sc), scale); 117 r = blend(r, SkGetPackedR32(sc), scale); 118 g = blend(g, SkGetPackedG32(sc), scale); 119 b = blend(b, SkGetPackedB32(sc), scale); 120 } 121 122 dst[i] = fEnforcePMColor ? SkPackARGB32(a, r, g, b) : SkPackARGB32NoCheck(a, r, g, b); 123 } 124 } 125} 126 127#ifndef SK_IGNORE_TO_STRING 128void SkArithmeticMode_scalar::toString(SkString* str) const { 129 str->append("SkArithmeticMode_scalar: "); 130 for (int i = 0; i < 4; ++i) { 131 str->appendScalar(fK[i]); 132 str->append(" "); 133 } 134 str->appendS32(fEnforcePMColor ? 1 : 0); 135} 136#endif 137 138/////////////////////////////////////////////////////////////////////////////// 139 140SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2, 141 SkScalar k3, SkScalar k4, 142 bool enforcePMColor) { 143 if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) && 144 SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) { 145 return SkXfermode::Create(SkXfermode::kSrc_Mode); 146 } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && 147 SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) { 148 return SkXfermode::Create(SkXfermode::kDst_Mode); 149 } 150 151 return new SkArithmeticMode_scalar(k1, k2, k3, k4, enforcePMColor); 152} 153 154 155////////////////////////////////////////////////////////////////////////////// 156 157#if SK_SUPPORT_GPU 158const GrFragmentProcessor* SkArithmeticMode_scalar::getFragmentProcessorForImageFilter( 159 const GrFragmentProcessor* dst) const { 160 return GrArithmeticFP::Create(SkScalarToFloat(fK[0]), 161 SkScalarToFloat(fK[1]), 162 SkScalarToFloat(fK[2]), 163 SkScalarToFloat(fK[3]), 164 fEnforcePMColor, 165 dst); 166} 167 168GrXPFactory* SkArithmeticMode_scalar::asXPFactory() const { 169 return GrArithmeticXPFactory::Create(SkScalarToFloat(fK[0]), 170 SkScalarToFloat(fK[1]), 171 SkScalarToFloat(fK[2]), 172 SkScalarToFloat(fK[3]), 173 fEnforcePMColor); 174} 175 176#endif 177 178SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) 179 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) 180SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 181