aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkColorShader.cpp9
-rw-r--r--src/core/SkPM4fPriv.h51
2 files changed, 57 insertions, 3 deletions
diff --git a/src/core/SkColorShader.cpp b/src/core/SkColorShader.cpp
index a761d605fa..69d9e46b27 100644
--- a/src/core/SkColorShader.cpp
+++ b/src/core/SkColorShader.cpp
@@ -320,7 +320,10 @@ bool SkColorShader::onAppendStages(SkRasterPipeline* p,
auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
p->append(SkRasterPipeline::move_src_dst);
p->append(SkRasterPipeline::constant_color, color);
- // TODO: sRGB -> dst gamut correction if needed
+ if (!append_gamut_transform(p, scratch,
+ SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dst)) {
+ return false;
+ }
p->append(SkRasterPipeline::srcin);
return true;
}
@@ -331,7 +334,9 @@ bool SkColor4Shader::onAppendStages(SkRasterPipeline* p,
auto color = scratch->make<SkPM4f>(fColor4.premul());
p->append(SkRasterPipeline::move_src_dst);
p->append(SkRasterPipeline::constant_color, color);
- // TODO: fColorSpace -> dst gamut correction if needed
+ if (!append_gamut_transform(p, scratch, fColorSpace.get(), dst)) {
+ return false;
+ }
p->append(SkRasterPipeline::srcin);
return true;
}
diff --git a/src/core/SkPM4fPriv.h b/src/core/SkPM4fPriv.h
index f70c5c5a53..304a49ffdd 100644
--- a/src/core/SkPM4fPriv.h
+++ b/src/core/SkPM4fPriv.h
@@ -10,7 +10,10 @@
#include "SkColorPriv.h"
#include "SkColorSpace.h"
+#include "SkColorSpace_Base.h"
+#include "SkFixedAlloc.h"
#include "SkPM4f.h"
+#include "SkRasterPipeline.h"
#include "SkSRGB.h"
static inline Sk4f set_alpha(const Sk4f& px, float alpha) {
@@ -72,12 +75,58 @@ static inline float exact_srgb_to_linear(float srgb) {
return linear;
}
+
+// N.B. scratch_matrix_3x4 must live at least as long as p.
+static inline bool append_gamut_transform(SkRasterPipeline* p, float scratch_matrix_3x4[12],
+ SkColorSpace* src, SkColorSpace* dst) {
+ if (src == dst) { return true; }
+ if (!dst) { return true; } // Legacy modes intentionally ignore color gamut.
+ if (!src) { return true; } // A null src color space means linear gamma, dst gamut.
+
+ auto toXYZ = as_CSB(src)-> toXYZD50(),
+ fromXYZ = as_CSB(dst)->fromXYZD50();
+ if (!toXYZ || !fromXYZ) { return false; } // Unsupported color space type.
+
+ if (as_CSB(src)->toXYZD50Hash() == as_CSB(dst)->toXYZD50Hash()) { return true; }
+
+ SkMatrix44 m44(*fromXYZ, *toXYZ);
+
+ // Convert from 4x4 to (column-major) 3x4.
+ auto ptr = scratch_matrix_3x4;
+ *ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0);
+ *ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1);
+ *ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2);
+ *ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3);
+
+ p->append(SkRasterPipeline::matrix_3x4, scratch_matrix_3x4);
+ // TODO: detect whether we can skip the clamps?
+ p->append(SkRasterPipeline::clamp_0);
+ p->append(SkRasterPipeline::clamp_a);
+ return true;
+}
+
+static inline bool append_gamut_transform(SkRasterPipeline* p, SkFallbackAlloc* scratch,
+ SkColorSpace* src, SkColorSpace* dst) {
+ struct matrix_3x4 { float arr[12]; };
+ return append_gamut_transform(p, scratch->make<matrix_3x4>()->arr, src, dst);
+}
+
static inline SkPM4f SkPM4f_from_SkColor(SkColor color, SkColorSpace* dst) {
SkColor4f color4f;
if (dst) {
// sRGB gamma, sRGB gamut.
color4f = SkColor4f::FromColor(color);
- // TODO: gamut transform if needed
+ void* color4f_ptr = &color4f;
+
+ float scratch_matrix_3x4[12];
+
+ SkRasterPipeline p;
+ p.append(SkRasterPipeline::constant_color, color4f_ptr);
+ append_gamut_transform(&p, scratch_matrix_3x4,
+ SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dst);
+ p.append(SkRasterPipeline::store_f32, &color4f_ptr);
+
+ p.compile()(0,1);
} else {
// Linear gamma, dst gamut.
swizzle_rb(SkNx_cast<float>(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f);