Index: src/effects/gradients/Sk4fLinearGradient.cpp |
diff --git a/src/effects/gradients/Sk4fLinearGradient.cpp b/src/effects/gradients/Sk4fLinearGradient.cpp |
index 9bc84c49957d6a07ef8e70d10fc3176a10965ccb..82b2fcc69b33731ac3e8546e6aad04a01b7a3f39 100644 |
--- a/src/effects/gradients/Sk4fLinearGradient.cpp |
+++ b/src/effects/gradients/Sk4fLinearGradient.cpp |
@@ -5,16 +5,18 @@ |
* found in the LICENSE file. |
*/ |
-#include "Sk4fGradientPriv.h" |
#include "Sk4fLinearGradient.h" |
+#include "SkUtils.h" |
+#include "SkXfermode.h" |
namespace { |
-template<typename DstType, bool do_premul> |
+template<typename DstType, SkColorProfileType, ApplyPremul> |
void fill(const Sk4f& c, DstType* dst, int n); |
template<> |
-void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { |
+void fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False> |
+ (const Sk4f& c, SkPM4f* dst, int n) { |
while (n > 0) { |
c.store(dst++); |
n--; |
@@ -22,21 +24,49 @@ void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { |
} |
template<> |
-void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { |
- fill<SkPM4f, false>(premul_4f(c), dst, n); |
+void fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::True> |
+ (const Sk4f& c, SkPM4f* dst, int n) { |
+ fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False>(premul_4f(c), dst, n); |
} |
template<> |
-void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { |
- sk_memset32(dst, trunc_from_255<false>(c), n); |
+void fill<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False> |
+ (const Sk4f& c, SkPMColor* dst, int n) { |
+ sk_memset32(dst, trunc_from_4f_255<ApplyPremul::False>(c), n); |
} |
template<> |
-void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { |
- sk_memset32(dst, trunc_from_255<true>(c), n); |
+void fill<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::True> |
+ (const Sk4f& c, SkPMColor* dst, int n) { |
+ sk_memset32(dst, trunc_from_4f_255<ApplyPremul::True>(c), n); |
} |
-template<typename DstType, bool do_premul> |
+template<> |
+void fill<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::False> |
+ (const Sk4f& c, SkPMColor* dst, int n) { |
+ // FIXME: this assumes opaque colors. Handle unpremultiplication. |
+ sk_memset32(dst, Sk4f_toS32(c), n); |
+} |
+ |
+template<> |
+void fill<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::True> |
+ (const Sk4f& c, SkPMColor* dst, int n) { |
+ sk_memset32(dst, Sk4f_toS32(premul_4f(c)), n); |
+} |
+ |
+template<> |
+void fill<uint64_t, kLinear_SkColorProfileType, ApplyPremul::False> |
+ (const Sk4f& c, uint64_t* dst, int n) { |
+ sk_memset64(dst, SkFloatToHalf_01(c), n); |
+} |
+ |
+template<> |
+void fill<uint64_t, kLinear_SkColorProfileType, ApplyPremul::True> |
+ (const Sk4f& c, uint64_t* dst, int n) { |
+ sk_memset64(dst, SkFloatToHalf_01(premul_4f(c)), n); |
+} |
+ |
+template<typename DstType, SkColorProfileType profile, ApplyPremul premul> |
void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
SkASSERT(n > 0); |
@@ -49,7 +79,7 @@ void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
Sk4f c3 = c1 + dc2; |
while (n >= 4) { |
- store4x<DstType, do_premul>(c0, c1, c2, c3, dst); |
+ store4x<DstType, profile, premul>(c0, c1, c2, c3, dst); |
dst += 4; |
c0 = c0 + dc4; |
@@ -59,12 +89,12 @@ void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
n -= 4; |
} |
if (n & 2) { |
- store<DstType, do_premul>(c0, dst++); |
- store<DstType, do_premul>(c1, dst++); |
+ store<DstType, profile, premul>(c0, dst++); |
+ store<DstType, profile, premul>(c1, dst++); |
c0 = c0 + dc2; |
} |
if (n & 1) { |
- store<DstType, do_premul>(c0, dst); |
+ store<DstType, profile, premul>(c0, dst); |
} |
} |
@@ -163,9 +193,13 @@ LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { |
// TODO: plumb dithering |
SkASSERT(count > 0); |
if (fColorsArePremul) { |
- this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); |
+ this->shadePremulSpan<SkPMColor, |
+ kLinear_SkColorProfileType, |
+ ApplyPremul::False>(x, y, dst, count); |
} else { |
- this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); |
+ this->shadePremulSpan<SkPMColor, |
+ kLinear_SkColorProfileType, |
+ ApplyPremul::True>(x, y, dst, count); |
} |
} |
@@ -179,13 +213,17 @@ LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { |
// TONOTDO: plumb dithering |
SkASSERT(count > 0); |
if (fColorsArePremul) { |
- this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); |
+ this->shadePremulSpan<SkPM4f, |
+ kLinear_SkColorProfileType, |
+ ApplyPremul::False>(x, y, dst, count); |
} else { |
- this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); |
+ this->shadePremulSpan<SkPM4f, |
+ kLinear_SkColorProfileType, |
+ ApplyPremul::True>(x, y, dst, count); |
} |
} |
-template<typename DstType, bool do_premul> |
+template<typename DstType, SkColorProfileType profile, ApplyPremul premul> |
void SkLinearGradient:: |
LinearGradient4fContext::shadePremulSpan(int x, int y, |
DstType dst[], |
@@ -195,23 +233,27 @@ LinearGradient4fContext::shadePremulSpan(int x, int y, |
switch (shader.fTileMode) { |
case kClamp_TileMode: |
this->shadeSpanInternal<DstType, |
- do_premul, |
+ profile, |
+ premul, |
kClamp_TileMode>(x, y, dst, count); |
break; |
case kRepeat_TileMode: |
this->shadeSpanInternal<DstType, |
- do_premul, |
+ profile, |
+ premul, |
kRepeat_TileMode>(x, y, dst, count); |
break; |
case kMirror_TileMode: |
this->shadeSpanInternal<DstType, |
- do_premul, |
+ profile, |
+ premul, |
kMirror_TileMode>(x, y, dst, count); |
break; |
} |
} |
-template<typename DstType, bool do_premul, SkShader::TileMode tileMode> |
+template<typename DstType, SkColorProfileType profile, ApplyPremul premul, |
+ SkShader::TileMode tileMode> |
void SkLinearGradient:: |
LinearGradient4fContext::shadeSpanInternal(int x, int y, |
DstType dst[], |
@@ -223,12 +265,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, |
&pt); |
const SkScalar fx = pinFx<tileMode>(pt.x()); |
const SkScalar dx = fDstToPos.getScaleX(); |
- LinearIntervalProcessor<DstType, tileMode> proc(fIntervals.begin(), |
- fIntervals.end() - 1, |
- this->findInterval(fx), |
- fx, |
- dx, |
- SkScalarNearlyZero(dx * count)); |
+ LinearIntervalProcessor<DstType, profile, tileMode> proc(fIntervals.begin(), |
+ fIntervals.end() - 1, |
+ this->findInterval(fx), |
+ fx, |
+ dx, |
+ SkScalarNearlyZero(dx * count)); |
while (count > 0) { |
// What we really want here is SkTPin(advance, 1, count) |
// but that's a significant perf hit for >> stops; investigate. |
@@ -243,12 +285,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, |
|| (n == count && proc.currentRampIsZero())); |
if (proc.currentRampIsZero()) { |
- fill<DstType, do_premul>(proc.currentColor(), |
- dst, n); |
+ fill<DstType, profile, premul>(proc.currentColor(), |
+ dst, n); |
} else { |
- ramp<DstType, do_premul>(proc.currentColor(), |
- proc.currentColorGrad(), |
- dst, n); |
+ ramp<DstType, profile, premul>(proc.currentColor(), |
+ proc.currentColorGrad(), |
+ dst, n); |
} |
proc.advance(SkIntToScalar(n)); |
@@ -257,7 +299,7 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, |
} |
} |
-template<typename DstType, SkShader::TileMode tileMode> |
+template<typename DstType, SkColorProfileType profile, SkShader::TileMode tileMode> |
class SkLinearGradient:: |
LinearGradient4fContext::LinearIntervalProcessor { |
public: |
@@ -267,8 +309,7 @@ public: |
SkScalar fx, |
SkScalar dx, |
bool is_vertical) |
- : fDstComponentScale(dst_component_scale<DstType>()) |
- , fAdvX((i->fP1 - fx) / dx) |
+ : fAdvX((i->fP1 - fx) / dx) |
, fFirstInterval(firstInterval) |
, fLastInterval(lastInterval) |
, fInterval(i) |
@@ -308,8 +349,8 @@ private: |
fDc = dst_swizzle<DstType>(fInterval->fDc); |
fCc = dst_swizzle<DstType>(fInterval->fC0); |
fCc = fCc + fDc * Sk4f(t); |
- fCc = fCc * fDstComponentScale; |
- fDcDx = fDc * fDstComponentScale * Sk4f(fDx); |
+ fCc = scale_for_dest<DstType, profile>(fCc); |
+ fDcDx = scale_for_dest<DstType, profile>(fDc * Sk4f(fDx)); |
fZeroRamp = fIsVertical || fInterval->isZeroRamp(); |
} |
@@ -342,8 +383,6 @@ private: |
return advX; |
} |
- const Sk4f fDstComponentScale; // cached dst scale (PMC: 255, PM4f: 1) |
- |
// Current interval properties. |
Sk4f fDc; // local color gradient (dc/dt) |
Sk4f fDcDx; // dst color gradient (dc/dx) |
@@ -402,3 +441,68 @@ LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { |
} |
} |
} |
+ |
+SkShader::Context::BlitProc SkLinearGradient:: |
+LinearGradient4fContext::onChooseBlitProc(const SkImageInfo& info, BlitState* state) { |
+ SkXfermode::Mode mode; |
+ if (!SkXfermode::AsMode(state->fXfer, &mode)) { |
+ return nullptr; |
+ } |
+ |
+ const SkGradientShaderBase& shader = static_cast<const SkGradientShaderBase&>(fShader); |
+ if (mode != SkXfermode::kSrc_Mode && |
+ !(mode == SkXfermode::kSrcOver_Mode && shader.colorsAreOpaque())) { |
+ return nullptr; |
+ } |
+ |
+ switch (info.colorType()) { |
+ case kN32_SkColorType: |
+ return D32_BlitProc; |
+ case kRGBA_F16_SkColorType: |
+ return D64_BlitProc; |
+ default: |
+ return nullptr; |
+ } |
+} |
+ |
+void SkLinearGradient:: |
+LinearGradient4fContext::D32_BlitProc(BlitState* state, int x, int y, const SkPixmap& dst, |
+ int count, const SkAlpha aa[]) { |
+ // FIXME: ignoring coverage for now |
+ const LinearGradient4fContext* ctx = |
+ static_cast<const LinearGradient4fContext*>(state->fCtx); |
+ |
+ if (dst.info().isLinear()) { |
+ if (ctx->fColorsArePremul) { |
+ ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False>( |
+ x, y, dst.writable_addr32(x, y), count); |
+ } else { |
+ ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::True>( |
+ x, y, dst.writable_addr32(x, y), count); |
+ } |
+ } else { |
+ if (ctx->fColorsArePremul) { |
+ ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::False>( |
+ x, y, dst.writable_addr32(x, y), count); |
+ } else { |
+ ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::True>( |
+ x, y, dst.writable_addr32(x, y), count); |
+ } |
+ } |
+} |
+ |
+void SkLinearGradient:: |
+LinearGradient4fContext::D64_BlitProc(BlitState* state, int x, int y, const SkPixmap& dst, |
+ int count, const SkAlpha aa[]) { |
+ // FIXME: ignoring coverage for now |
+ const LinearGradient4fContext* ctx = |
+ static_cast<const LinearGradient4fContext*>(state->fCtx); |
+ |
+ if (ctx->fColorsArePremul) { |
+ ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, ApplyPremul::False>( |
+ x, y, dst.writable_addr64(x, y), count); |
+ } else { |
+ ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, ApplyPremul::True>( |
+ x, y, dst.writable_addr64(x, y), count); |
+ } |
+} |