Sat, 03 Jan 2015 20:18:00 +0100
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 |