| Index: src/core/SkColorShader.cpp
|
| diff --git a/src/core/SkColorShader.cpp b/src/core/SkColorShader.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f399eaaa57a6666002f90f772cfd9b9bf77f064d
|
| --- /dev/null
|
| +++ b/src/core/SkColorShader.cpp
|
| @@ -0,0 +1,313 @@
|
| +/*
|
| + * Copyright 2016 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "SkColorShader.h"
|
| +#include "SkColorSpace.h"
|
| +#include "SkReadBuffer.h"
|
| +#include "SkUtils.h"
|
| +
|
| +SkColorShader::SkColorShader(SkColor c) : fColor(c) {}
|
| +
|
| +bool SkColorShader::isOpaque() const {
|
| + return SkColorGetA(fColor) == 255;
|
| +}
|
| +
|
| +sk_sp<SkFlattenable> SkColorShader::CreateProc(SkReadBuffer& buffer) {
|
| + return sk_make_sp<SkColorShader>(buffer.readColor());
|
| +}
|
| +
|
| +void SkColorShader::flatten(SkWriteBuffer& buffer) const {
|
| + buffer.writeColor(fColor);
|
| +}
|
| +
|
| +uint32_t SkColorShader::ColorShaderContext::getFlags() const {
|
| + return fFlags;
|
| +}
|
| +
|
| +SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const {
|
| + return new (storage) ColorShaderContext(*this, rec);
|
| +}
|
| +
|
| +SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
|
| + const ContextRec& rec)
|
| + : INHERITED(shader, rec)
|
| +{
|
| + SkColor color = shader.fColor;
|
| + unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
|
| +
|
| + unsigned r = SkColorGetR(color);
|
| + unsigned g = SkColorGetG(color);
|
| + unsigned b = SkColorGetB(color);
|
| +
|
| + if (a != 255) {
|
| + r = SkMulDiv255Round(r, a);
|
| + g = SkMulDiv255Round(g, a);
|
| + b = SkMulDiv255Round(b, a);
|
| + }
|
| + fPMColor = SkPackARGB32(a, r, g, b);
|
| +
|
| + SkColor4f c4 = SkColor4f::FromColor(shader.fColor);
|
| + c4.fA *= rec.fPaint->getAlpha() / 255.0f;
|
| + fPM4f = c4.premul();
|
| +
|
| + fFlags = kConstInY32_Flag;
|
| + if (255 == a) {
|
| + fFlags |= kOpaqueAlpha_Flag;
|
| + }
|
| +}
|
| +
|
| +void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
|
| + sk_memset32(span, fPMColor, count);
|
| +}
|
| +
|
| +void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
|
| + memset(alpha, SkGetPackedA32(fPMColor), count);
|
| +}
|
| +
|
| +void SkColorShader::ColorShaderContext::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
|
| + for (int i = 0; i < count; ++i) {
|
| + span[i] = fPM4f;
|
| + }
|
| +}
|
| +
|
| +SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
|
| + if (info) {
|
| + if (info->fColors && info->fColorCount >= 1) {
|
| + info->fColors[0] = fColor;
|
| + }
|
| + info->fColorCount = 1;
|
| + info->fTileMode = SkShader::kRepeat_TileMode;
|
| + }
|
| + return kColor_GradientType;
|
| +}
|
| +
|
| +#if SK_SUPPORT_GPU
|
| +
|
| +#include "SkGr.h"
|
| +#include "effects/GrConstColorProcessor.h"
|
| +const GrFragmentProcessor* SkColorShader::asFragmentProcessor(GrContext*, const SkMatrix&,
|
| + const SkMatrix*,
|
| + SkFilterQuality) const {
|
| + GrColor color = SkColorToPremulGrColor(fColor);
|
| + return GrConstColorProcessor::Create(color, GrConstColorProcessor::kModulateA_InputMode);
|
| +}
|
| +
|
| +#endif
|
| +
|
| +#ifndef SK_IGNORE_TO_STRING
|
| +void SkColorShader::toString(SkString* str) const {
|
| + str->append("SkColorShader: (");
|
| +
|
| + str->append("Color: ");
|
| + str->appendHex(fColor);
|
| +
|
| + this->INHERITED::toString(str);
|
| +
|
| + str->append(")");
|
| +}
|
| +#endif
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +static unsigned unit_to_byte(float unit) {
|
| + SkASSERT(unit >= 0 && unit <= 1);
|
| + return (unsigned)(unit * 255 + 0.5);
|
| +}
|
| +
|
| +static SkColor unit_to_skcolor(const SkColor4f& unit, SkColorSpace* cs) {
|
| + return SkColorSetARGB(unit_to_byte(unit.fA), unit_to_byte(unit.fR),
|
| + unit_to_byte(unit.fG), unit_to_byte(unit.fB));
|
| +}
|
| +
|
| +SkColor4Shader::SkColor4Shader(const SkColor4f& color, sk_sp<SkColorSpace> space)
|
| + : fColorSpace(std::move(space))
|
| + , fColor4(color)
|
| + , fCachedByteColor(unit_to_skcolor(color.pin(), space.get()))
|
| +{}
|
| +
|
| +sk_sp<SkFlattenable> SkColor4Shader::CreateProc(SkReadBuffer& buffer) {
|
| + SkColor4f color;
|
| + color.fA = buffer.readScalar(); // readFloat()
|
| + color.fR = buffer.readScalar();
|
| + color.fG = buffer.readScalar();
|
| + color.fB = buffer.readScalar();
|
| + if (buffer.readBool()) {
|
| + // TODO how do we unflatten colorspaces
|
| + }
|
| + return SkShader::MakeColorShader(color, nullptr);
|
| +}
|
| +
|
| +void SkColor4Shader::flatten(SkWriteBuffer& buffer) const {
|
| + buffer.writeScalar(fColor4.fA); // writeFloat()
|
| + buffer.writeScalar(fColor4.fR);
|
| + buffer.writeScalar(fColor4.fG);
|
| + buffer.writeScalar(fColor4.fB);
|
| + buffer.writeBool(false); // TODO how do we flatten colorspaces?
|
| +}
|
| +
|
| +uint32_t SkColor4Shader::Color4Context::getFlags() const {
|
| + return fFlags;
|
| +}
|
| +
|
| +SkShader::Context* SkColor4Shader::onCreateContext(const ContextRec& rec, void* storage) const {
|
| + return new (storage) Color4Context(*this, rec);
|
| +}
|
| +
|
| +SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader,
|
| + const ContextRec& rec)
|
| +: INHERITED(shader, rec)
|
| +{
|
| + SkColor color = shader.fCachedByteColor;
|
| + unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
|
| +
|
| + unsigned r = SkColorGetR(color);
|
| + unsigned g = SkColorGetG(color);
|
| + unsigned b = SkColorGetB(color);
|
| +
|
| + if (a != 255) {
|
| + r = SkMulDiv255Round(r, a);
|
| + g = SkMulDiv255Round(g, a);
|
| + b = SkMulDiv255Round(b, a);
|
| + }
|
| + fPMColor = SkPackARGB32(a, r, g, b);
|
| +
|
| + SkColor4f c4 = shader.fColor4;
|
| + c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f);
|
| + fPM4f = c4.premul();
|
| +
|
| + fFlags = kConstInY32_Flag;
|
| + if (255 == a) {
|
| + fFlags |= kOpaqueAlpha_Flag;
|
| + }
|
| +}
|
| +
|
| +void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) {
|
| + sk_memset32(span, fPMColor, count);
|
| +}
|
| +
|
| +void SkColor4Shader::Color4Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
|
| + memset(alpha, SkGetPackedA32(fPMColor), count);
|
| +}
|
| +
|
| +void SkColor4Shader::Color4Context::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
|
| + for (int i = 0; i < count; ++i) {
|
| + span[i] = fPM4f;
|
| + }
|
| +}
|
| +
|
| +// TODO: do we need an updated version of this method for color4+colorspace?
|
| +SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const {
|
| + if (info) {
|
| + if (info->fColors && info->fColorCount >= 1) {
|
| + info->fColors[0] = fCachedByteColor;
|
| + }
|
| + info->fColorCount = 1;
|
| + info->fTileMode = SkShader::kRepeat_TileMode;
|
| + }
|
| + return kColor_GradientType;
|
| +}
|
| +
|
| +#if SK_SUPPORT_GPU
|
| +
|
| +#include "SkGr.h"
|
| +#include "effects/GrConstColorProcessor.h"
|
| +const GrFragmentProcessor* SkColor4Shader::asFragmentProcessor(GrContext*, const SkMatrix&,
|
| + const SkMatrix*,
|
| + SkFilterQuality) const {
|
| + // TODO: how to communicate color4f to Gr
|
| + GrColor color = SkColorToPremulGrColor(fCachedByteColor);
|
| + return GrConstColorProcessor::Create(color, GrConstColorProcessor::kModulateA_InputMode);
|
| +}
|
| +
|
| +#endif
|
| +
|
| +#ifndef SK_IGNORE_TO_STRING
|
| +void SkColor4Shader::toString(SkString* str) const {
|
| + str->append("SkColor4Shader: (");
|
| +
|
| + str->append("ARGB:");
|
| + for (int i = 0; i < 4; ++i) {
|
| + str->appendf(" %g", fColor4.vec()[i]);
|
| + }
|
| + str->append(" )");
|
| +}
|
| +#endif
|
| +
|
| +sk_sp<SkShader> SkShader::MakeColorShader(const SkColor4f& color, sk_sp<SkColorSpace> space) {
|
| + if (!SkScalarsAreFinite(color.vec(), 4)) {
|
| + return nullptr;
|
| + }
|
| + return sk_make_sp<SkColor4Shader>(color, std::move(space));
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +static void D32_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
|
| + int count) {
|
| + SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
|
| + const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
|
| + proc(state->fXfer, dst.writable_addr32(x, y), src, count, nullptr);
|
| +}
|
| +
|
| +static void D32_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
|
| + int count, const SkAlpha aa[]) {
|
| + SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
|
| + const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
|
| + proc(state->fXfer, dst.writable_addr32(x, y), src, count, aa);
|
| +}
|
| +
|
| +static void F16_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
|
| + int count) {
|
| + SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
|
| + const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
|
| + proc(state->fXfer, dst.writable_addr64(x, y), src, count, nullptr);
|
| +}
|
| +
|
| +static void F16_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
|
| + int count, const SkAlpha aa[]) {
|
| + SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
|
| + const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
|
| + proc(state->fXfer, dst.writable_addr64(x, y), src, count, aa);
|
| +}
|
| +
|
| +static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info,
|
| + SkShader::Context::BlitState* state) {
|
| + uint32_t flags = SkXfermode::kSrcIsSingle_D32Flag;
|
| + if (pm4->a() == 1) {
|
| + flags |= SkXfermode::kSrcIsOpaque_D32Flag;
|
| + }
|
| + switch (info.colorType()) {
|
| + case kN32_SkColorType:
|
| + if (info.isSRGB()) {
|
| + flags |= SkXfermode::kDstIsSRGB_D32Flag;
|
| + }
|
| + state->fStorage[0] = (void*)SkXfermode::GetD32Proc(state->fXfer, flags);
|
| + state->fStorage[1] = (void*)pm4;
|
| + state->fBlitBW = D32_BlitBW;
|
| + state->fBlitAA = D32_BlitAA;
|
| + return true;
|
| + case kRGBA_F16_SkColorType:
|
| + state->fStorage[0] = (void*)SkXfermode::GetF16Proc(state->fXfer, flags);
|
| + state->fStorage[1] = (void*)pm4;
|
| + state->fBlitBW = F16_BlitBW;
|
| + state->fBlitAA = F16_BlitAA;
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +bool SkColorShader::ColorShaderContext::onChooseBlitProcs(const SkImageInfo& info,
|
| + BlitState* state) {
|
| + return choose_blitprocs(&fPM4f, info, state);
|
| +}
|
| +
|
| +bool SkColor4Shader::Color4Context::onChooseBlitProcs(const SkImageInfo& info, BlitState* state) {
|
| + return choose_blitprocs(&fPM4f, info, state);
|
| +}
|
|
|