implement more xfermodeproc4f and add GM

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1677293004

Review URL: https://codereview.chromium.org/1684623002
This commit is contained in:
reed 2016-02-09 11:59:24 -08:00 committed by Commit bot
parent 85dc359f74
commit e712532988
2 changed files with 488 additions and 136 deletions

View File

@ -10,7 +10,69 @@
#include "SkShader.h"
#include "SkXfermode.h"
namespace skiagm {
enum SrcType {
//! A WxH image with a rectangle in the lower right.
kRectangleImage_SrcType = 0x01,
//! kRectangleImage_SrcType with an alpha of 34.5%.
kRectangleImageWithAlpha_SrcType = 0x02,
//! kRectnagleImageWithAlpha_SrcType scaled down by half.
kSmallRectangleImageWithAlpha_SrcType = 0x04,
//! kRectangleImage_SrcType drawn directly instead in an image.
kRectangle_SrcType = 0x08,
//! Two rectangles, first on the right half, second on the bottom half.
kQuarterClear_SrcType = 0x10,
//! kQuarterClear_SrcType in a layer.
kQuarterClearInLayer_SrcType = 0x20,
//! A W/2xH/2 transparent image.
kSmallTransparentImage_SrcType = 0x40,
//! kRectangleImage_SrcType drawn directly with a mask.
kRectangleWithMask_SrcType = 0x80,
kAll_SrcType = 0xFF, //!< All the source types.
kBasic_SrcType = 0x03, //!< Just basic source types.
};
const struct {
SkXfermode::Mode fMode;
const char* fLabel;
int fSourceTypeMask; // The source types to use this
// mode with. See draw_mode for
// an explanation of each type.
// PDF has to play some tricks
// to support the base modes,
// test those more extensively.
} gModes[] = {
{ SkXfermode::kClear_Mode, "Clear", kAll_SrcType },
{ SkXfermode::kSrc_Mode, "Src", kAll_SrcType },
{ SkXfermode::kDst_Mode, "Dst", kAll_SrcType },
{ SkXfermode::kSrcOver_Mode, "SrcOver", kAll_SrcType },
{ SkXfermode::kDstOver_Mode, "DstOver", kAll_SrcType },
{ SkXfermode::kSrcIn_Mode, "SrcIn", kAll_SrcType },
{ SkXfermode::kDstIn_Mode, "DstIn", kAll_SrcType },
{ SkXfermode::kSrcOut_Mode, "SrcOut", kAll_SrcType },
{ SkXfermode::kDstOut_Mode, "DstOut", kAll_SrcType },
{ SkXfermode::kSrcATop_Mode, "SrcATop", kAll_SrcType },
{ SkXfermode::kDstATop_Mode, "DstATop", kAll_SrcType },
{ SkXfermode::kXor_Mode, "Xor", kBasic_SrcType },
{ SkXfermode::kPlus_Mode, "Plus", kBasic_SrcType },
{ SkXfermode::kModulate_Mode, "Modulate", kAll_SrcType },
{ SkXfermode::kScreen_Mode, "Screen", kBasic_SrcType },
{ SkXfermode::kOverlay_Mode, "Overlay", kBasic_SrcType },
{ SkXfermode::kDarken_Mode, "Darken", kBasic_SrcType },
{ SkXfermode::kLighten_Mode, "Lighten", kBasic_SrcType },
{ SkXfermode::kColorDodge_Mode, "ColorDodge", kBasic_SrcType },
{ SkXfermode::kColorBurn_Mode, "ColorBurn", kBasic_SrcType },
{ SkXfermode::kHardLight_Mode, "HardLight", kBasic_SrcType },
{ SkXfermode::kSoftLight_Mode, "SoftLight", kBasic_SrcType },
{ SkXfermode::kDifference_Mode, "Difference", kBasic_SrcType },
{ SkXfermode::kExclusion_Mode, "Exclusion", kBasic_SrcType },
{ SkXfermode::kMultiply_Mode, "Multiply", kAll_SrcType },
{ SkXfermode::kHue_Mode, "Hue", kBasic_SrcType },
{ SkXfermode::kSaturation_Mode, "Saturation", kBasic_SrcType },
{ SkXfermode::kColor_Mode, "Color", kBasic_SrcType },
{ SkXfermode::kLuminosity_Mode, "Luminosity", kBasic_SrcType },
};
static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
SkBitmap* transparent) {
@ -47,29 +109,7 @@ static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
class XfermodesGM : public GM {
enum SrcType {
//! A WxH image with a rectangle in the lower right.
kRectangleImage_SrcType = 0x01,
//! kRectangleImage_SrcType with an alpha of 34.5%.
kRectangleImageWithAlpha_SrcType = 0x02,
//! kRectnagleImageWithAlpha_SrcType scaled down by half.
kSmallRectangleImageWithAlpha_SrcType = 0x04,
//! kRectangleImage_SrcType drawn directly instead in an image.
kRectangle_SrcType = 0x08,
//! Two rectangles, first on the right half, second on the bottom half.
kQuarterClear_SrcType = 0x10,
//! kQuarterClear_SrcType in a layer.
kQuarterClearInLayer_SrcType = 0x20,
//! A W/2xH/2 transparent image.
kSmallTransparentImage_SrcType = 0x40,
//! kRectangleImage_SrcType drawn directly with a mask.
kRectangleWithMask_SrcType = 0x80,
kAll_SrcType = 0xFF, //!< All the source types.
kBasic_SrcType = 0x03, //!< Just basic source types.
};
class XfermodesGM : public skiagm::GM {
SkBitmap fBG;
SkBitmap fSrcB, fDstB, fTransparent;
@ -179,48 +219,6 @@ protected:
void onDraw(SkCanvas* canvas) override {
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
const struct {
SkXfermode::Mode fMode;
const char* fLabel;
int fSourceTypeMask; // The source types to use this
// mode with. See draw_mode for
// an explanation of each type.
// PDF has to play some tricks
// to support the base modes,
// test those more extensively.
} gModes[] = {
{ SkXfermode::kClear_Mode, "Clear", kAll_SrcType },
{ SkXfermode::kSrc_Mode, "Src", kAll_SrcType },
{ SkXfermode::kDst_Mode, "Dst", kAll_SrcType },
{ SkXfermode::kSrcOver_Mode, "SrcOver", kAll_SrcType },
{ SkXfermode::kDstOver_Mode, "DstOver", kAll_SrcType },
{ SkXfermode::kSrcIn_Mode, "SrcIn", kAll_SrcType },
{ SkXfermode::kDstIn_Mode, "DstIn", kAll_SrcType },
{ SkXfermode::kSrcOut_Mode, "SrcOut", kAll_SrcType },
{ SkXfermode::kDstOut_Mode, "DstOut", kAll_SrcType },
{ SkXfermode::kSrcATop_Mode, "SrcATop", kAll_SrcType },
{ SkXfermode::kDstATop_Mode, "DstATop", kAll_SrcType },
{ SkXfermode::kXor_Mode, "Xor", kBasic_SrcType },
{ SkXfermode::kPlus_Mode, "Plus", kBasic_SrcType },
{ SkXfermode::kModulate_Mode, "Modulate", kAll_SrcType },
{ SkXfermode::kScreen_Mode, "Screen", kBasic_SrcType },
{ SkXfermode::kOverlay_Mode, "Overlay", kBasic_SrcType },
{ SkXfermode::kDarken_Mode, "Darken", kBasic_SrcType },
{ SkXfermode::kLighten_Mode, "Lighten", kBasic_SrcType },
{ SkXfermode::kColorDodge_Mode, "ColorDodge", kBasic_SrcType },
{ SkXfermode::kColorBurn_Mode, "ColorBurn", kBasic_SrcType },
{ SkXfermode::kHardLight_Mode, "HardLight", kBasic_SrcType },
{ SkXfermode::kSoftLight_Mode, "SoftLight", kBasic_SrcType },
{ SkXfermode::kDifference_Mode, "Difference", kBasic_SrcType },
{ SkXfermode::kExclusion_Mode, "Exclusion", kBasic_SrcType },
{ SkXfermode::kMultiply_Mode, "Multiply", kAll_SrcType },
{ SkXfermode::kHue_Mode, "Hue", kBasic_SrcType },
{ SkXfermode::kSaturation_Mode, "Saturation", kBasic_SrcType },
{ SkXfermode::kColor_Mode, "Color", kBasic_SrcType },
{ SkXfermode::kLuminosity_Mode, "Luminosity", kBasic_SrcType },
};
const SkScalar w = SkIntToScalar(W);
const SkScalar h = SkIntToScalar(H);
SkMatrix m;
@ -291,10 +289,129 @@ protected:
private:
typedef GM INHERITED;
};
DEF_GM( return new XfermodesGM; )
//////////////////////////////////////////////////////////////////////////////
static GM* MyFactory(void*) { return new XfermodesGM; }
static GMRegistry reg(MyFactory);
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "SkNx.h"
static SkPMColor apply_proc(SkPMColor src, SkPMColor dst, SkXfermodeProc4f proc, float src_alpha) {
SkPM4f src4 = SkPM4f::FromPMColor(src);
for (int i = 0; i < 4; ++i) {
src4.fVec[i] *= src_alpha;
}
SkPM4f dst4 = SkPM4f::FromPMColor(dst);
SkPM4f res4 = proc(src4, dst4);
SkPMColor res;
SkNx_cast<uint8_t>(Sk4f::Load(res4.fVec) * Sk4f(255) + Sk4f(0.5f)).store(&res);
return res;
}
static bool apply_mode(const SkPixmap& res, const SkPixmap& src, const SkPixmap& dst,
SkXfermode* xfer, float src_alpha) {
SkXfermode::Mode mode;
if (!xfer) {
mode = SkXfermode::kSrcOver_Mode;
} else if (!xfer->asMode(&mode)) {
return false;
}
SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode);
if (!proc) {
return false;
}
for (int y = 0; y < res.height(); ++y) {
for (int x = 0; x < res.width(); ++x) {
*res.writable_addr32(x, y) = apply_proc(*src.addr32(x, y), *dst.addr32(x, y),
proc, src_alpha);
}
}
return true;
}
void draw_mode(const SkBitmap& srcB, const SkBitmap& dstB,
SkCanvas* canvas, SkXfermode* mode, SkScalar x, SkScalar y, float src_alpha) {
SkBitmap resB;
resB.allocN32Pixels(64, 64);
SkPixmap srcPM, dstPM, resPM;
srcB.peekPixels(&srcPM);
dstB.peekPixels(&dstPM);
resB.peekPixels(&resPM);
if (apply_mode(resPM, srcPM, dstPM, mode, src_alpha)) {
canvas->drawBitmap(resB, x, y, nullptr);
}
}
DEF_SIMPLE_GM(xfermodes_proc4f, canvas, 1000, 1000) {
SkBitmap bg, srcB, dstB, transparent;
bg.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType, kOpaque_SkAlphaType),
gData, 4);
make_bitmaps(64, 64, &dstB, &srcB, &transparent);
canvas->translate(10, 20);
const SkScalar w = 64;
const SkScalar h = 64;
SkMatrix m = SkMatrix::MakeScale(6, 6);
SkShader* s = SkShader::CreateBitmapShader(bg,
SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode,
&m);
SkPaint labelP;
labelP.setAntiAlias(true);
sk_tool_utils::set_portable_typeface(&labelP);
labelP.setTextAlign(SkPaint::kCenter_Align);
const int W = 5;
const float alphas[] = { 1.0f, 0.5f };
for (auto alpha : alphas) {
SkScalar x0 = 0;
SkScalar y0 = 0;
SkScalar x = x0, y = y0;
for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
SkAutoUnref aur(mode);
SkRect r;
r.set(x, y, x+w, y+h);
SkPaint p;
p.setStyle(SkPaint::kFill_Style);
p.setShader(s);
canvas->drawRect(r, p);
draw_mode(srcB, dstB, canvas, mode, r.fLeft, r.fTop, alpha);
r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
p.setStyle(SkPaint::kStroke_Style);
p.setShader(nullptr);
canvas->drawRect(r, p);
#if 1
canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
x + w/2, y - labelP.getTextSize()/2, labelP);
#endif
x += w + SkIntToScalar(10);
if ((i % W) == W - 1) {
x = x0;
y += h + SkIntToScalar(30);
}
}
if (y < 320) {
if (x > x0) {
y += h + SkIntToScalar(30);
}
y0 = y;
} else {
x0 += SkIntToScalar(400);
y0 = 0;
}
canvas->translate(400, 0);
}
s->unref();
}

View File

@ -53,6 +53,21 @@ static Sk4f alpha(const Sk4f& color) { return Sk4f(color.kth<3>()); }
static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color.kth<3>()); }
static Sk4f pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); }
static Sk4f color_alpha(const Sk4f& color, float newAlpha) {
return Sk4f(color.kth<0>(), color.kth<1>(), color.kth<2>(), newAlpha);
}
static Sk4f color_alpha(const Sk4f& color, const Sk4f& newAlpha) {
return color_alpha(color, newAlpha.kth<3>());
}
static Sk4f set_argb(float a, float r, float g, float b) {
if (0 == SkPM4f::R) {
return Sk4f(r, g, b, a);
} else {
return Sk4f(b, g, r, a);
}
}
static Sk4f clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); }
static Sk4f src_4f(const Sk4f& s, const Sk4f& d) { return s; }
static Sk4f dst_4f(const Sk4f& s, const Sk4f& d) { return d; }
@ -73,29 +88,264 @@ static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) {
return s * inv_alpha(d) + d * inv_alpha(s) + s * d;
}
///////////////////////////////////////////////////////////////////////////////
static SkPM4f as_pm4f(const Sk4f& x) {
SkPM4f pm4;
x.store(pm4.fVec);
return pm4;
static Sk4f overlay_4f(const Sk4f& s, const Sk4f& d) {
Sk4f sa = alpha(s);
Sk4f da = alpha(d);
Sk4f two = Sk4f(2);
Sk4f rc = (two * d <= da).thenElse(two * s * d,
sa * da - two * (da - d) * (sa - s));
return s + d - s * da + color_alpha(rc - d * sa, 0);
}
static Sk4f as_4f(const SkPM4f& pm4) {
return Sk4f::Load(pm4.fVec);
static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) {
return overlay_4f(d, s);
}
template <Sk4f (blend)(const Sk4f&, const Sk4f&)>
SkPM4f proc_4f(const SkPM4f& src, const SkPM4f& dst) {
return as_pm4f(blend(as_4f(src), as_4f(dst)));
static Sk4f darken_4f(const Sk4f& s, const Sk4f& d) {
Sk4f sa = alpha(s);
Sk4f da = alpha(d);
return s + d - Sk4f::Max(s * da, d * sa);
}
static Sk4f lighten_4f(const Sk4f& s, const Sk4f& d) {
Sk4f sa = alpha(s);
Sk4f da = alpha(d);
return s + d - Sk4f::Min(s * da, d * sa);
}
static Sk4f colordodge_4f(const Sk4f& s, const Sk4f& d) {
Sk4f sa = alpha(s);
Sk4f da = alpha(d);
Sk4f isa = Sk4f(1) - sa;
Sk4f ida = Sk4f(1) - da;
Sk4f srcover = s + d * isa;
Sk4f dstover = d + s * ida;
Sk4f otherwise = sa * Sk4f::Min(da, (d * sa) / (sa - s)) + s * ida + d * isa;
// Order matters here, preferring d==0 over s==sa.
auto colors = (d == Sk4f(0)).thenElse(dstover,
(s == sa).thenElse(srcover,
otherwise));
return color_alpha(colors, srcover);
}
static Sk4f colorburn_4f(const Sk4f& s, const Sk4f& d) {
Sk4f sa = alpha(s);
Sk4f da = alpha(d);
Sk4f isa = Sk4f(1) - sa;
Sk4f ida = Sk4f(1) - da;
Sk4f srcover = s + d * isa;
Sk4f dstover = d + s * ida;
Sk4f otherwise = sa * (da - Sk4f::Min(da, (da - d) * sa / s)) + s * ida + d * isa;
// Order matters here, preferring d==da over s==0.
auto colors = (d == da).thenElse(dstover,
(s == Sk4f(0)).thenElse(srcover,
otherwise));
return color_alpha(colors, srcover);
}
static Sk4f softlight_4f(const Sk4f& s, const Sk4f& d) {
Sk4f sa = alpha(s);
Sk4f da = alpha(d);
Sk4f isa = Sk4f(1) - sa;
Sk4f ida = Sk4f(1) - da;
// Some common terms.
Sk4f m = (da > Sk4f(0)).thenElse(d / da, Sk4f(0));
Sk4f s2 = Sk4f(2) * s;
Sk4f m4 = Sk4f(4) * m;
// The logic forks three ways:
// 1. dark src?
// 2. light src, dark dst?
// 3. light src, light dst?
Sk4f darkSrc = d * (sa + (s2 - sa) * (Sk4f(1) - m)); // Used in case 1.
Sk4f darkDst = (m4 * m4 + m4) * (m - Sk4f(1)) + Sk4f(7) * m; // Used in case 2.
Sk4f liteDst = m.sqrt() - m; // Used in case 3.
Sk4f liteSrc = d * sa + da * (s2 - sa) * (Sk4f(4) * d <= da).thenElse(darkDst,
liteDst); // Case 2 or 3?
return color_alpha(s * ida + d * isa + (s2 <= sa).thenElse(darkSrc, liteSrc), // Case 1 or 2/3?
s + d * isa);
}
static Sk4f difference_4f(const Sk4f& s, const Sk4f& d) {
Sk4f min = Sk4f::Min(s * alpha(d), d * alpha(s));
return s + d - min - color_alpha(min, 0);
}
static Sk4f exclusion_4f(const Sk4f& s, const Sk4f& d) {
Sk4f product = s * d;
return s + d - product - color_alpha(product, 0);
}
////////////////////////////////////////////////////
// The CSS compositing spec introduces the following formulas:
// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
// while PDF and CG uses the one from Rec. Rec. 601
// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
static inline float Lum(float r, float g, float b) {
return r * 0.2126f + g * 0.7152f + b * 0.0722f;
}
static inline float max(float a, float b, float c) {
return SkTMax(a, SkTMax(b, c));
}
static inline float min(float a, float b, float c) {
return SkTMin(a, SkTMin(b, c));
}
static inline float Sat(float r, float g, float b) {
return max(r, g, b) - min(r, g, b);
}
static inline void setSaturationComponents(float* Cmin, float* Cmid, float* Cmax, float s) {
if(*Cmax > *Cmin) {
*Cmid = (*Cmid - *Cmin) * s / (*Cmax - *Cmin);
*Cmax = s;
} else {
*Cmax = 0;
*Cmid = 0;
}
*Cmin = 0;
}
static inline void SetSat(float* r, float* g, float* b, float s) {
if(*r <= *g) {
if(*g <= *b) {
setSaturationComponents(r, g, b, s);
} else if(*r <= *b) {
setSaturationComponents(r, b, g, s);
} else {
setSaturationComponents(b, r, g, s);
}
} else if(*r <= *b) {
setSaturationComponents(g, r, b, s);
} else if(*g <= *b) {
setSaturationComponents(g, b, r, s);
} else {
setSaturationComponents(b, g, r, s);
}
}
static inline void clipColor(float* r, float* g, float* b, float a) {
float L = Lum(*r, *g, *b);
float n = min(*r, *g, *b);
float x = max(*r, *g, *b);
float denom;
if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
float scale = L / denom;
*r = L + (*r - L) * scale;
*g = L + (*g - L) * scale;
*b = L + (*b - L) * scale;
}
if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
float scale = (a - L) / denom;
*r = L + (*r - L) * scale;
*g = L + (*g - L) * scale;
*b = L + (*b - L) * scale;
}
}
static inline void SetLum(float* r, float* g, float* b, float a, float l) {
float d = l - Lum(*r, *g, *b);
*r += d;
*g += d;
*b += d;
clipColor(r, g, b, a);
}
static Sk4f hue_4f(const Sk4f& s, const Sk4f& d) {
float sa = s.kth<SkPM4f::A>();
float sr = s.kth<SkPM4f::R>();
float sg = s.kth<SkPM4f::G>();
float sb = s.kth<SkPM4f::B>();
float da = d.kth<SkPM4f::A>();
float dr = d.kth<SkPM4f::R>();
float dg = d.kth<SkPM4f::G>();
float db = d.kth<SkPM4f::B>();
float Sr = sr;
float Sg = sg;
float Sb = sb;
SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
sa + da - sa * da);
}
static Sk4f saturation_4f(const Sk4f& s, const Sk4f& d) {
float sa = s.kth<SkPM4f::A>();
float sr = s.kth<SkPM4f::R>();
float sg = s.kth<SkPM4f::G>();
float sb = s.kth<SkPM4f::B>();
float da = d.kth<SkPM4f::A>();
float dr = d.kth<SkPM4f::R>();
float dg = d.kth<SkPM4f::G>();
float db = d.kth<SkPM4f::B>();
float Dr = dr;
float Dg = dg;
float Db = db;
SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
sa + da - sa * da);
}
static Sk4f color_4f(const Sk4f& s, const Sk4f& d) {
float sa = s.kth<SkPM4f::A>();
float sr = s.kth<SkPM4f::R>();
float sg = s.kth<SkPM4f::G>();
float sb = s.kth<SkPM4f::B>();
float da = d.kth<SkPM4f::A>();
float dr = d.kth<SkPM4f::R>();
float dg = d.kth<SkPM4f::G>();
float db = d.kth<SkPM4f::B>();
float Sr = sr;
float Sg = sg;
float Sb = sb;
SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
sa + da - sa * da);
}
static Sk4f luminosity_4f(const Sk4f& s, const Sk4f& d) {
float sa = s.kth<SkPM4f::A>();
float sr = s.kth<SkPM4f::R>();
float sg = s.kth<SkPM4f::G>();
float sb = s.kth<SkPM4f::B>();
float da = d.kth<SkPM4f::A>();
float dr = d.kth<SkPM4f::R>();
float dg = d.kth<SkPM4f::G>();
float db = d.kth<SkPM4f::B>();
float Dr = dr;
float Dg = dg;
float Db = db;
SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
sa + da - sa * da);
}
///////////////////////////////////////////////////////////////////////////////
static SkPM4f not_implemented_yet_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return {{ 0.5f, 1.0f, 0.25f, 0.5f }};
}
// kClear_Mode, //!< [0, 0]
static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
return 0;
@ -267,9 +517,6 @@ static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f overlay_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kDarken_Mode
static inline int darken_byte(int sc, int dc, int sa, int da) {
@ -292,9 +539,6 @@ static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f darken_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kLighten_Mode
static inline int lighten_byte(int sc, int dc, int sa, int da) {
@ -317,9 +561,6 @@ static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f lighten_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kColorDodge_Mode
static inline int colordodge_byte(int sc, int dc, int sa, int da) {
@ -344,9 +585,6 @@ static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f colordodge_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kColorBurn_Mode
static inline int colorburn_byte(int sc, int dc, int sa, int da) {
@ -371,9 +609,6 @@ static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f colorburn_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kHardLight_Mode
static inline int hardlight_byte(int sc, int dc, int sa, int da) {
@ -394,9 +629,6 @@ static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f hardlight_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// returns 255 * sqrt(n/255)
static U8CPU sqrt_unit_byte(U8CPU n) {
@ -427,9 +659,6 @@ static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f softlight_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kDifference_Mode
static inline int difference_byte(int sc, int dc, int sa, int da) {
@ -445,9 +674,6 @@ static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f difference_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kExclusion_Mode
static inline int exclusion_byte(int sc, int dc, int, int) {
@ -467,9 +693,6 @@ static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f exclusion_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// The CSS compositing spec introduces the following formulas:
// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
@ -585,9 +808,6 @@ static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f hue_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kSaturation_Mode
// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
@ -622,9 +842,6 @@ static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f saturation_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kColor_Mode
// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
@ -658,9 +875,6 @@ static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f color_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kLuminosity_Mode
// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
@ -694,8 +908,29 @@ static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f luminosity_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
///////////////////////////////////////////////////////////////////////////////////////////////////
static SkPM4f as_pm4f(const Sk4f& x) {
SkPM4f pm4;
x.store(pm4.fVec);
return pm4;
}
static Sk4f as_4f(const SkPM4f& pm4) {
return Sk4f::Load(pm4.fVec);
}
template <Sk4f (blend)(const Sk4f&, const Sk4f&)> SkPM4f proc_4f(const SkPM4f& s, const SkPM4f& d) {
SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d)));
#ifdef SK_DEBUG
const float min = 0;
const float max = 1;
for (int i = 0; i < 4; ++i) {
SkASSERT(r.fVec[i] >= min && r.fVec[i] <= max);
}
#endif
return r;
}
const ProcCoeff gProcCoeffs[] = {
@ -715,20 +950,20 @@ const ProcCoeff gProcCoeffs[] = {
{ plus_modeproc, proc_4f<plus_4f>, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
{ modulate_modeproc, proc_4f<modulate_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
{ screen_modeproc, proc_4f<screen_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
{ overlay_modeproc, overlay_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ darken_modeproc, darken_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ lighten_modeproc, lighten_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colordodge_modeproc, colordodge_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colorburn_modeproc, colorburn_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hardlight_modeproc, hardlight_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ softlight_modeproc, softlight_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ difference_modeproc, difference_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ exclusion_modeproc, exclusion_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ overlay_modeproc, proc_4f<overlay_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ darken_modeproc, proc_4f<darken_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ lighten_modeproc, proc_4f<lighten_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colordodge_modeproc, proc_4f<colordodge_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colorburn_modeproc, proc_4f<colorburn_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hardlight_modeproc, proc_4f<hardlight_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ softlight_modeproc, proc_4f<softlight_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ difference_modeproc, proc_4f<difference_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ exclusion_modeproc, proc_4f<exclusion_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ multiply_modeproc, proc_4f<multiply_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hue_modeproc, hue_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ saturation_modeproc, saturation_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ color_modeproc, color_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ luminosity_modeproc, luminosity_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hue_modeproc, proc_4f<hue_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ saturation_modeproc, proc_4f<saturation_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ color_modeproc, proc_4f<color_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ luminosity_modeproc, proc_4f<luminosity_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
};
///////////////////////////////////////////////////////////////////////////////