gfx/skia/trunk/src/core/SkXfermode.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include "SkXfermode.h"
michael@0 11 #include "SkXfermode_proccoeff.h"
michael@0 12 #include "SkColorPriv.h"
michael@0 13 #include "SkReadBuffer.h"
michael@0 14 #include "SkWriteBuffer.h"
michael@0 15 #include "SkMathPriv.h"
michael@0 16 #include "SkString.h"
michael@0 17 #include "SkUtilsArm.h"
michael@0 18
michael@0 19 #if !SK_ARM_NEON_IS_NONE
michael@0 20 #include "SkXfermode_opts_arm_neon.h"
michael@0 21 #endif
michael@0 22
michael@0 23 #define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
michael@0 24
michael@0 25 #if 0
michael@0 26 // idea for higher precision blends in xfer procs (and slightly faster)
michael@0 27 // see DstATop as a probable caller
michael@0 28 static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
michael@0 29 SkASSERT(a <= 255);
michael@0 30 SkASSERT(b <= 255);
michael@0 31 SkASSERT(c <= 255);
michael@0 32 SkASSERT(d <= 255);
michael@0 33 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
michael@0 34 unsigned result = (prod + (prod >> 8)) >> 8;
michael@0 35 SkASSERT(result <= 255);
michael@0 36 return result;
michael@0 37 }
michael@0 38 #endif
michael@0 39
michael@0 40 static inline unsigned saturated_add(unsigned a, unsigned b) {
michael@0 41 SkASSERT(a <= 255);
michael@0 42 SkASSERT(b <= 255);
michael@0 43 unsigned sum = a + b;
michael@0 44 if (sum > 255) {
michael@0 45 sum = 255;
michael@0 46 }
michael@0 47 return sum;
michael@0 48 }
michael@0 49
michael@0 50 static inline int clamp_signed_byte(int n) {
michael@0 51 if (n < 0) {
michael@0 52 n = 0;
michael@0 53 } else if (n > 255) {
michael@0 54 n = 255;
michael@0 55 }
michael@0 56 return n;
michael@0 57 }
michael@0 58
michael@0 59 static inline int clamp_div255round(int prod) {
michael@0 60 if (prod <= 0) {
michael@0 61 return 0;
michael@0 62 } else if (prod >= 255*255) {
michael@0 63 return 255;
michael@0 64 } else {
michael@0 65 return SkDiv255Round(prod);
michael@0 66 }
michael@0 67 }
michael@0 68
michael@0 69 ///////////////////////////////////////////////////////////////////////////////
michael@0 70
michael@0 71 // kClear_Mode, //!< [0, 0]
michael@0 72 static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 73 return 0;
michael@0 74 }
michael@0 75
michael@0 76 // kSrc_Mode, //!< [Sa, Sc]
michael@0 77 static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 78 return src;
michael@0 79 }
michael@0 80
michael@0 81 // kDst_Mode, //!< [Da, Dc]
michael@0 82 static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 83 return dst;
michael@0 84 }
michael@0 85
michael@0 86 // kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
michael@0 87 static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 88 #if 0
michael@0 89 // this is the old, more-correct way, but it doesn't guarantee that dst==255
michael@0 90 // will always stay opaque
michael@0 91 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
michael@0 92 #else
michael@0 93 // this is slightly faster, but more importantly guarantees that dst==255
michael@0 94 // will always stay opaque
michael@0 95 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
michael@0 96 #endif
michael@0 97 }
michael@0 98
michael@0 99 // kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
michael@0 100 static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 101 // this is the reverse of srcover, just flipping src and dst
michael@0 102 // see srcover's comment about the 256 for opaqueness guarantees
michael@0 103 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
michael@0 104 }
michael@0 105
michael@0 106 // kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
michael@0 107 static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 108 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
michael@0 109 }
michael@0 110
michael@0 111 // kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
michael@0 112 static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 113 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
michael@0 114 }
michael@0 115
michael@0 116 // kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
michael@0 117 static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 118 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
michael@0 119 }
michael@0 120
michael@0 121 // kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
michael@0 122 static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 123 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
michael@0 124 }
michael@0 125
michael@0 126 // kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
michael@0 127 static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 128 unsigned sa = SkGetPackedA32(src);
michael@0 129 unsigned da = SkGetPackedA32(dst);
michael@0 130 unsigned isa = 255 - sa;
michael@0 131
michael@0 132 return SkPackARGB32(da,
michael@0 133 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
michael@0 134 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
michael@0 135 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
michael@0 136 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
michael@0 137 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
michael@0 138 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
michael@0 139 }
michael@0 140
michael@0 141 // kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
michael@0 142 static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 143 unsigned sa = SkGetPackedA32(src);
michael@0 144 unsigned da = SkGetPackedA32(dst);
michael@0 145 unsigned ida = 255 - da;
michael@0 146
michael@0 147 return SkPackARGB32(sa,
michael@0 148 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
michael@0 149 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
michael@0 150 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
michael@0 151 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
michael@0 152 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
michael@0 153 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
michael@0 154 }
michael@0 155
michael@0 156 // kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
michael@0 157 static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 158 unsigned sa = SkGetPackedA32(src);
michael@0 159 unsigned da = SkGetPackedA32(dst);
michael@0 160 unsigned isa = 255 - sa;
michael@0 161 unsigned ida = 255 - da;
michael@0 162
michael@0 163 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
michael@0 164 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
michael@0 165 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
michael@0 166 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
michael@0 167 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
michael@0 168 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
michael@0 169 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
michael@0 170 }
michael@0 171
michael@0 172 ///////////////////////////////////////////////////////////////////////////////
michael@0 173
michael@0 174 // kPlus_Mode
michael@0 175 static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 176 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
michael@0 177 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
michael@0 178 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
michael@0 179 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
michael@0 180 return SkPackARGB32(a, r, g, b);
michael@0 181 }
michael@0 182
michael@0 183 // kModulate_Mode
michael@0 184 static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 185 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
michael@0 186 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
michael@0 187 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
michael@0 188 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
michael@0 189 return SkPackARGB32(a, r, g, b);
michael@0 190 }
michael@0 191
michael@0 192 static inline int srcover_byte(int a, int b) {
michael@0 193 return a + b - SkAlphaMulAlpha(a, b);
michael@0 194 }
michael@0 195
michael@0 196 // kMultiply_Mode
michael@0 197 // B(Cb, Cs) = Cb x Cs
michael@0 198 // multiply uses its own version of blendfunc_byte because sa and da are not needed
michael@0 199 static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
michael@0 200 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
michael@0 201 }
michael@0 202
michael@0 203 static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 204 int sa = SkGetPackedA32(src);
michael@0 205 int da = SkGetPackedA32(dst);
michael@0 206 int a = srcover_byte(sa, da);
michael@0 207 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 208 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 209 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 210 return SkPackARGB32(a, r, g, b);
michael@0 211 }
michael@0 212
michael@0 213 // kScreen_Mode
michael@0 214 static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 215 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
michael@0 216 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
michael@0 217 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
michael@0 218 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
michael@0 219 return SkPackARGB32(a, r, g, b);
michael@0 220 }
michael@0 221
michael@0 222 // kOverlay_Mode
michael@0 223 static inline int overlay_byte(int sc, int dc, int sa, int da) {
michael@0 224 int tmp = sc * (255 - da) + dc * (255 - sa);
michael@0 225 int rc;
michael@0 226 if (2 * dc <= da) {
michael@0 227 rc = 2 * sc * dc;
michael@0 228 } else {
michael@0 229 rc = sa * da - 2 * (da - dc) * (sa - sc);
michael@0 230 }
michael@0 231 return clamp_div255round(rc + tmp);
michael@0 232 }
michael@0 233 static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 234 int sa = SkGetPackedA32(src);
michael@0 235 int da = SkGetPackedA32(dst);
michael@0 236 int a = srcover_byte(sa, da);
michael@0 237 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 238 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 239 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 240 return SkPackARGB32(a, r, g, b);
michael@0 241 }
michael@0 242
michael@0 243 // kDarken_Mode
michael@0 244 static inline int darken_byte(int sc, int dc, int sa, int da) {
michael@0 245 int sd = sc * da;
michael@0 246 int ds = dc * sa;
michael@0 247 if (sd < ds) {
michael@0 248 // srcover
michael@0 249 return sc + dc - SkDiv255Round(ds);
michael@0 250 } else {
michael@0 251 // dstover
michael@0 252 return dc + sc - SkDiv255Round(sd);
michael@0 253 }
michael@0 254 }
michael@0 255 static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 256 int sa = SkGetPackedA32(src);
michael@0 257 int da = SkGetPackedA32(dst);
michael@0 258 int a = srcover_byte(sa, da);
michael@0 259 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 260 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 261 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 262 return SkPackARGB32(a, r, g, b);
michael@0 263 }
michael@0 264
michael@0 265 // kLighten_Mode
michael@0 266 static inline int lighten_byte(int sc, int dc, int sa, int da) {
michael@0 267 int sd = sc * da;
michael@0 268 int ds = dc * sa;
michael@0 269 if (sd > ds) {
michael@0 270 // srcover
michael@0 271 return sc + dc - SkDiv255Round(ds);
michael@0 272 } else {
michael@0 273 // dstover
michael@0 274 return dc + sc - SkDiv255Round(sd);
michael@0 275 }
michael@0 276 }
michael@0 277 static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 278 int sa = SkGetPackedA32(src);
michael@0 279 int da = SkGetPackedA32(dst);
michael@0 280 int a = srcover_byte(sa, da);
michael@0 281 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 282 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 283 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 284 return SkPackARGB32(a, r, g, b);
michael@0 285 }
michael@0 286
michael@0 287 // kColorDodge_Mode
michael@0 288 static inline int colordodge_byte(int sc, int dc, int sa, int da) {
michael@0 289 int diff = sa - sc;
michael@0 290 int rc;
michael@0 291 if (0 == dc) {
michael@0 292 return SkAlphaMulAlpha(sc, 255 - da);
michael@0 293 } else if (0 == diff) {
michael@0 294 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
michael@0 295 } else {
michael@0 296 diff = dc * sa / diff;
michael@0 297 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
michael@0 298 }
michael@0 299 return clamp_div255round(rc);
michael@0 300 }
michael@0 301 static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 302 int sa = SkGetPackedA32(src);
michael@0 303 int da = SkGetPackedA32(dst);
michael@0 304 int a = srcover_byte(sa, da);
michael@0 305 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 306 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 307 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 308 return SkPackARGB32(a, r, g, b);
michael@0 309 }
michael@0 310
michael@0 311 // kColorBurn_Mode
michael@0 312 static inline int colorburn_byte(int sc, int dc, int sa, int da) {
michael@0 313 int rc;
michael@0 314 if (dc == da) {
michael@0 315 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
michael@0 316 } else if (0 == sc) {
michael@0 317 return SkAlphaMulAlpha(dc, 255 - sa);
michael@0 318 } else {
michael@0 319 int tmp = (da - dc) * sa / sc;
michael@0 320 rc = sa * (da - ((da < tmp) ? da : tmp))
michael@0 321 + sc * (255 - da) + dc * (255 - sa);
michael@0 322 }
michael@0 323 return clamp_div255round(rc);
michael@0 324 }
michael@0 325 static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 326 int sa = SkGetPackedA32(src);
michael@0 327 int da = SkGetPackedA32(dst);
michael@0 328 int a = srcover_byte(sa, da);
michael@0 329 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 330 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 331 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 332 return SkPackARGB32(a, r, g, b);
michael@0 333 }
michael@0 334
michael@0 335 // kHardLight_Mode
michael@0 336 static inline int hardlight_byte(int sc, int dc, int sa, int da) {
michael@0 337 int rc;
michael@0 338 if (2 * sc <= sa) {
michael@0 339 rc = 2 * sc * dc;
michael@0 340 } else {
michael@0 341 rc = sa * da - 2 * (da - dc) * (sa - sc);
michael@0 342 }
michael@0 343 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
michael@0 344 }
michael@0 345 static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 346 int sa = SkGetPackedA32(src);
michael@0 347 int da = SkGetPackedA32(dst);
michael@0 348 int a = srcover_byte(sa, da);
michael@0 349 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 350 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 351 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 352 return SkPackARGB32(a, r, g, b);
michael@0 353 }
michael@0 354
michael@0 355 // returns 255 * sqrt(n/255)
michael@0 356 static U8CPU sqrt_unit_byte(U8CPU n) {
michael@0 357 return SkSqrtBits(n, 15+4);
michael@0 358 }
michael@0 359
michael@0 360 // kSoftLight_Mode
michael@0 361 static inline int softlight_byte(int sc, int dc, int sa, int da) {
michael@0 362 int m = da ? dc * 256 / da : 0;
michael@0 363 int rc;
michael@0 364 if (2 * sc <= sa) {
michael@0 365 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
michael@0 366 } else if (4 * dc <= da) {
michael@0 367 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
michael@0 368 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
michael@0 369 } else {
michael@0 370 int tmp = sqrt_unit_byte(m) - m;
michael@0 371 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
michael@0 372 }
michael@0 373 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
michael@0 374 }
michael@0 375 static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 376 int sa = SkGetPackedA32(src);
michael@0 377 int da = SkGetPackedA32(dst);
michael@0 378 int a = srcover_byte(sa, da);
michael@0 379 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 380 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 381 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 382 return SkPackARGB32(a, r, g, b);
michael@0 383 }
michael@0 384
michael@0 385 // kDifference_Mode
michael@0 386 static inline int difference_byte(int sc, int dc, int sa, int da) {
michael@0 387 int tmp = SkMin32(sc * da, dc * sa);
michael@0 388 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
michael@0 389 }
michael@0 390 static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 391 int sa = SkGetPackedA32(src);
michael@0 392 int da = SkGetPackedA32(dst);
michael@0 393 int a = srcover_byte(sa, da);
michael@0 394 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 395 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 396 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 397 return SkPackARGB32(a, r, g, b);
michael@0 398 }
michael@0 399
michael@0 400 // kExclusion_Mode
michael@0 401 static inline int exclusion_byte(int sc, int dc, int, int) {
michael@0 402 // this equations is wacky, wait for SVG to confirm it
michael@0 403 //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
michael@0 404
michael@0 405 // The above equation can be simplified as follows
michael@0 406 int r = 255*(sc + dc) - 2 * sc * dc;
michael@0 407 return clamp_div255round(r);
michael@0 408 }
michael@0 409 static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 410 int sa = SkGetPackedA32(src);
michael@0 411 int da = SkGetPackedA32(dst);
michael@0 412 int a = srcover_byte(sa, da);
michael@0 413 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
michael@0 414 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
michael@0 415 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
michael@0 416 return SkPackARGB32(a, r, g, b);
michael@0 417 }
michael@0 418
michael@0 419 // The CSS compositing spec introduces the following formulas:
michael@0 420 // (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
michael@0 421 // SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
michael@0 422 // while PDF and CG uses the one from Rec. Rec. 601
michael@0 423 // See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
michael@0 424 static inline int Lum(int r, int g, int b)
michael@0 425 {
michael@0 426 return SkDiv255Round(r * 77 + g * 150 + b * 28);
michael@0 427 }
michael@0 428
michael@0 429 static inline int min2(int a, int b) { return a < b ? a : b; }
michael@0 430 static inline int max2(int a, int b) { return a > b ? a : b; }
michael@0 431 #define minimum(a, b, c) min2(min2(a, b), c)
michael@0 432 #define maximum(a, b, c) max2(max2(a, b), c)
michael@0 433
michael@0 434 static inline int Sat(int r, int g, int b) {
michael@0 435 return maximum(r, g, b) - minimum(r, g, b);
michael@0 436 }
michael@0 437
michael@0 438 static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
michael@0 439 if(*Cmax > *Cmin) {
michael@0 440 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
michael@0 441 *Cmax = s;
michael@0 442 } else {
michael@0 443 *Cmax = 0;
michael@0 444 *Cmid = 0;
michael@0 445 }
michael@0 446
michael@0 447 *Cmin = 0;
michael@0 448 }
michael@0 449
michael@0 450 static inline void SetSat(int* r, int* g, int* b, int s) {
michael@0 451 if(*r <= *g) {
michael@0 452 if(*g <= *b) {
michael@0 453 setSaturationComponents(r, g, b, s);
michael@0 454 } else if(*r <= *b) {
michael@0 455 setSaturationComponents(r, b, g, s);
michael@0 456 } else {
michael@0 457 setSaturationComponents(b, r, g, s);
michael@0 458 }
michael@0 459 } else if(*r <= *b) {
michael@0 460 setSaturationComponents(g, r, b, s);
michael@0 461 } else if(*g <= *b) {
michael@0 462 setSaturationComponents(g, b, r, s);
michael@0 463 } else {
michael@0 464 setSaturationComponents(b, g, r, s);
michael@0 465 }
michael@0 466 }
michael@0 467
michael@0 468 static inline void clipColor(int* r, int* g, int* b, int a) {
michael@0 469 int L = Lum(*r, *g, *b);
michael@0 470 int n = minimum(*r, *g, *b);
michael@0 471 int x = maximum(*r, *g, *b);
michael@0 472 int denom;
michael@0 473 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
michael@0 474 *r = L + SkMulDiv(*r - L, L, denom);
michael@0 475 *g = L + SkMulDiv(*g - L, L, denom);
michael@0 476 *b = L + SkMulDiv(*b - L, L, denom);
michael@0 477 }
michael@0 478
michael@0 479 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
michael@0 480 int numer = a - L;
michael@0 481 *r = L + SkMulDiv(*r - L, numer, denom);
michael@0 482 *g = L + SkMulDiv(*g - L, numer, denom);
michael@0 483 *b = L + SkMulDiv(*b - L, numer, denom);
michael@0 484 }
michael@0 485 }
michael@0 486
michael@0 487 static inline void SetLum(int* r, int* g, int* b, int a, int l) {
michael@0 488 int d = l - Lum(*r, *g, *b);
michael@0 489 *r += d;
michael@0 490 *g += d;
michael@0 491 *b += d;
michael@0 492
michael@0 493 clipColor(r, g, b, a);
michael@0 494 }
michael@0 495
michael@0 496 // non-separable blend modes are done in non-premultiplied alpha
michael@0 497 #define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
michael@0 498 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
michael@0 499
michael@0 500 // kHue_Mode
michael@0 501 // B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
michael@0 502 // Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
michael@0 503 static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 504 int sr = SkGetPackedR32(src);
michael@0 505 int sg = SkGetPackedG32(src);
michael@0 506 int sb = SkGetPackedB32(src);
michael@0 507 int sa = SkGetPackedA32(src);
michael@0 508
michael@0 509 int dr = SkGetPackedR32(dst);
michael@0 510 int dg = SkGetPackedG32(dst);
michael@0 511 int db = SkGetPackedB32(dst);
michael@0 512 int da = SkGetPackedA32(dst);
michael@0 513 int Sr, Sg, Sb;
michael@0 514
michael@0 515 if(sa && da) {
michael@0 516 Sr = sr * sa;
michael@0 517 Sg = sg * sa;
michael@0 518 Sb = sb * sa;
michael@0 519 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
michael@0 520 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
michael@0 521 } else {
michael@0 522 Sr = 0;
michael@0 523 Sg = 0;
michael@0 524 Sb = 0;
michael@0 525 }
michael@0 526
michael@0 527 int a = srcover_byte(sa, da);
michael@0 528 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
michael@0 529 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
michael@0 530 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
michael@0 531 return SkPackARGB32(a, r, g, b);
michael@0 532 }
michael@0 533
michael@0 534 // kSaturation_Mode
michael@0 535 // B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
michael@0 536 // Create a color with the saturation of the source color and the hue and luminosity of the backdrop color.
michael@0 537 static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 538 int sr = SkGetPackedR32(src);
michael@0 539 int sg = SkGetPackedG32(src);
michael@0 540 int sb = SkGetPackedB32(src);
michael@0 541 int sa = SkGetPackedA32(src);
michael@0 542
michael@0 543 int dr = SkGetPackedR32(dst);
michael@0 544 int dg = SkGetPackedG32(dst);
michael@0 545 int db = SkGetPackedB32(dst);
michael@0 546 int da = SkGetPackedA32(dst);
michael@0 547 int Dr, Dg, Db;
michael@0 548
michael@0 549 if(sa && da) {
michael@0 550 Dr = dr * sa;
michael@0 551 Dg = dg * sa;
michael@0 552 Db = db * sa;
michael@0 553 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
michael@0 554 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
michael@0 555 } else {
michael@0 556 Dr = 0;
michael@0 557 Dg = 0;
michael@0 558 Db = 0;
michael@0 559 }
michael@0 560
michael@0 561 int a = srcover_byte(sa, da);
michael@0 562 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
michael@0 563 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
michael@0 564 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
michael@0 565 return SkPackARGB32(a, r, g, b);
michael@0 566 }
michael@0 567
michael@0 568 // kColor_Mode
michael@0 569 // B(Cb, Cs) = SetLum(Cs, Lum(Cb))
michael@0 570 // Create a color with the hue and saturation of the source color and the luminosity of the backdrop color.
michael@0 571 static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 572 int sr = SkGetPackedR32(src);
michael@0 573 int sg = SkGetPackedG32(src);
michael@0 574 int sb = SkGetPackedB32(src);
michael@0 575 int sa = SkGetPackedA32(src);
michael@0 576
michael@0 577 int dr = SkGetPackedR32(dst);
michael@0 578 int dg = SkGetPackedG32(dst);
michael@0 579 int db = SkGetPackedB32(dst);
michael@0 580 int da = SkGetPackedA32(dst);
michael@0 581 int Sr, Sg, Sb;
michael@0 582
michael@0 583 if(sa && da) {
michael@0 584 Sr = sr * da;
michael@0 585 Sg = sg * da;
michael@0 586 Sb = sb * da;
michael@0 587 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
michael@0 588 } else {
michael@0 589 Sr = 0;
michael@0 590 Sg = 0;
michael@0 591 Sb = 0;
michael@0 592 }
michael@0 593
michael@0 594 int a = srcover_byte(sa, da);
michael@0 595 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
michael@0 596 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
michael@0 597 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
michael@0 598 return SkPackARGB32(a, r, g, b);
michael@0 599 }
michael@0 600
michael@0 601 // kLuminosity_Mode
michael@0 602 // B(Cb, Cs) = SetLum(Cb, Lum(Cs))
michael@0 603 // Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
michael@0 604 static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
michael@0 605 int sr = SkGetPackedR32(src);
michael@0 606 int sg = SkGetPackedG32(src);
michael@0 607 int sb = SkGetPackedB32(src);
michael@0 608 int sa = SkGetPackedA32(src);
michael@0 609
michael@0 610 int dr = SkGetPackedR32(dst);
michael@0 611 int dg = SkGetPackedG32(dst);
michael@0 612 int db = SkGetPackedB32(dst);
michael@0 613 int da = SkGetPackedA32(dst);
michael@0 614 int Dr, Dg, Db;
michael@0 615
michael@0 616 if(sa && da) {
michael@0 617 Dr = dr * sa;
michael@0 618 Dg = dg * sa;
michael@0 619 Db = db * sa;
michael@0 620 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
michael@0 621 } else {
michael@0 622 Dr = 0;
michael@0 623 Dg = 0;
michael@0 624 Db = 0;
michael@0 625 }
michael@0 626
michael@0 627 int a = srcover_byte(sa, da);
michael@0 628 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
michael@0 629 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
michael@0 630 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
michael@0 631 return SkPackARGB32(a, r, g, b);
michael@0 632 }
michael@0 633
michael@0 634 const ProcCoeff gProcCoeffs[] = {
michael@0 635 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
michael@0 636 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
michael@0 637 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
michael@0 638 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
michael@0 639 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
michael@0 640 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
michael@0 641 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
michael@0 642 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
michael@0 643 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
michael@0 644 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
michael@0 645 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
michael@0 646 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
michael@0 647
michael@0 648 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
michael@0 649 { modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
michael@0 650 { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
michael@0 651 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 652 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 653 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 654 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 655 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 656 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 657 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 658 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 659 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 660 { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 661 { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 662 { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 663 { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 664 { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
michael@0 665 };
michael@0 666
michael@0 667 ///////////////////////////////////////////////////////////////////////////////
michael@0 668
michael@0 669 bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
michael@0 670 return false;
michael@0 671 }
michael@0 672
michael@0 673 bool SkXfermode::asMode(Mode* mode) const {
michael@0 674 return false;
michael@0 675 }
michael@0 676
michael@0 677 bool SkXfermode::asNewEffect(GrEffectRef** effect, GrTexture* background) const {
michael@0 678 return false;
michael@0 679 }
michael@0 680
michael@0 681 bool SkXfermode::AsNewEffectOrCoeff(SkXfermode* xfermode,
michael@0 682 GrEffectRef** effect,
michael@0 683 Coeff* src,
michael@0 684 Coeff* dst,
michael@0 685 GrTexture* background) {
michael@0 686 if (NULL == xfermode) {
michael@0 687 return ModeAsCoeff(kSrcOver_Mode, src, dst);
michael@0 688 } else if (xfermode->asCoeff(src, dst)) {
michael@0 689 return true;
michael@0 690 } else {
michael@0 691 return xfermode->asNewEffect(effect, background);
michael@0 692 }
michael@0 693 }
michael@0 694
michael@0 695 SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
michael@0 696 // no-op. subclasses should override this
michael@0 697 return dst;
michael@0 698 }
michael@0 699
michael@0 700 void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
michael@0 701 const SkPMColor* SK_RESTRICT src, int count,
michael@0 702 const SkAlpha* SK_RESTRICT aa) const {
michael@0 703 SkASSERT(dst && src && count >= 0);
michael@0 704
michael@0 705 if (NULL == aa) {
michael@0 706 for (int i = count - 1; i >= 0; --i) {
michael@0 707 dst[i] = this->xferColor(src[i], dst[i]);
michael@0 708 }
michael@0 709 } else {
michael@0 710 for (int i = count - 1; i >= 0; --i) {
michael@0 711 unsigned a = aa[i];
michael@0 712 if (0 != a) {
michael@0 713 SkPMColor dstC = dst[i];
michael@0 714 SkPMColor C = this->xferColor(src[i], dstC);
michael@0 715 if (0xFF != a) {
michael@0 716 C = SkFourByteInterp(C, dstC, a);
michael@0 717 }
michael@0 718 dst[i] = C;
michael@0 719 }
michael@0 720 }
michael@0 721 }
michael@0 722 }
michael@0 723
michael@0 724 void SkXfermode::xfer16(uint16_t* dst,
michael@0 725 const SkPMColor* SK_RESTRICT src, int count,
michael@0 726 const SkAlpha* SK_RESTRICT aa) const {
michael@0 727 SkASSERT(dst && src && count >= 0);
michael@0 728
michael@0 729 if (NULL == aa) {
michael@0 730 for (int i = count - 1; i >= 0; --i) {
michael@0 731 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
michael@0 732 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
michael@0 733 }
michael@0 734 } else {
michael@0 735 for (int i = count - 1; i >= 0; --i) {
michael@0 736 unsigned a = aa[i];
michael@0 737 if (0 != a) {
michael@0 738 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
michael@0 739 SkPMColor C = this->xferColor(src[i], dstC);
michael@0 740 if (0xFF != a) {
michael@0 741 C = SkFourByteInterp(C, dstC, a);
michael@0 742 }
michael@0 743 dst[i] = SkPixel32ToPixel16_ToU16(C);
michael@0 744 }
michael@0 745 }
michael@0 746 }
michael@0 747 }
michael@0 748
michael@0 749 void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
michael@0 750 const SkPMColor src[], int count,
michael@0 751 const SkAlpha* SK_RESTRICT aa) const {
michael@0 752 SkASSERT(dst && src && count >= 0);
michael@0 753
michael@0 754 if (NULL == aa) {
michael@0 755 for (int i = count - 1; i >= 0; --i) {
michael@0 756 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
michael@0 757 dst[i] = SkToU8(SkGetPackedA32(res));
michael@0 758 }
michael@0 759 } else {
michael@0 760 for (int i = count - 1; i >= 0; --i) {
michael@0 761 unsigned a = aa[i];
michael@0 762 if (0 != a) {
michael@0 763 SkAlpha dstA = dst[i];
michael@0 764 unsigned A = SkGetPackedA32(this->xferColor(src[i],
michael@0 765 (SkPMColor)(dstA << SK_A32_SHIFT)));
michael@0 766 if (0xFF != a) {
michael@0 767 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
michael@0 768 }
michael@0 769 dst[i] = SkToU8(A);
michael@0 770 }
michael@0 771 }
michael@0 772 }
michael@0 773 }
michael@0 774
michael@0 775 ///////////////////////////////////////////////////////////////////////////////
michael@0 776
michael@0 777 void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
michael@0 778 const SkPMColor* SK_RESTRICT src, int count,
michael@0 779 const SkAlpha* SK_RESTRICT aa) const {
michael@0 780 SkASSERT(dst && src && count >= 0);
michael@0 781
michael@0 782 SkXfermodeProc proc = fProc;
michael@0 783
michael@0 784 if (NULL != proc) {
michael@0 785 if (NULL == aa) {
michael@0 786 for (int i = count - 1; i >= 0; --i) {
michael@0 787 dst[i] = proc(src[i], dst[i]);
michael@0 788 }
michael@0 789 } else {
michael@0 790 for (int i = count - 1; i >= 0; --i) {
michael@0 791 unsigned a = aa[i];
michael@0 792 if (0 != a) {
michael@0 793 SkPMColor dstC = dst[i];
michael@0 794 SkPMColor C = proc(src[i], dstC);
michael@0 795 if (a != 0xFF) {
michael@0 796 C = SkFourByteInterp(C, dstC, a);
michael@0 797 }
michael@0 798 dst[i] = C;
michael@0 799 }
michael@0 800 }
michael@0 801 }
michael@0 802 }
michael@0 803 }
michael@0 804
michael@0 805 void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
michael@0 806 const SkPMColor* SK_RESTRICT src, int count,
michael@0 807 const SkAlpha* SK_RESTRICT aa) const {
michael@0 808 SkASSERT(dst && src && count >= 0);
michael@0 809
michael@0 810 SkXfermodeProc proc = fProc;
michael@0 811
michael@0 812 if (NULL != proc) {
michael@0 813 if (NULL == aa) {
michael@0 814 for (int i = count - 1; i >= 0; --i) {
michael@0 815 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
michael@0 816 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
michael@0 817 }
michael@0 818 } else {
michael@0 819 for (int i = count - 1; i >= 0; --i) {
michael@0 820 unsigned a = aa[i];
michael@0 821 if (0 != a) {
michael@0 822 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
michael@0 823 SkPMColor C = proc(src[i], dstC);
michael@0 824 if (0xFF != a) {
michael@0 825 C = SkFourByteInterp(C, dstC, a);
michael@0 826 }
michael@0 827 dst[i] = SkPixel32ToPixel16_ToU16(C);
michael@0 828 }
michael@0 829 }
michael@0 830 }
michael@0 831 }
michael@0 832 }
michael@0 833
michael@0 834 void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
michael@0 835 const SkPMColor* SK_RESTRICT src, int count,
michael@0 836 const SkAlpha* SK_RESTRICT aa) const {
michael@0 837 SkASSERT(dst && src && count >= 0);
michael@0 838
michael@0 839 SkXfermodeProc proc = fProc;
michael@0 840
michael@0 841 if (NULL != proc) {
michael@0 842 if (NULL == aa) {
michael@0 843 for (int i = count - 1; i >= 0; --i) {
michael@0 844 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
michael@0 845 dst[i] = SkToU8(SkGetPackedA32(res));
michael@0 846 }
michael@0 847 } else {
michael@0 848 for (int i = count - 1; i >= 0; --i) {
michael@0 849 unsigned a = aa[i];
michael@0 850 if (0 != a) {
michael@0 851 SkAlpha dstA = dst[i];
michael@0 852 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
michael@0 853 unsigned A = SkGetPackedA32(res);
michael@0 854 if (0xFF != a) {
michael@0 855 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
michael@0 856 }
michael@0 857 dst[i] = SkToU8(A);
michael@0 858 }
michael@0 859 }
michael@0 860 }
michael@0 861 }
michael@0 862 }
michael@0 863
michael@0 864 SkProcXfermode::SkProcXfermode(SkReadBuffer& buffer)
michael@0 865 : SkXfermode(buffer) {
michael@0 866 fProc = NULL;
michael@0 867 if (!buffer.isCrossProcess()) {
michael@0 868 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
michael@0 869 }
michael@0 870 }
michael@0 871
michael@0 872 void SkProcXfermode::flatten(SkWriteBuffer& buffer) const {
michael@0 873 this->INHERITED::flatten(buffer);
michael@0 874 if (!buffer.isCrossProcess()) {
michael@0 875 buffer.writeFunctionPtr((void*)fProc);
michael@0 876 }
michael@0 877 }
michael@0 878
michael@0 879 #ifndef SK_IGNORE_TO_STRING
michael@0 880 void SkProcXfermode::toString(SkString* str) const {
michael@0 881 str->appendf("SkProcXfermode: %p", fProc);
michael@0 882 }
michael@0 883 #endif
michael@0 884
michael@0 885 //////////////////////////////////////////////////////////////////////////////
michael@0 886
michael@0 887 #if SK_SUPPORT_GPU
michael@0 888
michael@0 889 #include "GrEffect.h"
michael@0 890 #include "GrCoordTransform.h"
michael@0 891 #include "GrEffectUnitTest.h"
michael@0 892 #include "GrTBackendEffectFactory.h"
michael@0 893 #include "gl/GrGLEffect.h"
michael@0 894
michael@0 895 /**
michael@0 896 * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
michael@0 897 */
michael@0 898 class XferEffect : public GrEffect {
michael@0 899 public:
michael@0 900 static bool IsSupportedMode(SkXfermode::Mode mode) {
michael@0 901 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
michael@0 902 }
michael@0 903
michael@0 904 static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
michael@0 905 if (!IsSupportedMode(mode)) {
michael@0 906 return NULL;
michael@0 907 } else {
michael@0 908 AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
michael@0 909 return CreateEffectRef(effect);
michael@0 910 }
michael@0 911 }
michael@0 912
michael@0 913 virtual void getConstantColorComponents(GrColor* color,
michael@0 914 uint32_t* validFlags) const SK_OVERRIDE {
michael@0 915 *validFlags = 0;
michael@0 916 }
michael@0 917
michael@0 918 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
michael@0 919 return GrTBackendEffectFactory<XferEffect>::getInstance();
michael@0 920 }
michael@0 921
michael@0 922 static const char* Name() { return "XferEffect"; }
michael@0 923
michael@0 924 SkXfermode::Mode mode() const { return fMode; }
michael@0 925 const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
michael@0 926
michael@0 927 class GLEffect : public GrGLEffect {
michael@0 928 public:
michael@0 929 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
michael@0 930 : GrGLEffect(factory) {
michael@0 931 }
michael@0 932 virtual void emitCode(GrGLShaderBuilder* builder,
michael@0 933 const GrDrawEffect& drawEffect,
michael@0 934 EffectKey key,
michael@0 935 const char* outputColor,
michael@0 936 const char* inputColor,
michael@0 937 const TransformedCoordsArray& coords,
michael@0 938 const TextureSamplerArray& samplers) SK_OVERRIDE {
michael@0 939 SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
michael@0 940 const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
michael@0 941 const char* dstColor;
michael@0 942 if (backgroundTex) {
michael@0 943 dstColor = "bgColor";
michael@0 944 builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
michael@0 945 builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
michael@0 946 builder->fsCodeAppendf(";\n");
michael@0 947 } else {
michael@0 948 dstColor = builder->dstColor();
michael@0 949 }
michael@0 950 SkASSERT(NULL != dstColor);
michael@0 951
michael@0 952 // We don't try to optimize for this case at all
michael@0 953 if (NULL == inputColor) {
michael@0 954 builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
michael@0 955 inputColor = "ones";
michael@0 956 }
michael@0 957 builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
michael@0 958
michael@0 959 // These all perform src-over on the alpha channel.
michael@0 960 builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
michael@0 961 outputColor, inputColor, inputColor, dstColor);
michael@0 962
michael@0 963 switch (mode) {
michael@0 964 case SkXfermode::kOverlay_Mode:
michael@0 965 // Overlay is Hard-Light with the src and dst reversed
michael@0 966 HardLight(builder, outputColor, dstColor, inputColor);
michael@0 967 break;
michael@0 968 case SkXfermode::kDarken_Mode:
michael@0 969 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
michael@0 970 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
michael@0 971 outputColor,
michael@0 972 inputColor, dstColor, inputColor,
michael@0 973 dstColor, inputColor, dstColor);
michael@0 974 break;
michael@0 975 case SkXfermode::kLighten_Mode:
michael@0 976 builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
michael@0 977 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
michael@0 978 outputColor,
michael@0 979 inputColor, dstColor, inputColor,
michael@0 980 dstColor, inputColor, dstColor);
michael@0 981 break;
michael@0 982 case SkXfermode::kColorDodge_Mode:
michael@0 983 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'r');
michael@0 984 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'g');
michael@0 985 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'b');
michael@0 986 break;
michael@0 987 case SkXfermode::kColorBurn_Mode:
michael@0 988 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'r');
michael@0 989 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'g');
michael@0 990 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'b');
michael@0 991 break;
michael@0 992 case SkXfermode::kHardLight_Mode:
michael@0 993 HardLight(builder, outputColor, inputColor, dstColor);
michael@0 994 break;
michael@0 995 case SkXfermode::kSoftLight_Mode:
michael@0 996 builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
michael@0 997 builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
michael@0 998 builder->fsCodeAppendf("\t\t} else {\n");
michael@0 999 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'r');
michael@0 1000 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'g');
michael@0 1001 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'b');
michael@0 1002 builder->fsCodeAppendf("\t\t}\n");
michael@0 1003 break;
michael@0 1004 case SkXfermode::kDifference_Mode:
michael@0 1005 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
michael@0 1006 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
michael@0 1007 outputColor, inputColor, dstColor, inputColor, dstColor,
michael@0 1008 dstColor, inputColor);
michael@0 1009 break;
michael@0 1010 case SkXfermode::kExclusion_Mode:
michael@0 1011 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
michael@0 1012 "2.0 * %s.rgb * %s.rgb;\n",
michael@0 1013 outputColor, dstColor, inputColor, dstColor, inputColor);
michael@0 1014 break;
michael@0 1015 case SkXfermode::kMultiply_Mode:
michael@0 1016 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
michael@0 1017 "(1.0 - %s.a) * %s.rgb + "
michael@0 1018 "%s.rgb * %s.rgb;\n",
michael@0 1019 outputColor, inputColor, dstColor, dstColor, inputColor,
michael@0 1020 inputColor, dstColor);
michael@0 1021 break;
michael@0 1022 case SkXfermode::kHue_Mode: {
michael@0 1023 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
michael@0 1024 SkString setSat, setLum;
michael@0 1025 AddSatFunction(builder, &setSat);
michael@0 1026 AddLumFunction(builder, &setLum);
michael@0 1027 builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
michael@0 1028 dstColor, inputColor);
michael@0 1029 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
michael@0 1030 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
michael@0 1031 dstColor);
michael@0 1032 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
michael@0 1033 outputColor, inputColor, dstColor, dstColor, inputColor);
michael@0 1034 break;
michael@0 1035 }
michael@0 1036 case SkXfermode::kSaturation_Mode: {
michael@0 1037 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
michael@0 1038 SkString setSat, setLum;
michael@0 1039 AddSatFunction(builder, &setSat);
michael@0 1040 AddLumFunction(builder, &setLum);
michael@0 1041 builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
michael@0 1042 dstColor, inputColor);
michael@0 1043 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
michael@0 1044 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
michael@0 1045 dstColor);
michael@0 1046 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
michael@0 1047 outputColor, inputColor, dstColor, dstColor, inputColor);
michael@0 1048 break;
michael@0 1049 }
michael@0 1050 case SkXfermode::kColor_Mode: {
michael@0 1051 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
michael@0 1052 SkString setLum;
michael@0 1053 AddLumFunction(builder, &setLum);
michael@0 1054 builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
michael@0 1055 inputColor, dstColor);
michael@0 1056 builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
michael@0 1057 outputColor, setLum.c_str(), dstColor, inputColor);
michael@0 1058 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
michael@0 1059 outputColor, inputColor, dstColor, dstColor, inputColor);
michael@0 1060 break;
michael@0 1061 }
michael@0 1062 case SkXfermode::kLuminosity_Mode: {
michael@0 1063 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
michael@0 1064 SkString setLum;
michael@0 1065 AddLumFunction(builder, &setLum);
michael@0 1066 builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
michael@0 1067 inputColor, dstColor);
michael@0 1068 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
michael@0 1069 outputColor, setLum.c_str(), dstColor, inputColor);
michael@0 1070 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
michael@0 1071 outputColor, inputColor, dstColor, dstColor, inputColor);
michael@0 1072 break;
michael@0 1073 }
michael@0 1074 default:
michael@0 1075 GrCrash("Unknown XferEffect mode.");
michael@0 1076 break;
michael@0 1077 }
michael@0 1078 }
michael@0 1079
michael@0 1080 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
michael@0 1081 return drawEffect.castEffect<XferEffect>().mode();
michael@0 1082 }
michael@0 1083
michael@0 1084 private:
michael@0 1085 static void HardLight(GrGLShaderBuilder* builder,
michael@0 1086 const char* final,
michael@0 1087 const char* src,
michael@0 1088 const char* dst) {
michael@0 1089 static const char kComponents[] = {'r', 'g', 'b'};
michael@0 1090 for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
michael@0 1091 char component = kComponents[i];
michael@0 1092 builder->fsCodeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
michael@0 1093 builder->fsCodeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
michael@0 1094 builder->fsCodeAppend("\t\t} else {\n");
michael@0 1095 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
michael@0 1096 final, component, src, dst, dst, dst, component, src, src, component);
michael@0 1097 builder->fsCodeAppend("\t\t}\n");
michael@0 1098 }
michael@0 1099 builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
michael@0 1100 final, src, dst, dst, src);
michael@0 1101 }
michael@0 1102
michael@0 1103 // Does one component of color-dodge
michael@0 1104 static void ColorDodgeComponent(GrGLShaderBuilder* builder,
michael@0 1105 const char* final,
michael@0 1106 const char* src,
michael@0 1107 const char* dst,
michael@0 1108 const char component) {
michael@0 1109 builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
michael@0 1110 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
michael@0 1111 final, component, src, component, dst);
michael@0 1112 builder->fsCodeAppend("\t\t} else {\n");
michael@0 1113 builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
michael@0 1114 builder->fsCodeAppend("\t\t\tif (0.0 == d) {\n");
michael@0 1115 builder->fsCodeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
michael@0 1116 final, component, src, dst, src, component, dst, dst, component,
michael@0 1117 src);
michael@0 1118 builder->fsCodeAppend("\t\t\t} else {\n");
michael@0 1119 builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
michael@0 1120 dst, dst, component, src);
michael@0 1121 builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
michael@0 1122 final, component, src, src, component, dst, dst, component, src);
michael@0 1123 builder->fsCodeAppend("\t\t\t}\n");
michael@0 1124 builder->fsCodeAppend("\t\t}\n");
michael@0 1125 }
michael@0 1126
michael@0 1127 // Does one component of color-burn
michael@0 1128 static void ColorBurnComponent(GrGLShaderBuilder* builder,
michael@0 1129 const char* final,
michael@0 1130 const char* src,
michael@0 1131 const char* dst,
michael@0 1132 const char component) {
michael@0 1133 builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
michael@0 1134 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
michael@0 1135 final, component, src, dst, src, component, dst, dst, component,
michael@0 1136 src);
michael@0 1137 builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
michael@0 1138 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
michael@0 1139 final, component, dst, component, src);
michael@0 1140 builder->fsCodeAppend("\t\t} else {\n");
michael@0 1141 builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
michael@0 1142 dst, dst, dst, component, src, src, component);
michael@0 1143 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
michael@0 1144 final, component, src, src, component, dst, dst, component, src);
michael@0 1145 builder->fsCodeAppend("\t\t}\n");
michael@0 1146 }
michael@0 1147
michael@0 1148 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
michael@0 1149 static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder,
michael@0 1150 const char* final,
michael@0 1151 const char* src,
michael@0 1152 const char* dst,
michael@0 1153 const char component) {
michael@0 1154 // if (2S < Sa)
michael@0 1155 builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
michael@0 1156 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
michael@0 1157 builder->fsCodeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
michael@0 1158 final, component, dst, component, dst, component, src, src,
michael@0 1159 component, dst, dst, src, component, dst, component, src, src,
michael@0 1160 component);
michael@0 1161 // else if (4D < Da)
michael@0 1162 builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
michael@0 1163 dst, component, dst);
michael@0 1164 builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
michael@0 1165 dst, component, dst, component);
michael@0 1166 builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
michael@0 1167 builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
michael@0 1168 builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
michael@0 1169 // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
michael@0 1170 builder->fsCodeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
michael@0 1171 final, component, src, component, src, component, dst, component,
michael@0 1172 src, src, component, dst, src, src, component, src, src,
michael@0 1173 component);
michael@0 1174 builder->fsCodeAppendf("\t\t\t} else {\n");
michael@0 1175 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
michael@0 1176 builder->fsCodeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
michael@0 1177 final, component, dst, dst, component, src, src, component, dst,
michael@0 1178 src, component, dst, component, src, src, component, src,
michael@0 1179 component);
michael@0 1180 builder->fsCodeAppendf("\t\t\t}\n");
michael@0 1181 }
michael@0 1182
michael@0 1183 // Adds a function that takes two colors and an alpha as input. It produces a color with the
michael@0 1184 // hue and saturation of the first color, the luminosity of the second color, and the input
michael@0 1185 // alpha. It has this signature:
michael@0 1186 // vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
michael@0 1187 static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) {
michael@0 1188 // Emit a helper that gets the luminance of a color.
michael@0 1189 SkString getFunction;
michael@0 1190 GrGLShaderVar getLumArgs[] = {
michael@0 1191 GrGLShaderVar("color", kVec3f_GrSLType),
michael@0 1192 };
michael@0 1193 SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
michael@0 1194 builder->fsEmitFunction(kFloat_GrSLType,
michael@0 1195 "luminance",
michael@0 1196 SK_ARRAY_COUNT(getLumArgs), getLumArgs,
michael@0 1197 getLumBody.c_str(),
michael@0 1198 &getFunction);
michael@0 1199
michael@0 1200 // Emit the set luminance function.
michael@0 1201 GrGLShaderVar setLumArgs[] = {
michael@0 1202 GrGLShaderVar("hueSat", kVec3f_GrSLType),
michael@0 1203 GrGLShaderVar("alpha", kFloat_GrSLType),
michael@0 1204 GrGLShaderVar("lumColor", kVec3f_GrSLType),
michael@0 1205 };
michael@0 1206 SkString setLumBody;
michael@0 1207 setLumBody.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str());
michael@0 1208 setLumBody.append("\tvec3 outColor = hueSat + diff;\n");
michael@0 1209 setLumBody.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str());
michael@0 1210 setLumBody.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n"
michael@0 1211 "\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n"
michael@0 1212 "\tif (minComp < 0.0) {\n"
michael@0 1213 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n"
michael@0 1214 "\t}\n"
michael@0 1215 "\tif (maxComp > alpha) {\n"
michael@0 1216 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
michael@0 1217 "\t}\n"
michael@0 1218 "\treturn outColor;\n");
michael@0 1219 builder->fsEmitFunction(kVec3f_GrSLType,
michael@0 1220 "set_luminance",
michael@0 1221 SK_ARRAY_COUNT(setLumArgs), setLumArgs,
michael@0 1222 setLumBody.c_str(),
michael@0 1223 setLumFunction);
michael@0 1224 }
michael@0 1225
michael@0 1226 // Adds a function that creates a color with the hue and luminosity of one input color and
michael@0 1227 // the saturation of another color. It will have this signature:
michael@0 1228 // float set_saturation(vec3 hueLumColor, vec3 satColor)
michael@0 1229 static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) {
michael@0 1230 // Emit a helper that gets the saturation of a color
michael@0 1231 SkString getFunction;
michael@0 1232 GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
michael@0 1233 SkString getSatBody;
michael@0 1234 getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
michael@0 1235 "min(min(color.r, color.g), color.b);\n");
michael@0 1236 builder->fsEmitFunction(kFloat_GrSLType,
michael@0 1237 "saturation",
michael@0 1238 SK_ARRAY_COUNT(getSatArgs), getSatArgs,
michael@0 1239 getSatBody.c_str(),
michael@0 1240 &getFunction);
michael@0 1241
michael@0 1242 // Emit a helper that sets the saturation given sorted input channels. This used
michael@0 1243 // to use inout params for min, mid, and max components but that seems to cause
michael@0 1244 // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
michael@0 1245 // adjusted min, mid, and max inputs, respectively.
michael@0 1246 SkString helperFunction;
michael@0 1247 GrGLShaderVar helperArgs[] = {
michael@0 1248 GrGLShaderVar("minComp", kFloat_GrSLType),
michael@0 1249 GrGLShaderVar("midComp", kFloat_GrSLType),
michael@0 1250 GrGLShaderVar("maxComp", kFloat_GrSLType),
michael@0 1251 GrGLShaderVar("sat", kFloat_GrSLType),
michael@0 1252 };
michael@0 1253 static const char kHelperBody[] = "\tif (minComp < maxComp) {\n"
michael@0 1254 "\t\tvec3 result;\n"
michael@0 1255 "\t\tresult.r = 0.0;\n"
michael@0 1256 "\t\tresult.g = sat * (midComp - minComp) / (maxComp - minComp);\n"
michael@0 1257 "\t\tresult.b = sat;\n"
michael@0 1258 "\t\treturn result;\n"
michael@0 1259 "\t} else {\n"
michael@0 1260 "\t\treturn vec3(0, 0, 0);\n"
michael@0 1261 "\t}\n";
michael@0 1262 builder->fsEmitFunction(kVec3f_GrSLType,
michael@0 1263 "set_saturation_helper",
michael@0 1264 SK_ARRAY_COUNT(helperArgs), helperArgs,
michael@0 1265 kHelperBody,
michael@0 1266 &helperFunction);
michael@0 1267
michael@0 1268 GrGLShaderVar setSatArgs[] = {
michael@0 1269 GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
michael@0 1270 GrGLShaderVar("satColor", kVec3f_GrSLType),
michael@0 1271 };
michael@0 1272 const char* helpFunc = helperFunction.c_str();
michael@0 1273 SkString setSatBody;
michael@0 1274 setSatBody.appendf("\tfloat sat = %s(satColor);\n"
michael@0 1275 "\tif (hueLumColor.r <= hueLumColor.g) {\n"
michael@0 1276 "\t\tif (hueLumColor.g <= hueLumColor.b) {\n"
michael@0 1277 "\t\t\thueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n"
michael@0 1278 "\t\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
michael@0 1279 "\t\t\thueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n"
michael@0 1280 "\t\t} else {\n"
michael@0 1281 "\t\t\thueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);\n"
michael@0 1282 "\t\t}\n"
michael@0 1283 "\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
michael@0 1284 "\t\thueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n"
michael@0 1285 "\t} else if (hueLumColor.g <= hueLumColor.b) {\n"
michael@0 1286 "\t\thueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n"
michael@0 1287 "\t} else {\n"
michael@0 1288 "\t\thueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n"
michael@0 1289 "\t}\n"
michael@0 1290 "\treturn hueLumColor;\n",
michael@0 1291 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
michael@0 1292 helpFunc, helpFunc);
michael@0 1293 builder->fsEmitFunction(kVec3f_GrSLType,
michael@0 1294 "set_saturation",
michael@0 1295 SK_ARRAY_COUNT(setSatArgs), setSatArgs,
michael@0 1296 setSatBody.c_str(),
michael@0 1297 setSatFunction);
michael@0 1298
michael@0 1299 }
michael@0 1300
michael@0 1301 typedef GrGLEffect INHERITED;
michael@0 1302 };
michael@0 1303
michael@0 1304 GR_DECLARE_EFFECT_TEST;
michael@0 1305
michael@0 1306 private:
michael@0 1307 XferEffect(SkXfermode::Mode mode, GrTexture* background)
michael@0 1308 : fMode(mode) {
michael@0 1309 if (background) {
michael@0 1310 fBackgroundTransform.reset(kLocal_GrCoordSet, background);
michael@0 1311 this->addCoordTransform(&fBackgroundTransform);
michael@0 1312 fBackgroundAccess.reset(background);
michael@0 1313 this->addTextureAccess(&fBackgroundAccess);
michael@0 1314 } else {
michael@0 1315 this->setWillReadDstColor();
michael@0 1316 }
michael@0 1317 }
michael@0 1318 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
michael@0 1319 const XferEffect& s = CastEffect<XferEffect>(other);
michael@0 1320 return fMode == s.fMode &&
michael@0 1321 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
michael@0 1322 }
michael@0 1323
michael@0 1324 SkXfermode::Mode fMode;
michael@0 1325 GrCoordTransform fBackgroundTransform;
michael@0 1326 GrTextureAccess fBackgroundAccess;
michael@0 1327
michael@0 1328 typedef GrEffect INHERITED;
michael@0 1329 };
michael@0 1330
michael@0 1331 GR_DEFINE_EFFECT_TEST(XferEffect);
michael@0 1332 GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
michael@0 1333 GrContext*,
michael@0 1334 const GrDrawTargetCaps&,
michael@0 1335 GrTexture*[]) {
michael@0 1336 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
michael@0 1337
michael@0 1338 AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
michael@0 1339 return CreateEffectRef(gEffect);
michael@0 1340 }
michael@0 1341
michael@0 1342 #endif
michael@0 1343
michael@0 1344 ///////////////////////////////////////////////////////////////////////////////
michael@0 1345 ///////////////////////////////////////////////////////////////////////////////
michael@0 1346
michael@0 1347 SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
michael@0 1348 uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
michael@0 1349 if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
michael@0 1350 // out of range, just set to something harmless
michael@0 1351 mode32 = SkXfermode::kSrcOut_Mode;
michael@0 1352 }
michael@0 1353 fMode = (SkXfermode::Mode)mode32;
michael@0 1354
michael@0 1355 const ProcCoeff& rec = gProcCoeffs[fMode];
michael@0 1356 // these may be valid, or may be CANNOT_USE_COEFF
michael@0 1357 fSrcCoeff = rec.fSC;
michael@0 1358 fDstCoeff = rec.fDC;
michael@0 1359 // now update our function-ptr in the super class
michael@0 1360 this->INHERITED::setProc(rec.fProc);
michael@0 1361 }
michael@0 1362
michael@0 1363 bool SkProcCoeffXfermode::asMode(Mode* mode) const {
michael@0 1364 if (mode) {
michael@0 1365 *mode = fMode;
michael@0 1366 }
michael@0 1367 return true;
michael@0 1368 }
michael@0 1369
michael@0 1370 bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
michael@0 1371 if (CANNOT_USE_COEFF == fSrcCoeff) {
michael@0 1372 return false;
michael@0 1373 }
michael@0 1374
michael@0 1375 if (sc) {
michael@0 1376 *sc = fSrcCoeff;
michael@0 1377 }
michael@0 1378 if (dc) {
michael@0 1379 *dc = fDstCoeff;
michael@0 1380 }
michael@0 1381 return true;
michael@0 1382 }
michael@0 1383
michael@0 1384 #if SK_SUPPORT_GPU
michael@0 1385 bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
michael@0 1386 GrTexture* background) const {
michael@0 1387 if (XferEffect::IsSupportedMode(fMode)) {
michael@0 1388 if (NULL != effect) {
michael@0 1389 *effect = XferEffect::Create(fMode, background);
michael@0 1390 SkASSERT(NULL != *effect);
michael@0 1391 }
michael@0 1392 return true;
michael@0 1393 }
michael@0 1394 return false;
michael@0 1395 }
michael@0 1396 #endif
michael@0 1397
michael@0 1398 void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
michael@0 1399 this->INHERITED::flatten(buffer);
michael@0 1400 buffer.write32(fMode);
michael@0 1401 }
michael@0 1402
michael@0 1403 const char* SkXfermode::ModeName(Mode mode) {
michael@0 1404 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
michael@0 1405 const char* gModeStrings[] = {
michael@0 1406 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
michael@0 1407 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
michael@0 1408 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
michael@0 1409 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
michael@0 1410 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
michael@0 1411 };
michael@0 1412 return gModeStrings[mode];
michael@0 1413 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
michael@0 1414 }
michael@0 1415
michael@0 1416 #ifndef SK_IGNORE_TO_STRING
michael@0 1417 void SkProcCoeffXfermode::toString(SkString* str) const {
michael@0 1418 str->append("SkProcCoeffXfermode: ");
michael@0 1419
michael@0 1420 str->append("mode: ");
michael@0 1421 str->append(ModeName(fMode));
michael@0 1422
michael@0 1423 static const char* gCoeffStrings[kCoeffCount] = {
michael@0 1424 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
michael@0 1425 };
michael@0 1426
michael@0 1427 str->append(" src: ");
michael@0 1428 if (CANNOT_USE_COEFF == fSrcCoeff) {
michael@0 1429 str->append("can't use");
michael@0 1430 } else {
michael@0 1431 str->append(gCoeffStrings[fSrcCoeff]);
michael@0 1432 }
michael@0 1433
michael@0 1434 str->append(" dst: ");
michael@0 1435 if (CANNOT_USE_COEFF == fDstCoeff) {
michael@0 1436 str->append("can't use");
michael@0 1437 } else {
michael@0 1438 str->append(gCoeffStrings[fDstCoeff]);
michael@0 1439 }
michael@0 1440 }
michael@0 1441 #endif
michael@0 1442
michael@0 1443 ///////////////////////////////////////////////////////////////////////////////
michael@0 1444
michael@0 1445 class SkClearXfermode : public SkProcCoeffXfermode {
michael@0 1446 public:
michael@0 1447 static SkClearXfermode* Create(const ProcCoeff& rec) {
michael@0 1448 return SkNEW_ARGS(SkClearXfermode, (rec));
michael@0 1449 }
michael@0 1450
michael@0 1451 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
michael@0 1452 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
michael@0 1453
michael@0 1454 SK_TO_STRING_OVERRIDE()
michael@0 1455 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
michael@0 1456
michael@0 1457 private:
michael@0 1458 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
michael@0 1459 SkClearXfermode(SkReadBuffer& buffer)
michael@0 1460 : SkProcCoeffXfermode(buffer) {}
michael@0 1461
michael@0 1462 typedef SkProcCoeffXfermode INHERITED;
michael@0 1463 };
michael@0 1464
michael@0 1465 void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
michael@0 1466 const SkPMColor* SK_RESTRICT, int count,
michael@0 1467 const SkAlpha* SK_RESTRICT aa) const {
michael@0 1468 SkASSERT(dst && count >= 0);
michael@0 1469
michael@0 1470 if (NULL == aa) {
michael@0 1471 memset(dst, 0, count << 2);
michael@0 1472 } else {
michael@0 1473 for (int i = count - 1; i >= 0; --i) {
michael@0 1474 unsigned a = aa[i];
michael@0 1475 if (0xFF == a) {
michael@0 1476 dst[i] = 0;
michael@0 1477 } else if (a != 0) {
michael@0 1478 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
michael@0 1479 }
michael@0 1480 }
michael@0 1481 }
michael@0 1482 }
michael@0 1483 void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
michael@0 1484 const SkPMColor* SK_RESTRICT, int count,
michael@0 1485 const SkAlpha* SK_RESTRICT aa) const {
michael@0 1486 SkASSERT(dst && count >= 0);
michael@0 1487
michael@0 1488 if (NULL == aa) {
michael@0 1489 memset(dst, 0, count);
michael@0 1490 } else {
michael@0 1491 for (int i = count - 1; i >= 0; --i) {
michael@0 1492 unsigned a = aa[i];
michael@0 1493 if (0xFF == a) {
michael@0 1494 dst[i] = 0;
michael@0 1495 } else if (0 != a) {
michael@0 1496 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
michael@0 1497 }
michael@0 1498 }
michael@0 1499 }
michael@0 1500 }
michael@0 1501
michael@0 1502 #ifndef SK_IGNORE_TO_STRING
michael@0 1503 void SkClearXfermode::toString(SkString* str) const {
michael@0 1504 this->INHERITED::toString(str);
michael@0 1505 }
michael@0 1506 #endif
michael@0 1507
michael@0 1508 ///////////////////////////////////////////////////////////////////////////////
michael@0 1509
michael@0 1510 class SkSrcXfermode : public SkProcCoeffXfermode {
michael@0 1511 public:
michael@0 1512 static SkSrcXfermode* Create(const ProcCoeff& rec) {
michael@0 1513 return SkNEW_ARGS(SkSrcXfermode, (rec));
michael@0 1514 }
michael@0 1515
michael@0 1516 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
michael@0 1517 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
michael@0 1518
michael@0 1519 SK_TO_STRING_OVERRIDE()
michael@0 1520 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
michael@0 1521
michael@0 1522 private:
michael@0 1523 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
michael@0 1524 SkSrcXfermode(SkReadBuffer& buffer)
michael@0 1525 : SkProcCoeffXfermode(buffer) {}
michael@0 1526
michael@0 1527 typedef SkProcCoeffXfermode INHERITED;
michael@0 1528 };
michael@0 1529
michael@0 1530 void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
michael@0 1531 const SkPMColor* SK_RESTRICT src, int count,
michael@0 1532 const SkAlpha* SK_RESTRICT aa) const {
michael@0 1533 SkASSERT(dst && src && count >= 0);
michael@0 1534
michael@0 1535 if (NULL == aa) {
michael@0 1536 memcpy(dst, src, count << 2);
michael@0 1537 } else {
michael@0 1538 for (int i = count - 1; i >= 0; --i) {
michael@0 1539 unsigned a = aa[i];
michael@0 1540 if (a == 0xFF) {
michael@0 1541 dst[i] = src[i];
michael@0 1542 } else if (a != 0) {
michael@0 1543 dst[i] = SkFourByteInterp(src[i], dst[i], a);
michael@0 1544 }
michael@0 1545 }
michael@0 1546 }
michael@0 1547 }
michael@0 1548
michael@0 1549 void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
michael@0 1550 const SkPMColor* SK_RESTRICT src, int count,
michael@0 1551 const SkAlpha* SK_RESTRICT aa) const {
michael@0 1552 SkASSERT(dst && src && count >= 0);
michael@0 1553
michael@0 1554 if (NULL == aa) {
michael@0 1555 for (int i = count - 1; i >= 0; --i) {
michael@0 1556 dst[i] = SkToU8(SkGetPackedA32(src[i]));
michael@0 1557 }
michael@0 1558 } else {
michael@0 1559 for (int i = count - 1; i >= 0; --i) {
michael@0 1560 unsigned a = aa[i];
michael@0 1561 if (0 != a) {
michael@0 1562 unsigned srcA = SkGetPackedA32(src[i]);
michael@0 1563 if (a == 0xFF) {
michael@0 1564 dst[i] = SkToU8(srcA);
michael@0 1565 } else {
michael@0 1566 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
michael@0 1567 }
michael@0 1568 }
michael@0 1569 }
michael@0 1570 }
michael@0 1571 }
michael@0 1572 #ifndef SK_IGNORE_TO_STRING
michael@0 1573 void SkSrcXfermode::toString(SkString* str) const {
michael@0 1574 this->INHERITED::toString(str);
michael@0 1575 }
michael@0 1576 #endif
michael@0 1577
michael@0 1578 ///////////////////////////////////////////////////////////////////////////////
michael@0 1579
michael@0 1580 class SkDstInXfermode : public SkProcCoeffXfermode {
michael@0 1581 public:
michael@0 1582 static SkDstInXfermode* Create(const ProcCoeff& rec) {
michael@0 1583 return SkNEW_ARGS(SkDstInXfermode, (rec));
michael@0 1584 }
michael@0 1585
michael@0 1586 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
michael@0 1587
michael@0 1588 SK_TO_STRING_OVERRIDE()
michael@0 1589 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
michael@0 1590
michael@0 1591 private:
michael@0 1592 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
michael@0 1593 SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
michael@0 1594
michael@0 1595 typedef SkProcCoeffXfermode INHERITED;
michael@0 1596 };
michael@0 1597
michael@0 1598 void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
michael@0 1599 const SkPMColor* SK_RESTRICT src, int count,
michael@0 1600 const SkAlpha* SK_RESTRICT aa) const {
michael@0 1601 SkASSERT(dst && src);
michael@0 1602
michael@0 1603 if (count <= 0) {
michael@0 1604 return;
michael@0 1605 }
michael@0 1606 if (NULL != aa) {
michael@0 1607 return this->INHERITED::xfer32(dst, src, count, aa);
michael@0 1608 }
michael@0 1609
michael@0 1610 do {
michael@0 1611 unsigned a = SkGetPackedA32(*src);
michael@0 1612 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
michael@0 1613 dst++;
michael@0 1614 src++;
michael@0 1615 } while (--count != 0);
michael@0 1616 }
michael@0 1617
michael@0 1618 #ifndef SK_IGNORE_TO_STRING
michael@0 1619 void SkDstInXfermode::toString(SkString* str) const {
michael@0 1620 this->INHERITED::toString(str);
michael@0 1621 }
michael@0 1622 #endif
michael@0 1623
michael@0 1624 ///////////////////////////////////////////////////////////////////////////////
michael@0 1625
michael@0 1626 class SkDstOutXfermode : public SkProcCoeffXfermode {
michael@0 1627 public:
michael@0 1628 static SkDstOutXfermode* Create(const ProcCoeff& rec) {
michael@0 1629 return SkNEW_ARGS(SkDstOutXfermode, (rec));
michael@0 1630 }
michael@0 1631
michael@0 1632 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
michael@0 1633
michael@0 1634 SK_TO_STRING_OVERRIDE()
michael@0 1635 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
michael@0 1636
michael@0 1637 private:
michael@0 1638 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
michael@0 1639 SkDstOutXfermode(SkReadBuffer& buffer)
michael@0 1640 : INHERITED(buffer) {}
michael@0 1641
michael@0 1642 typedef SkProcCoeffXfermode INHERITED;
michael@0 1643 };
michael@0 1644
michael@0 1645 void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
michael@0 1646 const SkPMColor* SK_RESTRICT src, int count,
michael@0 1647 const SkAlpha* SK_RESTRICT aa) const {
michael@0 1648 SkASSERT(dst && src);
michael@0 1649
michael@0 1650 if (count <= 0) {
michael@0 1651 return;
michael@0 1652 }
michael@0 1653 if (NULL != aa) {
michael@0 1654 return this->INHERITED::xfer32(dst, src, count, aa);
michael@0 1655 }
michael@0 1656
michael@0 1657 do {
michael@0 1658 unsigned a = SkGetPackedA32(*src);
michael@0 1659 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
michael@0 1660 dst++;
michael@0 1661 src++;
michael@0 1662 } while (--count != 0);
michael@0 1663 }
michael@0 1664
michael@0 1665 #ifndef SK_IGNORE_TO_STRING
michael@0 1666 void SkDstOutXfermode::toString(SkString* str) const {
michael@0 1667 this->INHERITED::toString(str);
michael@0 1668 }
michael@0 1669 #endif
michael@0 1670
michael@0 1671 ///////////////////////////////////////////////////////////////////////////////
michael@0 1672
michael@0 1673 SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
michael@0 1674 static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1];
michael@0 1675
michael@0 1676 void SkXfermode::Term() {
michael@0 1677 SkAutoMutexAcquire ac(gCachedXfermodesMutex);
michael@0 1678
michael@0 1679 for (size_t i = 0; i < SK_ARRAY_COUNT(gCachedXfermodes); ++i) {
michael@0 1680 SkSafeUnref(gCachedXfermodes[i]);
michael@0 1681 gCachedXfermodes[i] = NULL;
michael@0 1682 }
michael@0 1683 }
michael@0 1684
michael@0 1685 extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
michael@0 1686 SkXfermode::Mode mode);
michael@0 1687 extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
michael@0 1688
michael@0 1689 SkXfermode* SkXfermode::Create(Mode mode) {
michael@0 1690 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
michael@0 1691 SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
michael@0 1692
michael@0 1693 if ((unsigned)mode >= kModeCount) {
michael@0 1694 // report error
michael@0 1695 return NULL;
michael@0 1696 }
michael@0 1697
michael@0 1698 // Skia's "defaut" mode is srcover. NULL in SkPaint is interpreted as srcover
michael@0 1699 // so we can just return NULL from the factory.
michael@0 1700 if (kSrcOver_Mode == mode) {
michael@0 1701 return NULL;
michael@0 1702 }
michael@0 1703
michael@0 1704 // guard our access to gCachedXfermodes, since we may write into it
michael@0 1705 SkAutoMutexAcquire ac(gCachedXfermodesMutex);
michael@0 1706
michael@0 1707 SkXfermode* xfer = gCachedXfermodes[mode];
michael@0 1708 if (NULL == xfer) {
michael@0 1709 ProcCoeff rec = gProcCoeffs[mode];
michael@0 1710
michael@0 1711 SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
michael@0 1712
michael@0 1713 if (pp != NULL) {
michael@0 1714 rec.fProc = pp;
michael@0 1715 }
michael@0 1716
michael@0 1717 // check if we have a platform optim for that
michael@0 1718 SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
michael@0 1719 if (xfm != NULL) {
michael@0 1720 xfer = xfm;
michael@0 1721 } else {
michael@0 1722 // All modes can in theory be represented by the ProcCoeff rec, since
michael@0 1723 // it contains function ptrs. However, a few modes are both simple and
michael@0 1724 // commonly used, so we call those out for their own subclasses here.
michael@0 1725 switch (mode) {
michael@0 1726 case kClear_Mode:
michael@0 1727 xfer = SkClearXfermode::Create(rec);
michael@0 1728 break;
michael@0 1729 case kSrc_Mode:
michael@0 1730 xfer = SkSrcXfermode::Create(rec);
michael@0 1731 break;
michael@0 1732 case kSrcOver_Mode:
michael@0 1733 SkASSERT(false); // should not land here
michael@0 1734 break;
michael@0 1735 case kDstIn_Mode:
michael@0 1736 xfer = SkDstInXfermode::Create(rec);
michael@0 1737 break;
michael@0 1738 case kDstOut_Mode:
michael@0 1739 xfer = SkDstOutXfermode::Create(rec);
michael@0 1740 break;
michael@0 1741 default:
michael@0 1742 // no special-case, just rely in the rec and its function-ptrs
michael@0 1743 xfer = SkProcCoeffXfermode::Create(rec, mode);
michael@0 1744 break;
michael@0 1745 }
michael@0 1746 }
michael@0 1747 gCachedXfermodes[mode] = xfer;
michael@0 1748 }
michael@0 1749 return SkSafeRef(xfer);
michael@0 1750 }
michael@0 1751
michael@0 1752 SkXfermodeProc SkXfermode::GetProc(Mode mode) {
michael@0 1753 SkXfermodeProc proc = NULL;
michael@0 1754 if ((unsigned)mode < kModeCount) {
michael@0 1755 proc = gProcCoeffs[mode].fProc;
michael@0 1756 }
michael@0 1757 return proc;
michael@0 1758 }
michael@0 1759
michael@0 1760 bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
michael@0 1761 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
michael@0 1762
michael@0 1763 if ((unsigned)mode >= (unsigned)kModeCount) {
michael@0 1764 // illegal mode parameter
michael@0 1765 return false;
michael@0 1766 }
michael@0 1767
michael@0 1768 const ProcCoeff& rec = gProcCoeffs[mode];
michael@0 1769
michael@0 1770 if (CANNOT_USE_COEFF == rec.fSC) {
michael@0 1771 return false;
michael@0 1772 }
michael@0 1773
michael@0 1774 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
michael@0 1775 if (src) {
michael@0 1776 *src = rec.fSC;
michael@0 1777 }
michael@0 1778 if (dst) {
michael@0 1779 *dst = rec.fDC;
michael@0 1780 }
michael@0 1781 return true;
michael@0 1782 }
michael@0 1783
michael@0 1784 bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
michael@0 1785 if (NULL == xfer) {
michael@0 1786 if (mode) {
michael@0 1787 *mode = kSrcOver_Mode;
michael@0 1788 }
michael@0 1789 return true;
michael@0 1790 }
michael@0 1791 return xfer->asMode(mode);
michael@0 1792 }
michael@0 1793
michael@0 1794 bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
michael@0 1795 if (NULL == xfer) {
michael@0 1796 return ModeAsCoeff(kSrcOver_Mode, src, dst);
michael@0 1797 }
michael@0 1798 return xfer->asCoeff(src, dst);
michael@0 1799 }
michael@0 1800
michael@0 1801 bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
michael@0 1802 // if xfer==null then the mode is srcover
michael@0 1803 Mode m = kSrcOver_Mode;
michael@0 1804 if (xfer && !xfer->asMode(&m)) {
michael@0 1805 return false;
michael@0 1806 }
michael@0 1807 return mode == m;
michael@0 1808 }
michael@0 1809
michael@0 1810 ///////////////////////////////////////////////////////////////////////////////
michael@0 1811 //////////// 16bit xfermode procs
michael@0 1812
michael@0 1813 #ifdef SK_DEBUG
michael@0 1814 static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
michael@0 1815 static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
michael@0 1816 #endif
michael@0 1817
michael@0 1818 static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1819 SkASSERT(require_255(src));
michael@0 1820 return SkPixel32ToPixel16(src);
michael@0 1821 }
michael@0 1822
michael@0 1823 static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
michael@0 1824 return dst;
michael@0 1825 }
michael@0 1826
michael@0 1827 static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
michael@0 1828 SkASSERT(require_0(src));
michael@0 1829 return dst;
michael@0 1830 }
michael@0 1831
michael@0 1832 static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1833 SkASSERT(require_255(src));
michael@0 1834 return SkPixel32ToPixel16(src);
michael@0 1835 }
michael@0 1836
michael@0 1837 static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
michael@0 1838 SkASSERT(require_0(src));
michael@0 1839 return dst;
michael@0 1840 }
michael@0 1841
michael@0 1842 static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1843 SkASSERT(require_255(src));
michael@0 1844 return dst;
michael@0 1845 }
michael@0 1846
michael@0 1847 static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1848 SkASSERT(require_255(src));
michael@0 1849 return SkPixel32ToPixel16(src);
michael@0 1850 }
michael@0 1851
michael@0 1852 static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1853 SkASSERT(require_255(src));
michael@0 1854 return dst;
michael@0 1855 }
michael@0 1856
michael@0 1857 static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
michael@0 1858 SkASSERT(require_0(src));
michael@0 1859 return dst;
michael@0 1860 }
michael@0 1861
michael@0 1862 static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
michael@0 1863 unsigned isa = 255 - SkGetPackedA32(src);
michael@0 1864
michael@0 1865 return SkPackRGB16(
michael@0 1866 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
michael@0 1867 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
michael@0 1868 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
michael@0 1869 }
michael@0 1870
michael@0 1871 static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
michael@0 1872 SkASSERT(require_0(src));
michael@0 1873 return dst;
michael@0 1874 }
michael@0 1875
michael@0 1876 static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1877 SkASSERT(require_255(src));
michael@0 1878 return SkPixel32ToPixel16(src);
michael@0 1879 }
michael@0 1880
michael@0 1881 static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1882 SkASSERT(require_255(src));
michael@0 1883 return dst;
michael@0 1884 }
michael@0 1885
michael@0 1886 /*********
michael@0 1887 darken and lighten boil down to this.
michael@0 1888
michael@0 1889 darken = (1 - Sa) * Dc + min(Sc, Dc)
michael@0 1890 lighten = (1 - Sa) * Dc + max(Sc, Dc)
michael@0 1891
michael@0 1892 if (Sa == 0) these become
michael@0 1893 darken = Dc + min(0, Dc) = 0
michael@0 1894 lighten = Dc + max(0, Dc) = Dc
michael@0 1895
michael@0 1896 if (Sa == 1) these become
michael@0 1897 darken = min(Sc, Dc)
michael@0 1898 lighten = max(Sc, Dc)
michael@0 1899 */
michael@0 1900
michael@0 1901 static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
michael@0 1902 SkASSERT(require_0(src));
michael@0 1903 return 0;
michael@0 1904 }
michael@0 1905
michael@0 1906 static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1907 SkASSERT(require_255(src));
michael@0 1908 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
michael@0 1909 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
michael@0 1910 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
michael@0 1911 return SkPackRGB16(r, g, b);
michael@0 1912 }
michael@0 1913
michael@0 1914 static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
michael@0 1915 SkASSERT(require_0(src));
michael@0 1916 return dst;
michael@0 1917 }
michael@0 1918
michael@0 1919 static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
michael@0 1920 SkASSERT(require_255(src));
michael@0 1921 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
michael@0 1922 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
michael@0 1923 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
michael@0 1924 return SkPackRGB16(r, g, b);
michael@0 1925 }
michael@0 1926
michael@0 1927 struct Proc16Rec {
michael@0 1928 SkXfermodeProc16 fProc16_0;
michael@0 1929 SkXfermodeProc16 fProc16_255;
michael@0 1930 SkXfermodeProc16 fProc16_General;
michael@0 1931 };
michael@0 1932
michael@0 1933 static const Proc16Rec gModeProcs16[] = {
michael@0 1934 { NULL, NULL, NULL }, // CLEAR
michael@0 1935 { NULL, src_modeproc16_255, NULL },
michael@0 1936 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
michael@0 1937 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
michael@0 1938 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
michael@0 1939 { NULL, srcin_modeproc16_255, NULL },
michael@0 1940 { NULL, dstin_modeproc16_255, NULL },
michael@0 1941 { NULL, NULL, NULL },// SRC_OUT
michael@0 1942 { dstout_modeproc16_0, NULL, NULL },
michael@0 1943 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
michael@0 1944 { NULL, dstatop_modeproc16_255, NULL },
michael@0 1945 { NULL, NULL, NULL }, // XOR
michael@0 1946
michael@0 1947 { NULL, NULL, NULL }, // plus
michael@0 1948 { NULL, NULL, NULL }, // modulate
michael@0 1949 { NULL, NULL, NULL }, // screen
michael@0 1950 { NULL, NULL, NULL }, // overlay
michael@0 1951 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
michael@0 1952 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
michael@0 1953 { NULL, NULL, NULL }, // colordodge
michael@0 1954 { NULL, NULL, NULL }, // colorburn
michael@0 1955 { NULL, NULL, NULL }, // hardlight
michael@0 1956 { NULL, NULL, NULL }, // softlight
michael@0 1957 { NULL, NULL, NULL }, // difference
michael@0 1958 { NULL, NULL, NULL }, // exclusion
michael@0 1959 { NULL, NULL, NULL }, // multiply
michael@0 1960 { NULL, NULL, NULL }, // hue
michael@0 1961 { NULL, NULL, NULL }, // saturation
michael@0 1962 { NULL, NULL, NULL }, // color
michael@0 1963 { NULL, NULL, NULL }, // luminosity
michael@0 1964 };
michael@0 1965
michael@0 1966 SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
michael@0 1967 SkXfermodeProc16 proc16 = NULL;
michael@0 1968 if ((unsigned)mode < kModeCount) {
michael@0 1969 const Proc16Rec& rec = gModeProcs16[mode];
michael@0 1970 unsigned a = SkColorGetA(srcColor);
michael@0 1971
michael@0 1972 if (0 == a) {
michael@0 1973 proc16 = rec.fProc16_0;
michael@0 1974 } else if (255 == a) {
michael@0 1975 proc16 = rec.fProc16_255;
michael@0 1976 } else {
michael@0 1977 proc16 = rec.fProc16_General;
michael@0 1978 }
michael@0 1979 }
michael@0 1980 return proc16;
michael@0 1981 }
michael@0 1982
michael@0 1983 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
michael@0 1984 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
michael@0 1985 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
michael@0 1986 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
michael@0 1987 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
michael@0 1988 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
michael@0 1989 #if !SK_ARM_NEON_IS_NONE
michael@0 1990 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkNEONProcCoeffXfermode)
michael@0 1991 #endif
michael@0 1992 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END

mercurial