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
This commit is contained in:
commit-bot@chromium.org 2013-03-21 12:40:08 +00:00
parent c1641fc922
commit 311d4eafab

View File

@ -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;