remove filterSpan from SkColorFilter

Bug: skia:
Change-Id: Ie8a31ea8131c08d251a825622484342e3e174474
Reviewed-on: https://skia-review.googlesource.com/21207
Commit-Queue: Mike Reed <reed@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Mike Klein <mtklein@chromium.org>
Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Mike Reed 2017-06-29 11:37:15 -04:00 committed by Skia Commit-Bot
parent 185a3798db
commit 9c1d780228
18 changed files with 12 additions and 623 deletions

View File

@ -63,15 +63,6 @@ public:
*/
virtual bool asComponentTable(SkBitmap* table) const;
/** Called with a scanline of colors, as if there was a shader installed.
The implementation writes out its filtered version into result[].
Note: shader and result may be the same buffer.
@param src array of colors, possibly generated by a shader
@param count the number of entries in the src[] and result[] arrays
@param result written by the filter
*/
virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[]) const = 0;
void appendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool shaderIsOpaque) const;
enum Flags {
@ -93,17 +84,7 @@ public:
*/
virtual sk_sp<SkColorFilter> makeComposed(sk_sp<SkColorFilter>) const { return nullptr; }
/**
* Apply this colorfilter to the specified SkColor. This routine handles
* converting to SkPMColor, calling the filter, and then converting back
* to SkColor. This method is not virtual, but will call filterSpan()
* which is virtual.
*/
SkColor filterColor(SkColor) const;
/**
* Filters a single color.
*/
SkColor4f filterColor4f(const SkColor4f&) const;
/** Create a colorfilter that uses the specified color and mode.

View File

@ -28,8 +28,6 @@ class SK_API SkLumaColorFilter : public SkColorFilter {
public:
static sk_sp<SkColorFilter> Make();
void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override;
#if SK_SUPPORT_GPU
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
#endif

View File

@ -49,9 +49,17 @@ void SkColorFilter::appendStages(SkRasterPipeline* p,
}
SkColor SkColorFilter::filterColor(SkColor c) const {
SkPMColor dst, src = SkPreMultiplyColor(c);
this->filterSpan(&src, 1, &dst);
return SkUnPreMultiply::PMColorToColor(dst);
const float inv255 = 1.0f / 255;
SkColor4f c4 = this->filterColor4f({
SkColorGetR(c) * inv255,
SkColorGetG(c) * inv255,
SkColorGetB(c) * inv255,
SkColorGetA(c) * inv255,
});
return SkColorSetARGB(sk_float_round2int(c4.fA*255),
sk_float_round2int(c4.fR*255),
sk_float_round2int(c4.fG*255),
sk_float_round2int(c4.fB*255));
}
#include "SkRasterPipeline.h"
@ -89,11 +97,6 @@ public:
return fOuter->getFlags() & fInner->getFlags();
}
void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
fInner->filterSpan(shader, count, result);
fOuter->filterSpan(result, count, result);
}
#ifndef SK_IGNORE_TO_STRING
void toString(SkString* str) const override {
SkString outerS, innerS;

View File

@ -62,81 +62,6 @@ uint32_t SkColorMatrixFilterRowMajor255::getFlags() const {
return this->INHERITED::getFlags() | fFlags;
}
static Sk4f scale_rgb(float scale) {
static_assert(SkPM4f::A == 3, "Alpha is lane 3");
return Sk4f(scale, scale, scale, 1);
}
static Sk4f premul(const Sk4f& x) {
return x * scale_rgb(x[SkPM4f::A]);
}
static Sk4f unpremul(const Sk4f& x) {
return x * scale_rgb(1 / x[SkPM4f::A]); // TODO: fast/approx invert?
}
static Sk4f clamp_0_1(const Sk4f& x) {
return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0));
}
static SkPMColor round(const Sk4f& x) {
SkPMColor c;
SkNx_cast<uint8_t>(x * Sk4f(255) + Sk4f(0.5f)).store(&c);
return c;
}
template <typename Adaptor, typename T>
void filter_span(const float array[], const T src[], int count, T dst[]) {
const Sk4f c0 = Sk4f::Load(array + 0);
const Sk4f c1 = Sk4f::Load(array + 4);
const Sk4f c2 = Sk4f::Load(array + 8);
const Sk4f c3 = Sk4f::Load(array + 12);
const Sk4f c4 = Sk4f::Load(array + 16);
// todo: we could cache this in the constructor...
T matrix_translate_pmcolor = Adaptor::From4f(premul(clamp_0_1(c4)));
for (int i = 0; i < count; i++) {
Sk4f srcf = Adaptor::To4f(src[i]);
float srcA = srcf[SkPM4f::A];
if (0 == srcA) {
dst[i] = matrix_translate_pmcolor;
continue;
}
if (1 != srcA) {
srcf = unpremul(srcf);
}
Sk4f r4 = srcf[Adaptor::R];
Sk4f g4 = srcf[Adaptor::G];
Sk4f b4 = srcf[Adaptor::B];
Sk4f a4 = srcf[Adaptor::A];
// apply matrix
Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4;
dst[i] = Adaptor::From4f(premul(clamp_0_1(dst4)));
}
}
struct SkPMColorAdaptor {
enum {
R = SK_R_INDEX,
G = SK_G_INDEX,
B = SK_B_INDEX,
A = SK_A_INDEX,
};
static SkPMColor From4f(const Sk4f& c4) {
return round(swizzle_rb_if_bgra(c4));
}
static Sk4f To4f(SkPMColor c) {
return Sk4f_fromL32(c);
}
};
void SkColorMatrixFilterRowMajor255::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
filter_span<SkPMColorAdaptor>(fTranspose, src, count, dst);
}
///////////////////////////////////////////////////////////////////////////////
void SkColorMatrixFilterRowMajor255::flatten(SkWriteBuffer& buffer) const {

View File

@ -18,7 +18,6 @@ public:
/** Creates a color matrix filter that returns the same value in all four channels. */
static sk_sp<SkColorFilter> MakeSingleChannelOutput(const SkScalar row[5]);
void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override;
uint32_t getFlags() const override;
bool asColorMatrix(SkScalar matrix[20]) const override;
sk_sp<SkColorFilter> makeComposed(sk_sp<SkColorFilter>) const override;

View File

@ -62,47 +62,6 @@ uint32_t SkModeColorFilter::getFlags() const {
return flags;
}
void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
SkPMColor color = fPMColor;
switch (fMode) {
case SkBlendMode::kSrc:
sk_memset32(result, color, count);
break;
case SkBlendMode::kSrcIn:
for (int i = 0; i < count; ++i) {
result[i] = SkAlphaMulQ(color, SkAlpha255To256(SkGetPackedA32(shader[i])));
}
break;
case SkBlendMode::kModulate:
for (int i = 0; i < count; ++i) {
int a = SkMulDiv255Round(SkGetPackedA32(color), SkGetPackedA32(shader[i]));
int r = SkMulDiv255Round(SkGetPackedR32(color), SkGetPackedR32(shader[i]));
int g = SkMulDiv255Round(SkGetPackedG32(color), SkGetPackedG32(shader[i]));
int b = SkMulDiv255Round(SkGetPackedB32(color), SkGetPackedB32(shader[i]));
result[i] = SkPackARGB32(a, r, g, b);
}
break;
default: {
SkSTArenaAlloc<256> alloc;
SkRasterPipeline p(&alloc);
if (kN32_SkColorType == kBGRA_8888_SkColorType) {
p.append(SkRasterPipeline::load_bgra, &shader);
} else {
p.append(SkRasterPipeline::load_8888, &shader);
}
this->appendStages(&p, nullptr, &alloc, false);
if (kN32_SkColorType == kBGRA_8888_SkColorType) {
p.append(SkRasterPipeline::store_bgra, &result);
} else {
p.append(SkRasterPipeline::store_8888, &result);
}
p.run(0, 0, count);
} break;
}
}
void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
buffer.writeColor(fColor);
buffer.writeUInt((int)fMode);

View File

@ -21,7 +21,6 @@ public:
bool asColorMode(SkColor*, SkBlendMode*) const override;
uint32_t getFlags() const override;
void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override;
#ifndef SK_IGNORE_TO_STRING
void toString(SkString* str) const override;

View File

@ -44,9 +44,7 @@ public:
}
// Let fMatrixFilter handle all the other calls directly.
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override {
fMatrixFilter->filterSpan(src, count, dst);
}
uint32_t getFlags() const override {
return fMatrixFilter->getFlags();
}

View File

@ -22,111 +22,6 @@
using InvertStyle = SkHighContrastConfig::InvertStyle;
namespace {
SkScalar Hue2RGB(SkScalar p, SkScalar q, SkScalar t) {
if (t < 0) {
t += 1;
} else if (t > 1) {
t -= 1;
}
if (t < 1/6.f) {
return p + (q - p) * 6 * t;
}
if (t < 1/2.f) {
return q;
}
if (t < 2/3.f) {
return p + (q - p) * (2/3.f - t) * 6;
}
return p;
}
SkScalar IncreaseContrast(SkScalar f, SkScalar contrast) {
SkScalar m = (1 + contrast) / (1 - contrast);
SkScalar b = (-0.5f * m + 0.5f);
return m * f + b;
}
SkColor4f ApplyHighContrastFilter(const SkHighContrastConfig& config, const SkColor4f& src) {
// Apply a gamma of 2.0 so that the rest of the calculations
// happen roughly in linear space.
float rf = src.fR * src.fR;
float gf = src.fG * src.fG;
float bf = src.fB * src.fB;
// Convert to grayscale using luminance coefficients.
if (config.fGrayscale) {
SkScalar lum =
rf * SK_LUM_COEFF_R + gf * SK_LUM_COEFF_G + bf * SK_LUM_COEFF_B;
rf = lum;
gf = lum;
bf = lum;
}
// Now invert.
if (config.fInvertStyle == InvertStyle::kInvertBrightness) {
rf = 1 - rf;
gf = 1 - gf;
bf = 1 - bf;
} else if (config.fInvertStyle == InvertStyle::kInvertLightness) {
// Convert to HSL
SkScalar max = SkTMax(SkTMax(rf, gf), bf);
SkScalar min = SkTMin(SkTMin(rf, gf), bf);
SkScalar l = (max + min) / 2;
SkScalar h, s;
if (max == min) {
h = 0;
s = 0;
} else {
SkScalar d = max - min;
s = l > 0.5f ? d / (2 - max - min) : d / (max + min);
if (max == rf) {
h = (gf - bf) / d + (gf < bf ? 6 : 0);
} else if (max == gf) {
h = (bf - rf) / d + 2;
} else {
h = (rf - gf) / d + 4;
}
h /= 6;
}
// Invert lightness.
l = 1 - l;
// Now convert back to RGB.
if (s == 0) {
// Grayscale
rf = l;
gf = l;
bf = l;
} else {
SkScalar q = l < 0.5f ? l * (1 + s) : l + s - l * s;
SkScalar p = 2 * l - q;
rf = Hue2RGB(p, q, h + 1/3.f);
gf = Hue2RGB(p, q, h);
bf = Hue2RGB(p, q, h - 1/3.f);
}
}
// Increase contrast.
if (config.fContrast != 0.0f) {
rf = IncreaseContrast(rf, config.fContrast);
gf = IncreaseContrast(gf, config.fContrast);
bf = IncreaseContrast(bf, config.fContrast);
}
// Convert back from linear to a color space with a gamma of ~2.0.
return SkColor4f::Pin(SkScalarSqrt(rf), SkScalarSqrt(gf), SkScalarSqrt(bf), src.fA);
}
} // namespace
class SkHighContrast_Filter : public SkColorFilter {
public:
SkHighContrast_Filter(const SkHighContrastConfig& config) {
@ -143,7 +38,6 @@ public:
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
#endif
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
void onAppendStages(SkRasterPipeline* p,
SkColorSpace* dst,
SkArenaAlloc* scratch,
@ -164,20 +58,6 @@ private:
typedef SkColorFilter INHERITED;
};
void SkHighContrast_Filter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
const float oneOver255 = 1.0f / 255;
for (int i = 0; i < count; ++i) {
SkColor color = SkUnPreMultiply::PMColorToColor(src[i]);
// be sure to NOT treat color as sRGB, as we are in legacy mode here
SkColor4f s4 {
SkColorGetR(color) * oneOver255, SkColorGetG(color) * oneOver255,
SkColorGetB(color) * oneOver255, SkColorGetA(color) * oneOver255,
};
SkColor4f d4 = ApplyHighContrastFilter(fConfig, s4);
dst[i] = d4.premul().toPMColor();
}
}
void SkHighContrast_Filter::onAppendStages(SkRasterPipeline* p,
SkColorSpace* dstCS,
SkArenaAlloc* alloc,

View File

@ -17,25 +17,6 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#endif
void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
for (int i = 0; i < count; ++i) {
SkPMColor c = src[i];
/*
* While LuminanceToAlpha is defined to operate on un-premultiplied
* inputs, due to the final alpha scaling it can be computed based on
* premultipled components:
*
* LumA = (k1 * r / a + k2 * g / a + k3 * b / a) * a
* LumA = (k1 * r + k2 * g + k3 * b)
*/
unsigned luma = SkComputeLuminance(SkGetPackedR32(c),
SkGetPackedG32(c),
SkGetPackedB32(c));
dst[i] = SkPackARGB32(luma, 0, 0, 0);
}
}
void SkLumaColorFilter::onAppendStages(SkRasterPipeline* p,
SkColorSpace* dst,
SkArenaAlloc* scratch,

View File

@ -12,17 +12,6 @@
#include "SkReadBuffer.h"
#include "../jumper/SkJumper.h"
void SkOverdrawColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
for (int x = 0; x < count; x++) {
uint8_t alpha = SkGetPackedA32(src[x]);
if (alpha >= kNumColors) {
alpha = kNumColors - 1;
}
dst[x] = fColors[alpha];
}
}
void SkOverdrawColorFilter::onAppendStages(SkRasterPipeline* p,
SkColorSpace* dstCS,
SkArenaAlloc* alloc,

View File

@ -31,7 +31,6 @@ public:
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
#endif
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
void toString(SkString* str) const override;
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer);

View File

@ -89,8 +89,6 @@ public:
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
#endif
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
@ -141,49 +139,6 @@ private:
typedef SkColorFilter INHERITED;
};
void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
const uint8_t* table = fStorage;
const uint8_t* tableA = gIdentityTable;
const uint8_t* tableR = gIdentityTable;
const uint8_t* tableG = gIdentityTable;
const uint8_t* tableB = gIdentityTable;
if (fFlags & kA_Flag) {
tableA = table; table += 256;
}
if (fFlags & kR_Flag) {
tableR = table; table += 256;
}
if (fFlags & kG_Flag) {
tableG = table; table += 256;
}
if (fFlags & kB_Flag) {
tableB = table;
}
const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
for (int i = 0; i < count; ++i) {
SkPMColor c = src[i];
unsigned a, r, g, b;
if (0 == c) {
a = r = g = b = 0;
} else {
a = SkGetPackedA32(c);
r = SkGetPackedR32(c);
g = SkGetPackedG32(c);
b = SkGetPackedB32(c);
if (a < 255) {
SkUnPreMultiply::Scale scale = scaleTable[a];
r = SkUnPreMultiply::ApplyScale(scale, r);
g = SkUnPreMultiply::ApplyScale(scale, g);
b = SkUnPreMultiply::ApplyScale(scale, b);
}
}
dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
tableG[g], tableB[b]);
}
}
#ifndef SK_IGNORE_TO_STRING
void SkTable_ColorFilter::toString(SkString* str) const {
const uint8_t* table = fStorage;

View File

@ -39,21 +39,6 @@ void SkColorFilterShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fFilter.get());
}
uint32_t SkColorFilterShader::FilterShaderContext::getFlags() const {
const SkColorFilterShader& filterShader = static_cast<const SkColorFilterShader&>(fShader);
uint32_t shaderF = fShaderContext->getFlags();
uint32_t filterF = filterShader.fFilter->getFlags();
// If the filter does not support a given feature, but sure to clear the corresponding flag
// in the shader flags.
//
if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) {
shaderF &= ~kOpaqueAlpha_Flag;
}
return shaderF;
}
bool SkColorFilterShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS,
SkArenaAlloc* alloc, const SkMatrix& ctm,
const SkPaint& paint, const SkMatrix* localM) const {
@ -64,55 +49,10 @@ bool SkColorFilterShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpac
return true;
}
SkShaderBase::Context* SkColorFilterShader::onMakeContext(const ContextRec& rec,
SkArenaAlloc* alloc) const {
auto* shaderContext = as_SB(fShader)->makeContext(rec, alloc);
if (nullptr == shaderContext) {
return nullptr;
}
return alloc->make<FilterShaderContext>(*this, shaderContext, rec);
}
sk_sp<SkShader> SkColorFilterShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
return xformer->apply(fShader.get())->makeWithColorFilter(xformer->apply(fFilter.get()));
}
SkColorFilterShader::FilterShaderContext::FilterShaderContext(
const SkColorFilterShader& filterShader,
SkShaderBase::Context* shaderContext,
const ContextRec& rec)
: INHERITED(filterShader, rec)
, fShaderContext(shaderContext)
{}
void SkColorFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[],
int count) {
const SkColorFilterShader& filterShader = static_cast<const SkColorFilterShader&>(fShader);
fShaderContext->shadeSpan(x, y, result, count);
filterShader.fFilter->filterSpan(result, count, result);
}
#include "SkRasterPipeline.h"
void SkColorFilterShader::FilterShaderContext::shadeSpan4f(int x, int y, SkPM4f result[],
int count) {
const SkColorFilterShader& filterShader = static_cast<const SkColorFilterShader&>(fShader);
fShaderContext->shadeSpan4f(x, y, result, count);
// now apply the filter
SkSTArenaAlloc<128> alloc;
SkRasterPipeline pipeline(&alloc);
const SkPM4f* src = result;
pipeline.append(SkRasterPipeline::load_f32, &src);
filterShader.fFilter->appendStages(&pipeline, nullptr, &alloc, filterShader.isOpaque());
SkPM4f* dst = result;
pipeline.append(SkRasterPipeline::store_f32, &dst);
pipeline.run(0,y, count);
}
#if SK_SUPPORT_GPU
/////////////////////////////////////////////////////////////////////

View File

@ -21,33 +21,11 @@ public:
sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
#endif
class FilterShaderContext : public Context {
public:
// Takes ownership of shaderContext and calls its destructor.
FilterShaderContext(const SkColorFilterShader&, SkShaderBase::Context*, const ContextRec&);
uint32_t getFlags() const override;
void shadeSpan(int x, int y, SkPMColor[], int count) override;
void shadeSpan4f(int x, int y, SkPM4f[], int count) override;
void set3DMask(const SkMask* mask) override {
// forward to our proxy
fShaderContext->set3DMask(mask);
}
private:
SkShaderBase::Context* fShaderContext;
typedef Context INHERITED;
};
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorFilterShader)
protected:
void flatten(SkWriteBuffer&) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc* alloc) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
const SkMatrix&, const SkPaint&, const SkMatrix* localM) const override;

View File

@ -37,8 +37,6 @@ public:
return sk_sp<SkColorFilter>(new SkGaussianColorFilter);
}
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
#if SK_SUPPORT_GPU
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
#endif
@ -58,75 +56,6 @@ private:
typedef SkColorFilter INHERITED;
};
static inline float eval_gaussian(float x) {
// x = 1 - x;
// return sk_float_exp(-x * x * 4) - 0.018f;
return 0.00030726194381713867f +
x*(0.15489584207534790039f +
x*(0.21345567703247070312f +
(2.89795351028442382812f - 2.26661229133605957031f*x)*x));
}
static void build_table() {
SkDebugf("const uint8_t gByteExpU8Table[256] = {");
for (int i = 0; i <= 255; ++i) {
if (!(i % 8)) {
SkDebugf("\n");
}
int v = (int)(eval_gaussian(i / 255.f) * 256);
SkDebugf(" 0x%02X,", v);
}
SkDebugf("\n};\n");
}
const uint8_t gByteExpU8Table[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07,
0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D,
0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11,
0x11, 0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x15,
0x16, 0x17, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B,
0x1C, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21,
0x22, 0x23, 0x24, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4C, 0x4D,
0x4E, 0x50, 0x51, 0x53, 0x54, 0x55, 0x57, 0x58,
0x5A, 0x5B, 0x5D, 0x5E, 0x60, 0x61, 0x63, 0x64,
0x66, 0x68, 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x71,
0x73, 0x75, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7F,
0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8A, 0x8C,
0x8E, 0x90, 0x91, 0x93, 0x95, 0x96, 0x98, 0x9A,
0x9C, 0x9D, 0x9F, 0xA1, 0xA2, 0xA4, 0xA6, 0xA8,
0xA9, 0xAB, 0xAD, 0xAE, 0xB0, 0xB2, 0xB3, 0xB5,
0xB7, 0xB8, 0xBA, 0xBC, 0xBD, 0xBF, 0xC0, 0xC2,
0xC3, 0xC5, 0xC7, 0xC8, 0xCA, 0xCB, 0xCD, 0xCE,
0xCF, 0xD1, 0xD2, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9,
0xDA, 0xDC, 0xDD, 0xDE, 0xDF, 0xE1, 0xE2, 0xE3,
0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF0, 0xF1, 0xF2,
0xF3, 0xF3, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7,
0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA,
0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
};
void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
// to re-build the table, call build_table() which will dump it out using SkDebugf.
if (false) {
build_table();
}
for (int i = 0; i < count; ++i) {
SkPMColor c = src[i];
uint8_t a = gByteExpU8Table[SkGetPackedA32(c)];
dst[i] = SkPackARGB32(a, a, a, a);
}
}
sk_sp<SkFlattenable> SkGaussianColorFilter::CreateProc(SkReadBuffer&) {
return Make();
}

View File

@ -110,124 +110,3 @@ DEF_TEST(ColorFilter, reporter) {
test_composecolorfilter_limit(reporter);
}
///////////////////////////////////////////////////////////////////////////////
DEF_TEST(LumaColorFilter, reporter) {
SkPMColor in, out;
auto lf(SkLumaColorFilter::Make());
// Applying luma to white produces black with the same transparency.
for (unsigned i = 0; i < 256; ++i) {
in = SkPackARGB32(i, i, i, i);
lf->filterSpan(&in, 1, &out);
REPORTER_ASSERT(reporter, SkGetPackedA32(out) == i);
REPORTER_ASSERT(reporter, SkGetPackedR32(out) == 0);
REPORTER_ASSERT(reporter, SkGetPackedG32(out) == 0);
REPORTER_ASSERT(reporter, SkGetPackedB32(out) == 0);
}
// Applying luma to black yields transparent black (luminance(black) == 0)
for (unsigned i = 0; i < 256; ++i) {
in = SkPackARGB32(i, 0, 0, 0);
lf->filterSpan(&in, 1, &out);
REPORTER_ASSERT(reporter, out == SK_ColorTRANSPARENT);
}
// For general colors, a luma filter generates black with an attenuated alpha channel.
for (unsigned i = 1; i < 256; ++i) {
in = SkPackARGB32(i, i, i / 2, i / 3);
lf->filterSpan(&in, 1, &out);
REPORTER_ASSERT(reporter, out != in);
REPORTER_ASSERT(reporter, SkGetPackedA32(out) <= i);
REPORTER_ASSERT(reporter, SkGetPackedR32(out) == 0);
REPORTER_ASSERT(reporter, SkGetPackedG32(out) == 0);
REPORTER_ASSERT(reporter, SkGetPackedB32(out) == 0);
}
}
///////////////////////////////////////////////////////////////////////////////
#include "SkColorMatrixFilter.h"
static void get_brightness_matrix(float amount, float matrix[20]) {
// Spec implementation
// (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquivalent)
// <feFunc[R|G|B] type="linear" slope="[amount]">
memset(matrix, 0, 20 * sizeof(SkScalar));
matrix[0] = matrix[6] = matrix[12] = amount;
matrix[18] = 1.f;
}
static void get_grayscale_matrix(float amount, float matrix[20]) {
// Note, these values are computed to ensure MatrixNeedsClamping is false
// for amount in [0..1]
matrix[0] = 0.2126f + 0.7874f * amount;
matrix[1] = 0.7152f - 0.7152f * amount;
matrix[2] = 1.f - (matrix[0] + matrix[1]);
matrix[3] = matrix[4] = 0.f;
matrix[5] = 0.2126f - 0.2126f * amount;
matrix[6] = 0.7152f + 0.2848f * amount;
matrix[7] = 1.f - (matrix[5] + matrix[6]);
matrix[8] = matrix[9] = 0.f;
matrix[10] = 0.2126f - 0.2126f * amount;
matrix[11] = 0.7152f - 0.7152f * amount;
matrix[12] = 1.f - (matrix[10] + matrix[11]);
matrix[13] = matrix[14] = 0.f;
matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
matrix[18] = 1.f;
}
static sk_sp<SkColorFilter> make_cf0() {
SkScalar matrix[20];
get_brightness_matrix(0.5f, matrix);
return SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
}
static sk_sp<SkColorFilter> make_cf1() {
SkScalar matrix[20];
get_grayscale_matrix(1, matrix);
return SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
}
static sk_sp<SkColorFilter> make_cf2() {
SkColorMatrix m0, m1;
get_brightness_matrix(0.5f, m0.fMat);
get_grayscale_matrix(1, m1.fMat);
m0.preConcat(m1);
return SkColorFilter::MakeMatrixFilterRowMajor255(m0.fMat);
}
static sk_sp<SkColorFilter> make_cf3() {
SkColorMatrix m0, m1;
get_brightness_matrix(0.5f, m0.fMat);
get_grayscale_matrix(1, m1.fMat);
m0.postConcat(m1);
return SkColorFilter::MakeMatrixFilterRowMajor255(m0.fMat);
}
typedef sk_sp<SkColorFilter> (*CFProc)();
// Test that a colormatrix that "should" preserve opaquness actually does.
DEF_TEST(ColorMatrixFilter, reporter) {
const CFProc procs[] = {
make_cf0, make_cf1, make_cf2, make_cf3,
};
for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
auto cf(procs[i]());
// generate all possible r,g,b triples
for (int r = 0; r < 256; ++r) {
for (int g = 0; g < 256; ++g) {
SkPMColor storage[256];
for (int b = 0; b < 256; ++b) {
storage[b] = SkPackARGB32(0xFF, r, g, b);
}
cf->filterSpan(storage, 256, storage);
for (int b = 0; b < 256; ++b) {
REPORTER_ASSERT(reporter, 0xFF == SkGetPackedA32(storage[b]));
}
}
}
}
}

View File

@ -37,9 +37,6 @@ public:
return GrSRGBEffect::Make(fMode);
}
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override {
SK_ABORT("SkSRGBColorFilter is only implemented for GPU");
}
void onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool) const override {
SK_ABORT("SkSRGBColorFilter is only implemented for GPU");
}