/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkPM4fPriv_DEFINED #define SkPM4fPriv_DEFINED #include "SkColorData.h" #include "SkColorSpace.h" #include "SkColorSpacePriv.h" #include "SkColorSpaceXformSteps.h" #include "SkArenaAlloc.h" #include "SkPM4f.h" #include "SkRasterPipeline.h" #include "SkSRGB.h" #include "../jumper/SkJumper.h" // This file is mostly helper routines for doing color space management. // It probably wants a new name, and they likely don't need to be inline. // // There are two generations of routines in here, the old ones that assumed linear blending, // and the new ones assuming as-encoded blending. We're trying to move to the new as-encoded // ones and will hopefully eventually remove all the linear routines. // // We'll start with the new as-encoded routines first, // and shove all the old broken routines towards the bottom. static inline Sk4f Sk4f_fromL32(uint32_t px) { return SkNx_cast(Sk4b::Load(&px)) * (1/255.0f); } static inline uint32_t Sk4f_toL32(const Sk4f& px) { uint32_t l32; SkNx_cast(Sk4f_round(px * 255.0f)).store(&l32); return l32; } static inline SkPM4f premul_in_dst_colorspace(SkColor4f color4f, SkColorSpace* srcCS, SkColorSpace* dstCS) { // We treat untagged sources as sRGB. if (!srcCS) { srcCS = sk_srgb_singleton(); } // If dstCS is null, no color space transformation is needed (and apply() will just premul). if (!dstCS) { dstCS = srcCS; } // TODO: In the very common case of srcCS being sRGB, // can we precompute an sRGB -> dstCS SkColorSpaceXformSteps for each device and use it here? SkColorSpaceXformSteps(srcCS, kUnpremul_SkAlphaType, dstCS) .apply(color4f.vec()); return {{color4f.fR, color4f.fG, color4f.fB, color4f.fA}}; } static inline SkPM4f premul_in_dst_colorspace(SkColor c, SkColorSpace* dstCS) { SkColor4f color4f; swizzle_rb(Sk4f_fromL32(c)).store(color4f.vec()); // SkColors are always sRGB. return premul_in_dst_colorspace(color4f, sk_srgb_singleton(), dstCS); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Functions below this line are probably totally broken as far as color space management goes. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! static inline Sk4f Sk4f_fromS32(uint32_t px) { return { sk_linear_from_srgb[(px >> 0) & 0xff], sk_linear_from_srgb[(px >> 8) & 0xff], sk_linear_from_srgb[(px >> 16) & 0xff], (1/255.0f) * (px >> 24) }; } static inline uint32_t Sk4f_toS32(const Sk4f& px) { Sk4i rgb = sk_linear_to_srgb(px), srgb = { rgb[0], rgb[1], rgb[2], (int)(255.0f * px[3] + 0.5f) }; uint32_t s32; SkNx_cast(srgb).store(&s32); return s32; } static inline void append_gamut_transform(SkRasterPipeline* p, SkArenaAlloc* alloc, SkColorSpace* src, SkColorSpace* dst, SkAlphaType srcAT) { if (src == dst || !dst || !src) { return; } const SkMatrix44 *fromSrc = src-> toXYZD50(), *toDst = dst->fromXYZD50(); if (!fromSrc || !toDst) { SkDEBUGFAIL("We can't handle non-XYZ color spaces in append_gamut_transform()."); return; } // Slightly more sophisticated version of if (src == dst) if (src->toXYZD50Hash() == dst->toXYZD50Hash()) { return; } // Convert from 4x4 to (column-major) 3x4. SkMatrix44 m44(*toDst, *fromSrc); float* ptr = alloc->makeArrayDefault(12); *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, ptr-12); } #endif