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 18static const bool gUseUnpremul = false; 19 20class SkArithmeticMode_scalar : public SkXfermode { 21public: 22 static SkArithmeticMode_scalar* Create(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 23 bool enforcePMColor) { 24 return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4, enforcePMColor)); 25 } 26 27 virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, 28 const SkAlpha aa[]) const override; 29 30 SK_TO_STRING_OVERRIDE() 31 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) 32 33#if SK_SUPPORT_GPU 34 bool asFragmentProcessor(GrFragmentProcessor**, GrTexture* background) const override; 35 36 bool asXPFactory(GrXPFactory**) const override; 37#endif 38 39private: 40 SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, bool enforcePMColor) { 41 fK[0] = k1; 42 fK[1] = k2; 43 fK[2] = k3; 44 fK[3] = k4; 45 fEnforcePMColor = enforcePMColor; 46 } 47 48 void flatten(SkWriteBuffer& buffer) const override { 49 buffer.writeScalar(fK[0]); 50 buffer.writeScalar(fK[1]); 51 buffer.writeScalar(fK[2]); 52 buffer.writeScalar(fK[3]); 53 buffer.writeBool(fEnforcePMColor); 54 } 55 SkScalar fK[4]; 56 bool fEnforcePMColor; 57 58 friend class SkArithmeticMode; 59 60 typedef SkXfermode INHERITED; 61}; 62 63SkFlattenable* SkArithmeticMode_scalar::CreateProc(SkReadBuffer& buffer) { 64 const SkScalar k1 = buffer.readScalar(); 65 const SkScalar k2 = buffer.readScalar(); 66 const SkScalar k3 = buffer.readScalar(); 67 const SkScalar k4 = buffer.readScalar(); 68 const bool enforcePMColor = buffer.readBool(); 69 return Create(k1, k2, k3, k4, enforcePMColor); 70} 71 72static int pinToByte(int value) { 73 if (value < 0) { 74 value = 0; 75 } else if (value > 255) { 76 value = 255; 77 } 78 return value; 79} 80 81static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 82 int src, int dst) { 83 SkScalar result = SkScalarMul(k1, src * dst) + 84 SkScalarMul(k2, src) + 85 SkScalarMul(k3, dst) + 86 k4; 87 int res = SkScalarRoundToInt(result); 88 return pinToByte(res); 89} 90 91static int blend(int src, int dst, int scale) { 92 return dst + ((src - dst) * scale >> 8); 93} 94 95static bool needsUnpremul(int alpha) { 96 return 0 != alpha && 0xFF != alpha; 97} 98 99void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], 100 int count, const SkAlpha aaCoverage[]) const { 101 SkScalar k1 = fK[0] / 255; 102 SkScalar k2 = fK[1]; 103 SkScalar k3 = fK[2]; 104 SkScalar k4 = fK[3] * 255; 105 106 for (int i = 0; i < count; ++i) { 107 if ((NULL == aaCoverage) || aaCoverage[i]) { 108 SkPMColor sc = src[i]; 109 SkPMColor dc = dst[i]; 110 111 int a, r, g, b; 112 113 if (gUseUnpremul) { 114 int sa = SkGetPackedA32(sc); 115 int da = SkGetPackedA32(dc); 116 117 int srcNeedsUnpremul = needsUnpremul(sa); 118 int dstNeedsUnpremul = needsUnpremul(da); 119 120 if (!srcNeedsUnpremul && !dstNeedsUnpremul) { 121 a = arith(k1, k2, k3, k4, sa, da); 122 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 123 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 124 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 125 } else { 126 int sr = SkGetPackedR32(sc); 127 int sg = SkGetPackedG32(sc); 128 int sb = SkGetPackedB32(sc); 129 if (srcNeedsUnpremul) { 130 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa); 131 sr = SkUnPreMultiply::ApplyScale(scale, sr); 132 sg = SkUnPreMultiply::ApplyScale(scale, sg); 133 sb = SkUnPreMultiply::ApplyScale(scale, sb); 134 } 135 136 int dr = SkGetPackedR32(dc); 137 int dg = SkGetPackedG32(dc); 138 int db = SkGetPackedB32(dc); 139 if (dstNeedsUnpremul) { 140 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da); 141 dr = SkUnPreMultiply::ApplyScale(scale, dr); 142 dg = SkUnPreMultiply::ApplyScale(scale, dg); 143 db = SkUnPreMultiply::ApplyScale(scale, db); 144 } 145 146 a = arith(k1, k2, k3, k4, sa, da); 147 r = arith(k1, k2, k3, k4, sr, dr); 148 g = arith(k1, k2, k3, k4, sg, dg); 149 b = arith(k1, k2, k3, k4, sb, db); 150 } 151 } else { 152 a = arith(k1, k2, k3, k4, SkGetPackedA32(sc), SkGetPackedA32(dc)); 153 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 154 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 155 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 156 if (fEnforcePMColor) { 157 r = SkMin32(r, a); 158 g = SkMin32(g, a); 159 b = SkMin32(b, a); 160 } 161 } 162 163 // apply antialias coverage if necessary 164 if (aaCoverage && 0xFF != aaCoverage[i]) { 165 int scale = aaCoverage[i] + (aaCoverage[i] >> 7); 166 a = blend(a, SkGetPackedA32(sc), scale); 167 r = blend(r, SkGetPackedR32(sc), scale); 168 g = blend(g, SkGetPackedG32(sc), scale); 169 b = blend(b, SkGetPackedB32(sc), scale); 170 } 171 172 // turn the result back into premul 173 if (gUseUnpremul && (0xFF != a)) { 174 int scale = a + (a >> 7); 175 r = SkAlphaMul(r, scale); 176 g = SkAlphaMul(g, scale); 177 b = SkAlphaMul(b, scale); 178 } 179 dst[i] = fEnforcePMColor ? SkPackARGB32(a, r, g, b) : SkPackARGB32NoCheck(a, r, g, b); 180 } 181 } 182} 183 184#ifndef SK_IGNORE_TO_STRING 185void SkArithmeticMode_scalar::toString(SkString* str) const { 186 str->append("SkArithmeticMode_scalar: "); 187 for (int i = 0; i < 4; ++i) { 188 str->appendScalar(fK[i]); 189 str->append(" "); 190 } 191 str->appendS32(fEnforcePMColor ? 1 : 0); 192} 193#endif 194 195/////////////////////////////////////////////////////////////////////////////// 196 197static bool fitsInBits(SkScalar x, int bits) { 198 return SkScalarAbs(x) < (1 << (bits - 1)); 199} 200 201#if 0 // UNUSED 202static int32_t toDot8(SkScalar x) { 203 return (int32_t)(x * 256); 204} 205#endif 206 207SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2, 208 SkScalar k3, SkScalar k4, 209 bool enforcePMColor) { 210 if (fitsInBits(k1, 8) && fitsInBits(k2, 16) && 211 fitsInBits(k2, 16) && fitsInBits(k2, 24)) { 212 213#if 0 // UNUSED 214 int32_t i1 = toDot8(k1); 215 int32_t i2 = toDot8(k2); 216 int32_t i3 = toDot8(k3); 217 int32_t i4 = toDot8(k4); 218 if (i1) { 219 return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4)); 220 } 221 if (0 == i2) { 222 return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4)); 223 } 224 if (0 == i3) { 225 return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4)); 226 } 227 return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4)); 228#endif 229 } 230 return SkArithmeticMode_scalar::Create(k1, k2, k3, k4, enforcePMColor); 231} 232 233 234////////////////////////////////////////////////////////////////////////////// 235 236#if SK_SUPPORT_GPU 237bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp, 238 GrTexture* background) const { 239 if (fp) { 240 *fp = GrArithmeticFP::Create(SkScalarToFloat(fK[0]), 241 SkScalarToFloat(fK[1]), 242 SkScalarToFloat(fK[2]), 243 SkScalarToFloat(fK[3]), 244 fEnforcePMColor, 245 background); 246 } 247 return true; 248} 249 250bool SkArithmeticMode_scalar::asXPFactory(GrXPFactory** xpf) const { 251 if (xpf) { 252 *xpf = GrArithmeticXPFactory::Create(SkScalarToFloat(fK[0]), 253 SkScalarToFloat(fK[1]), 254 SkScalarToFloat(fK[2]), 255 SkScalarToFloat(fK[3]), 256 fEnforcePMColor); 257 } 258 return true; 259} 260 261#endif 262 263SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) 264 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) 265SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 266