blob: 7492cce5ec089bacdba84a67efafa8b56dbee3ed [file] [log] [blame]
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001/*
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
mike@reedtribe.orge51755f2011-12-10 19:36:56 +00008#include "SkArithmeticMode.h"
9#include "SkColorPriv.h"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000010#include "SkString.h"
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000011#include "SkUnPreMultiply.h"
12
13class SkArithmeticMode_scalar : public SkXfermode {
14public:
15 SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) {
16 fK[0] = k1;
17 fK[1] = k2;
18 fK[2] = k3;
19 fK[3] = k4;
20 }
21
22 virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +000023 const SkAlpha aa[]) const SK_OVERRIDE;
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000024
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000025 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +000026 SK_DECLARE_UNFLATTENABLE_OBJECT()
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000027
28private:
29 SkScalar fK[4];
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000030
skia.committer@gmail.com98ded842013-01-23 07:06:17 +000031 typedef SkXfermode INHERITED;
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000032};
33
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000034static int pinToByte(int value) {
35 if (value < 0) {
36 value = 0;
37 } else if (value > 255) {
38 value = 255;
39 }
40 return value;
41}
42
43static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4,
44 int src, int dst) {
45 SkScalar result = SkScalarMul(k1, src * dst) +
46 SkScalarMul(k2, src) +
47 SkScalarMul(k3, dst) +
48 k4;
49 int res = SkScalarRoundToInt(result);
50 return pinToByte(res);
51}
52
53static int blend(int src, int dst, int scale) {
54 return dst + ((src - dst) * scale >> 8);
55}
56
57static bool needsUnpremul(int alpha) {
58 return 0 != alpha && 0xFF != alpha;
59}
60
61void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[],
reed@google.com30da7452012-12-17 19:55:24 +000062 int count, const SkAlpha aaCoverage[]) const {
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000063 SkScalar k1 = fK[0] / 255;
64 SkScalar k2 = fK[1];
65 SkScalar k3 = fK[2];
66 SkScalar k4 = fK[3] * 255;
67
68 for (int i = 0; i < count; ++i) {
69 if ((NULL == aaCoverage) || aaCoverage[i]) {
70 SkPMColor sc = src[i];
71 SkPMColor dc = dst[i];
72 int sa = SkGetPackedA32(sc);
73 int da = SkGetPackedA32(dc);
74
75 int srcNeedsUnpremul = needsUnpremul(sa);
76 int dstNeedsUnpremul = needsUnpremul(sa);
77
78 int a, r, g, b;
79
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +000080 if (!srcNeedsUnpremul && !dstNeedsUnpremul) {
mike@reedtribe.orge51755f2011-12-10 19:36:56 +000081 a = arith(k1, k2, k3, k4, sa, sa);
82 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc));
83 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc));
84 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc));
85 } else {
86 int sr = SkGetPackedR32(sc);
87 int sg = SkGetPackedG32(sc);
88 int sb = SkGetPackedB32(sc);
89 if (srcNeedsUnpremul) {
90 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa);
91 sr = SkUnPreMultiply::ApplyScale(scale, sr);
92 sg = SkUnPreMultiply::ApplyScale(scale, sg);
93 sb = SkUnPreMultiply::ApplyScale(scale, sb);
94 }
95
96 int dr = SkGetPackedR32(dc);
97 int dg = SkGetPackedG32(dc);
98 int db = SkGetPackedB32(dc);
99 if (dstNeedsUnpremul) {
100 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da);
101 dr = SkUnPreMultiply::ApplyScale(scale, dr);
102 dg = SkUnPreMultiply::ApplyScale(scale, dg);
103 db = SkUnPreMultiply::ApplyScale(scale, db);
104 }
105
106 a = arith(k1, k2, k3, k4, sa, sa);
107 r = arith(k1, k2, k3, k4, sr, dr);
108 g = arith(k1, k2, k3, k4, sg, dg);
109 b = arith(k1, k2, k3, k4, sb, db);
110 }
111
112 // apply antialias coverage if necessary
113 if (aaCoverage && 0xFF != aaCoverage[i]) {
114 int scale = aaCoverage[i] + (aaCoverage[i] >> 7);
115 a = blend(a, SkGetPackedA32(sc), scale);
116 r = blend(r, SkGetPackedR32(sc), scale);
117 g = blend(g, SkGetPackedG32(sc), scale);
118 b = blend(b, SkGetPackedB32(sc), scale);
119 }
120
mike@reedtribe.org0e330ae2012-08-12 19:08:41 +0000121 // turn the result back into premul
122 if (0xFF != a) {
123 int scale = a + (a >> 7);
124 r = SkAlphaMul(r, scale);
125 g = SkAlphaMul(g, scale);
126 b = SkAlphaMul(b, scale);
127 }
128 dst[i] = SkPackARGB32(a, r, g, b);
mike@reedtribe.orge51755f2011-12-10 19:36:56 +0000129 }
130 }
131}
132
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000133#ifdef SK_DEVELOPER
134void SkArithmeticMode_scalar::toString(SkString* str) const {
135 str->append("SkArithmeticMode_scalar: ");
136 for (int i = 0; i < 4; ++i) {
137 str->appendScalar(fK[i]);
138 if (i < 3) {
139 str->append(" ");
140 }
141 }
142}
143#endif
mike@reedtribe.orge51755f2011-12-10 19:36:56 +0000144
145///////////////////////////////////////////////////////////////////////////////
146
147static bool fitsInBits(SkScalar x, int bits) {
148#ifdef SK_SCALAR_IS_FIXED
149 x = SkAbs32(x);
150 x += 1 << 7;
151 x >>= 8;
152 return x < (1 << (bits - 1));
153#else
154 return SkScalarAbs(x) < (1 << (bits - 1));
155#endif
156}
157
caryclark@google.com383d5d42012-06-06 12:09:18 +0000158#if 0 // UNUSED
mike@reedtribe.orge51755f2011-12-10 19:36:56 +0000159static int32_t toDot8(SkScalar x) {
160#ifdef SK_SCALAR_IS_FIXED
161 x += 1 << 7;
162 x >>= 8;
163 return x;
164#else
165 return (int32_t)(x * 256);
166#endif
167}
caryclark@google.com383d5d42012-06-06 12:09:18 +0000168#endif
mike@reedtribe.orge51755f2011-12-10 19:36:56 +0000169
170SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2,
171 SkScalar k3, SkScalar k4) {
172 if (fitsInBits(k1, 8) && fitsInBits(k2, 16) &&
173 fitsInBits(k2, 16) && fitsInBits(k2, 24)) {
174
caryclark@google.com383d5d42012-06-06 12:09:18 +0000175#if 0 // UNUSED
mike@reedtribe.orge51755f2011-12-10 19:36:56 +0000176 int32_t i1 = toDot8(k1);
177 int32_t i2 = toDot8(k2);
178 int32_t i3 = toDot8(k3);
179 int32_t i4 = toDot8(k4);
mike@reedtribe.orge51755f2011-12-10 19:36:56 +0000180 if (i1) {
181 return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4));
182 }
183 if (0 == i2) {
184 return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4));
185 }
186 if (0 == i3) {
187 return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4));
188 }
189 return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4));
190#endif
191 }
192 return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4));
193}