diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-21 12:40:08 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-21 12:40:08 +0000 |
commit | 311d4eafab513adae3ef6c37dd4d573844bccd63 (patch) | |
tree | f34a5b0452289bc36333ed310e3fd553335c2a17 | |
parent | c1641fc92259a1ca5cfc32cd5c8c55ea316b2bd1 (diff) |
This changes fixes issues with the non-separable blend modes. They were not producing the correct results if alpha was involved.
I fixed the math so everything happens in premultiplied alpha so there is no loss in precision.
I also fixed the math of color-burn and color-dodge.
Author: cabanier@gmail.com
Reviewed By: reed@google.com
Review URL: https://chromiumcodereview.appspot.com/12662006
git-svn-id: http://skia.googlecode.com/svn/trunk@8283 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | src/core/SkXfermode.cpp | 115 |
1 files changed, 43 insertions, 72 deletions
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 9f4153ddf6..de18c26fd1 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -290,57 +290,41 @@ static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) { static inline int colordodge_byte(int sc, int dc, int sa, int da) { int diff = sa - sc; int rc; - if (0 == diff) { + if (0 == dc) { + return SkAlphaMulAlpha(sc, 255 - da); + } else if (0 == diff) { rc = sa * da + sc * (255 - da) + dc * (255 - sa); - rc = SkDiv255Round(rc); } else { - int tmp = (dc * sa << 15) / (da * diff); - rc = SkDiv255Round(sa * da) * tmp >> 15; - // don't clamp here, since we'll do it in our modeproc + diff = dc * sa / diff; + rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa); } - return rc; + return clamp_div255round(rc); } static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) { - // added to avoid div-by-zero in colordodge_byte - if (0 == dst) { - return src; - } - int sa = SkGetPackedA32(src); int da = SkGetPackedA32(dst); int a = srcover_byte(sa, da); int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - r = clamp_max(r, a); - g = clamp_max(g, a); - b = clamp_max(b, a); return SkPackARGB32(a, r, g, b); } // kColorBurn_Mode static inline int colorburn_byte(int sc, int dc, int sa, int da) { int rc; - if (dc == da && 0 == sc) { - rc = sa * da + dc * (255 - sa); + if (dc == da) { + rc = sa * da + sc * (255 - da) + dc * (255 - sa); } else if (0 == sc) { return SkAlphaMulAlpha(dc, 255 - sa); } else { - int tmp = (sa * (da - dc) * 256) / (sc * da); - if (tmp > 256) { - tmp = 256; - } - int tmp2 = sa * da; - rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa); + int tmp = (da - dc) * sa / sc; + rc = sa * (da - ((da < tmp) ? da : tmp)) + + sc * (255 - da) + dc * (255 - sa); } - return SkDiv255Round(rc); + return clamp_div255round(rc); } static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { - // added to avoid div-by-zero in colorburn_byte - if (0 == dst) { - return src; - } - int sa = SkGetPackedA32(src); int da = SkGetPackedA32(dst); int a = srcover_byte(sa, da); @@ -438,7 +422,7 @@ static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { // See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm static inline int Lum(int r, int g, int b) { - return (r * 77 + g * 151 + b * 28) >> 8; + return SkDiv255Round(r * 77 + g * 150 + b * 28); } static inline int min2(int a, int b) { return a < b ? a : b; } @@ -452,7 +436,7 @@ static inline int Sat(int r, int g, int b) { static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) { if(*Cmax > *Cmin) { - *Cmid = (((*Cmid - *Cmin) * s ) / (*Cmax - *Cmin)); + *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin); *Cmax = s; } else { *Cmax = 0; @@ -480,35 +464,35 @@ static inline void SetSat(int* r, int* g, int* b, int s) { } } -static inline void clipColor(int* r, int* g, int* b) { +static inline void clipColor(int* r, int* g, int* b, int a) { int L = Lum(*r, *g, *b); int n = minimum(*r, *g, *b); int x = maximum(*r, *g, *b); if(n < 0) { - *r = L + (((*r - L) * L) / (L - n)); - *g = L + (((*g - L) * L) / (L - n)); - *b = L + (((*b - L) * L) / (L - n)); + *r = L + SkMulDiv(*r - L, L, L - n); + *g = L + SkMulDiv(*g - L, L, L - n); + *b = L + SkMulDiv(*b - L, L, L - n); } - if(x > 255) { - *r = L + (((*r - L) * (255 - L)) / (x - L)); - *g = L + (((*g - L) * (255 - L)) / (x - L)); - *b = L + (((*b - L) * (255 - L)) / (x - L)); + if (x > a) { + *r = L + SkMulDiv(*r - L, a - L, x - L); + *g = L + SkMulDiv(*g - L, a - L, x - L); + *b = L + SkMulDiv(*b - L, a - L, x - L); } } -static inline void SetLum(int* r, int* g, int* b, int l) { +static inline void SetLum(int* r, int* g, int* b, int a, int l) { int d = l - Lum(*r, *g, *b); *r += d; *g += d; *b += d; - clipColor(r, g, b); + clipColor(r, g, b, a); } // non-separable blend modes are done in non-premultiplied alpha #define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \ - clamp_div255round(sc * (255 - da) + dc * (255 - sa) + clamp_div255round(sa * da) * blendval) + clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval) // kHue_Mode // B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)) @@ -526,14 +510,11 @@ static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) { int Sr, Sg, Sb; if(sa && da) { - Sr = SkMulDiv255Round(sr, sa); - Sg = SkMulDiv255Round(sg, sa); - Sb = SkMulDiv255Round(sb, sa); - int Dr = SkMulDiv255Round(dr, da); - int Dg = SkMulDiv255Round(dg, da); - int Db = SkMulDiv255Round(db, da); - SetSat(&Sr, &Sg, &Sb, Sat(Dr, Dg, Db)); - SetLum(&Sr, &Sg, &Sb, Lum(Dr, Dg, Db)); + Sr = sr * sa; + Sg = sg * sa; + Sb = sb * sa; + SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa); + SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa); } else { Sr = 0; Sg = 0; @@ -563,15 +544,11 @@ static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) { int Dr, Dg, Db; if(sa && da) { - int Sr = SkMulDiv255Round(sr, sa); - int Sg = SkMulDiv255Round(sg, sa); - int Sb = SkMulDiv255Round(sb, sa); - Dr = SkMulDiv255Round(dr, da); - Dg = SkMulDiv255Round(dg, da); - Db = SkMulDiv255Round(db, da); - int LumD = Lum(Dr, Dg, Db); - SetSat(&Dr, &Dg, &Db, Sat(Sr, Sg, Sb)); - SetLum(&Dr, &Dg, &Db, LumD); + Dr = dr * sa; + Dg = dg * sa; + Db = db * sa; + SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da); + SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa); } else { Dr = 0; Dg = 0; @@ -601,13 +578,10 @@ static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) { int Sr, Sg, Sb; if(sa && da) { - Sr = SkMulDiv255Round(sr, sa); - Sg = SkMulDiv255Round(sg, sa); - Sb = SkMulDiv255Round(sb, sa); - int Dr = SkMulDiv255Round(dr, da); - int Dg = SkMulDiv255Round(dg, da); - int Db = SkMulDiv255Round(db, da); - SetLum(&Sr, &Sg, &Sb, Lum(Dr, Dg, Db)); + Sr = sr * da; + Sg = sg * da; + Sb = sb * da; + SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa); } else { Sr = 0; Sg = 0; @@ -637,13 +611,10 @@ static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) { int Dr, Dg, Db; if(sa && da) { - int Sr = SkMulDiv255Round(sr, sa); - int Sg = SkMulDiv255Round(sg, sa); - int Sb = SkMulDiv255Round(sb, sa); - Dr = SkMulDiv255Round(dr, da); - Dg = SkMulDiv255Round(dg, da); - Db = SkMulDiv255Round(db, da); - SetLum(&Dr, &Dg, &Db, Lum(Sr, Sg, Sb)); + Dr = dr * sa; + Dg = dg * sa; + Db = db * sa; + SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da); } else { Dr = 0; Dg = 0; |