blob: 1add88c8b1fa4add87fa58ef49bc161a86ec24b1 [file] [log] [blame]
/*
* Copyright (C) 2020-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "ColorComponents.h"
#include "ColorMatrix.h"
#include "ColorModels.h"
#include "ColorTransferFunctions.h"
namespace WebCore {
enum class WhitePoint { D50, D65 };
template<typename, typename> struct BoundedGammaEncoded;
template<typename, typename> struct BoundedLinearEncoded;
template<typename, typename> struct ExtendedGammaEncoded;
template<typename, typename> struct ExtendedLinearEncoded;
template<typename> struct HSLA;
template<typename> struct HWBA;
template<typename> struct LCHA;
template<typename> struct Lab;
template<typename> struct OKLCHA;
template<typename> struct OKLab;
template<typename, WhitePoint> struct XYZA;
// MARK: Make functions.
template<typename ColorType, typename T> constexpr ColorType makeFromComponents(const ColorComponents<T, 4>& c)
{
return ColorType { c[0], c[1], c[2], c[3] };
}
template<typename ColorType, unsigned Index, typename T> constexpr auto clampedComponent(T c) -> typename ColorType::ComponentType
{
static_assert(std::is_integral_v<T>);
constexpr auto componentInfo = ColorType::Model::componentInfo[Index];
return std::clamp<T>(c, componentInfo.min, componentInfo.max);
}
template<typename ColorType, unsigned Index> constexpr float clampedComponent(float c)
{
constexpr auto componentInfo = ColorType::Model::componentInfo[Index];
if constexpr (componentInfo.min == -std::numeric_limits<float>::infinity() && componentInfo.max == std::numeric_limits<float>::infinity())
return c;
if constexpr (componentInfo.min == -std::numeric_limits<float>::infinity())
return std::min(c, componentInfo.max);
if constexpr (componentInfo.max == std::numeric_limits<float>::infinity())
return std::max(c, componentInfo.min);
return std::clamp(c, componentInfo.min, componentInfo.max);
}
template<typename ColorType, unsigned Index, typename T> constexpr T clampedComponent(const ColorComponents<T, 4>& c)
{
return clampedComponent<ColorType, Index>(c[Index]);
}
template<typename T, typename ComponentType = T> constexpr ComponentType clampedAlpha(T alpha)
{
return std::clamp<T>(alpha, AlphaTraits<ComponentType>::transparent, AlphaTraits<ComponentType>::opaque);
}
template<typename ColorType, typename T> constexpr ColorComponents<T, 4> clampedComponents(const ColorComponents<T, 4>& components)
{
return { clampedComponent<ColorType, 0>(components), clampedComponent<ColorType, 1>(components), clampedComponent<ColorType, 2>(components), clampedAlpha(components[3]) };
}
template<typename ColorType, typename T> constexpr ColorComponents<T, 4> clampedComponentsExceptAlpha(const ColorComponents<T, 4>& components)
{
return { clampedComponent<ColorType, 0>(components), clampedComponent<ColorType, 1>(components), clampedComponent<ColorType, 2>(components), components[3] };
}
template<typename ColorType, typename T> constexpr ColorType makeFromComponentsClamping(const ColorComponents<T, 4>& components)
{
return makeFromComponents<ColorType>(clampedComponents<ColorType>(components));
}
template<typename ColorType, typename T> constexpr ColorType makeFromComponentsClamping(T c1, T c2, T c3)
{
return makeFromComponents<ColorType>(ColorComponents { clampedComponent<ColorType, 0>(c1), clampedComponent<ColorType, 1>(c2), clampedComponent<ColorType, 2>(c3), AlphaTraits<typename ColorType::ComponentType>::opaque });
}
template<typename ColorType, typename T> constexpr ColorType makeFromComponentsClamping(T c1, T c2, T c3, T alpha)
{
return makeFromComponents<ColorType>(ColorComponents { clampedComponent<ColorType, 0>(c1), clampedComponent<ColorType, 1>(c2), clampedComponent<ColorType, 2>(c3), clampedAlpha<T, typename ColorType::ComponentType>(alpha) });
}
template<typename ColorType, typename T> constexpr ColorType makeFromComponentsClampingExceptAlpha(const ColorComponents<T, 4>& components)
{
return makeFromComponents<ColorType>(clampedComponentsExceptAlpha<ColorType>(components));
}
template<typename ColorType, typename T, typename Alpha> constexpr ColorType makeFromComponentsClampingExceptAlpha(T c1, T c2, T c3, Alpha alpha)
{
return makeFromComponents<ColorType>(ColorComponents { clampedComponent<ColorType, 0>(c1), clampedComponent<ColorType, 1>(c2), clampedComponent<ColorType, 2>(c3), alpha });
}
#if ASSERT_ENABLED
template<typename T> constexpr void assertInRange(T color)
{
if constexpr (std::is_same_v<typename T::ComponentType, float>) {
auto components = asColorComponents(color);
for (unsigned i = 0; i < 3; ++i) {
ASSERT_WITH_MESSAGE(components[i] >= T::Model::componentInfo[i].min, "Component at index %d is %f and is less than the allowed minimum %f", i, components[i], T::Model::componentInfo[i].min);
ASSERT_WITH_MESSAGE(components[i] <= T::Model::componentInfo[i].max, "Component at index %d is %f and is greater than the allowed maximum %f", i, components[i], T::Model::componentInfo[i].max);
}
ASSERT_WITH_MESSAGE(color.alpha >= AlphaTraits<typename T::ComponentType>::transparent, "Alpha is %f and is less than the allowed minimum (transparent) %f", color.alpha, AlphaTraits<typename T::ComponentType>::transparent);
ASSERT_WITH_MESSAGE(color.alpha <= AlphaTraits<typename T::ComponentType>::opaque, "Alpha is %f and is greater than the allowed maximum (opaque) %f", color.alpha, AlphaTraits<typename T::ComponentType>::opaque);
}
}
#else
template<typename T> constexpr void assertInRange(T)
{
}
#endif
template<typename, typename = void> inline constexpr bool IsConvertibleToColorComponents = false;
template<typename T> inline constexpr bool IsConvertibleToColorComponents<T, std::void_t<decltype(asColorComponents(std::declval<T>()))>> = true;
template<typename, typename = void> inline constexpr bool HasComponentTypeMember = false;
template<typename T> inline constexpr bool HasComponentTypeMember<T, std::void_t<typename T::ComponentType>> = true;
template<typename T, typename U, bool enabled> inline constexpr bool HasComponentTypeValue = false;
template<typename T, typename U> inline constexpr bool HasComponentTypeValue<T, U, true> = std::is_same_v<typename T::ComponentType, U>;
template<typename T, typename U> inline constexpr bool HasComponentType = HasComponentTypeValue<T, U, HasComponentTypeMember<T>>;
template<typename T> inline constexpr bool IsColorType = IsConvertibleToColorComponents<T> && HasComponentTypeMember<T>;
template<typename T, typename U> inline constexpr bool IsColorTypeWithComponentType = IsConvertibleToColorComponents<T> && HasComponentType<T, U>;
template<template<typename> class ColorType, typename Replacement> struct ColorTypeReplacingComponentTypeHelper { using type = ColorType<Replacement>; };
template<template<typename> class ColorType, typename Replacement> using ColorTypeReplacingComponentType = typename ColorTypeReplacingComponentTypeHelper<ColorType, Replacement>::type;
template<typename Parent> struct ColorWithAlphaHelper {
// Helper to allow convenient syntax for working with color types.
// e.g. auto yellowWith50PercentAlpha = Color::yellow.colorWithAlphaByte(128);
constexpr Parent colorWithAlphaByte(uint8_t overrideAlpha) const
{
static_assert(std::is_same_v<decltype(std::declval<Parent>().alpha), uint8_t>, "Only uint8_t based color types are supported.");
auto copy = *static_cast<const Parent*>(this);
copy.alpha = overrideAlpha;
return copy;
}
};
template<typename ColorType, typename std::enable_if_t<IsConvertibleToColorComponents<ColorType>>* = nullptr>
constexpr bool operator==(const ColorType& a, const ColorType& b)
{
return asColorComponents(a) == asColorComponents(b);
}
template<typename ColorType, typename std::enable_if_t<IsConvertibleToColorComponents<ColorType>>* = nullptr>
constexpr bool operator!=(const ColorType& a, const ColorType& b)
{
return !(a == b);
}
// MARK: - RGB Color Types.
template<typename T, typename D, typename ColorType, typename M, typename TF> struct RGBAType : ColorWithAlphaHelper<ColorType> {
using ComponentType = T;
using Model = M;
using TransferFunction = TF;
using Descriptor = D;
static constexpr auto whitePoint = D::whitePoint;
constexpr RGBAType(T red, T green, T blue, T alpha = AlphaTraits<T>::opaque)
: red { red }
, green { green }
, blue { blue }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr RGBAType()
: RGBAType { 0, 0, 0, 0 }
{
}
T red;
T green;
T blue;
T alpha;
};
template<typename T, typename D, typename ColorType, typename M, typename TF> constexpr ColorComponents<T, 4> asColorComponents(const RGBAType<T, D, ColorType, M, TF>& c)
{
return { c.red, c.green, c.blue, c.alpha };
}
template<typename T, typename D>
struct BoundedGammaEncoded : RGBAType<T, D, BoundedGammaEncoded<T, D>, RGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Clamped>> {
using RGBAType<T, D, BoundedGammaEncoded<T, D>, RGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Clamped>>::RGBAType;
using LinearCounterpart = BoundedLinearEncoded<T, D>;
using ExtendedCounterpart = ExtendedGammaEncoded<T, D>;
template<typename Replacement> using SelfWithReplacementComponent = BoundedGammaEncoded<Replacement, D>;
};
template<typename T, typename D>
struct BoundedLinearEncoded : RGBAType<T, D, BoundedLinearEncoded<T, D>, RGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Clamped>> {
using RGBAType<T, D, BoundedLinearEncoded<T, D>, RGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Clamped>>::RGBAType;
static constexpr auto linearToXYZ = D::linearToXYZ;
static constexpr auto xyzToLinear = D::xyzToLinear;
using GammaEncodedCounterpart = BoundedGammaEncoded<T, D>;
using ExtendedCounterpart = ExtendedLinearEncoded<T, D>;
template<typename Replacement> using SelfWithReplacementComponent = BoundedLinearEncoded<Replacement, D>;
};
template<typename T, typename D>
struct ExtendedGammaEncoded : RGBAType<T, D, ExtendedGammaEncoded<T, D>, ExtendedRGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Unclamped>> {
using RGBAType<T, D, ExtendedGammaEncoded<T, D>, ExtendedRGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Unclamped>>::RGBAType;
using LinearCounterpart = ExtendedLinearEncoded<T, D>;
using BoundedCounterpart = BoundedGammaEncoded<T, D>;
using Reference = LinearCounterpart;
};
template<typename T, typename D>
struct ExtendedLinearEncoded : RGBAType<T, D, ExtendedLinearEncoded<T, D>, ExtendedRGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Unclamped>> {
using RGBAType<T, D, ExtendedLinearEncoded<T, D>, ExtendedRGBModel<T>, typename D::template TransferFunction<T, TransferFunctionMode::Unclamped>>::RGBAType;
static constexpr auto linearToXYZ = D::linearToXYZ;
static constexpr auto xyzToLinear = D::xyzToLinear;
using GammaEncodedCounterpart = ExtendedGammaEncoded<T, D>;
using BoundedCounterpart = BoundedLinearEncoded<T, D>;
using Reference = XYZA<T, D::whitePoint>;
};
template<typename, typename = void> inline constexpr bool HasDescriptorMember = false;
template<typename ColorType> inline constexpr bool HasDescriptorMember<ColorType, std::void_t<typename ColorType::Descriptor>> = true;
template<typename, typename = void> inline constexpr bool HasExtendedCounterpartMember = false;
template<typename ColorType> inline constexpr bool HasExtendedCounterpartMember<ColorType, std::void_t<typename ColorType::ExtendedCounterpart>> = true;
template<typename, typename = void> inline constexpr bool HasBoundedCounterpartMember = false;
template<typename ColorType> inline constexpr bool HasBoundedCounterpartMember<ColorType, std::void_t<typename ColorType::BoundedCounterpart>> = true;
template<typename, typename = void> inline constexpr bool HasGammaEncodedCounterpartMember = false;
template<typename ColorType> inline constexpr bool HasGammaEncodedCounterpartMember<ColorType, std::void_t<typename ColorType::GammaEncodedCounterpart>> = true;
template<typename, typename = void> inline constexpr bool HasLinearCounterpartMember = false;
template<typename ColorType> inline constexpr bool HasLinearCounterpartMember<ColorType, std::void_t<typename ColorType::LinearCounterpart>> = true;
template<typename, typename = void> inline constexpr bool HasSelfWithReplacementComponentMember = false;
template<typename ColorType> inline constexpr bool HasSelfWithReplacementComponentMember<ColorType, std::void_t<typename ColorType::SelfWithReplacementComponent>> = true;
template<typename ColorType, typename Replacement> using ColorTypeWithReplacementComponent = typename ColorType::template SelfWithReplacementComponent<Replacement>;
template<typename ColorType> inline constexpr bool IsRGBType = HasDescriptorMember<ColorType>;
template<typename ColorType> inline constexpr bool IsRGBExtendedType = IsRGBType<ColorType> && HasBoundedCounterpartMember<ColorType>;
template<typename ColorType> inline constexpr bool IsRGBBoundedType = IsRGBType<ColorType> && HasExtendedCounterpartMember<ColorType>;
template<typename ColorType> inline constexpr bool IsRGBGammaEncodedType = IsRGBType<ColorType> && HasLinearCounterpartMember<ColorType>;
template<typename ColorType> inline constexpr bool IsRGBLinearEncodedType = IsRGBType<ColorType> && HasGammaEncodedCounterpartMember<ColorType>;
template<typename ColorType1, typename ColorType2, bool enabled> inline constexpr bool IsSameRGBTypeFamilyValue = false;
template<typename ColorType1, typename ColorType2> inline constexpr bool IsSameRGBTypeFamilyValue<ColorType1, ColorType2, true> = std::is_same_v<typename ColorType1::Descriptor, typename ColorType2::Descriptor>;
template<typename ColorType1, typename ColorType2> inline constexpr bool IsSameRGBTypeFamily = IsSameRGBTypeFamilyValue<ColorType1, ColorType2, IsRGBType<ColorType1> && IsRGBType<ColorType2>>;
struct SRGBADescriptor {
template<typename T, TransferFunctionMode Mode> using TransferFunction = SRGBTransferFunction<T, Mode>;
static constexpr auto whitePoint = WhitePoint::D65;
// https://drafts.csswg.org/css-color/#color-conversion-code
static constexpr ColorMatrix<3, 3> xyzToLinear {
3.2409699419045226f, -1.537383177570094f, -0.4986107602930034f,
-0.9692436362808796f, 1.8759675015077202f, 0.04155505740717559f,
0.05563007969699366f, -0.20397695888897652f, 1.0569715142428786f
};
static constexpr ColorMatrix<3, 3> linearToXYZ {
0.41239079926595934f, 0.357584339383878f, 0.1804807884018343f,
0.21263900587151027f, 0.715168678767756f, 0.07219231536073371f,
0.01933081871559182f, 0.11919477979462598f, 0.9505321522496607f
};
};
template<typename T> using SRGBA = BoundedGammaEncoded<T, SRGBADescriptor>;
template<typename T> using LinearSRGBA = BoundedLinearEncoded<T, SRGBADescriptor>;
template<typename T> using ExtendedSRGBA = ExtendedGammaEncoded<T, SRGBADescriptor>;
template<typename T> using LinearExtendedSRGBA = ExtendedLinearEncoded<T, SRGBADescriptor>;
struct A98RGBDescriptor {
template<typename T, TransferFunctionMode Mode> using TransferFunction = A98RGBTransferFunction<T, Mode>;
static constexpr auto whitePoint = WhitePoint::D65;
// https://drafts.csswg.org/css-color/#color-conversion-code
static constexpr ColorMatrix<3, 3> xyzToLinear {
2.493496911941425f, -0.9313836179191239f, -0.4027107844507168f,
-0.8294889695615747f, 1.7626640603183463f, 0.0236246858419436f,
0.0358458302437845f, -0.0761723892680418f, 0.9568845240076872f
};
static constexpr ColorMatrix<3, 3> linearToXYZ {
0.5766690429101305f, 0.1855582379065463f, 0.1882286462349947f,
0.29734497525053605f, 0.6273635662554661f, 0.07529145849399788f,
0.02703136138641234f, 0.07068885253582723f, 0.9913375368376388f
};
};
template<typename T> using A98RGB = BoundedGammaEncoded<T, A98RGBDescriptor>;
template<typename T> using LinearA98RGB = BoundedLinearEncoded<T, A98RGBDescriptor>;
struct DisplayP3Descriptor {
template<typename T, TransferFunctionMode Mode> using TransferFunction = SRGBTransferFunction<T, Mode>;
static constexpr auto whitePoint = WhitePoint::D65;
// https://drafts.csswg.org/css-color/#color-conversion-code
static constexpr ColorMatrix<3, 3> xyzToLinear {
2.493496911941425f, -0.9313836179191239f, -0.4027107844507168f,
-0.8294889695615747f, 1.7626640603183463f, 0.0236246858419436f,
0.0358458302437845f, -0.0761723892680418f, 0.9568845240076872f
};
static constexpr ColorMatrix<3, 3> linearToXYZ {
0.4865709486482162f, 0.2656676931690931f, 0.198217285234363f,
0.2289745640697488f, 0.6917385218365064f, 0.079286914093745f,
0.0f, 0.0451133818589026f, 1.043944368900976f
};
};
template<typename T> using DisplayP3 = BoundedGammaEncoded<T, DisplayP3Descriptor>;
template<typename T> using LinearDisplayP3 = BoundedLinearEncoded<T, DisplayP3Descriptor>;
struct ProPhotoRGBDescriptor {
template<typename T, TransferFunctionMode Mode> using TransferFunction = ProPhotoRGBTransferFunction<T, Mode>;
static constexpr auto whitePoint = WhitePoint::D50;
// https://drafts.csswg.org/css-color/#color-conversion-code
static constexpr ColorMatrix<3, 3> xyzToLinear {
1.3457989731028281f, -0.25558010007997534f, -0.05110628506753401f,
-0.5446224939028347f, 1.5082327413132781f, 0.02053603239147973f,
0.0f, 0.0f, 1.2119675456389454f
};
static constexpr ColorMatrix<3, 3> linearToXYZ {
0.7977604896723027f, 0.13518583717574031f, 0.0313493495815248f,
0.2880711282292934f, 0.7118432178101014f, 0.00008565396060525902f,
0.0f, 0.0f, 0.8251046025104601f
};
};
template<typename T> using ProPhotoRGB = BoundedGammaEncoded<T, ProPhotoRGBDescriptor>;
template<typename T> using LinearProPhotoRGB = BoundedLinearEncoded<T, ProPhotoRGBDescriptor>;
struct Rec2020Descriptor {
template<typename T, TransferFunctionMode Mode> using TransferFunction = Rec2020TransferFunction<T, Mode>;
static constexpr auto whitePoint = WhitePoint::D65;
// https://drafts.csswg.org/css-color/#color-conversion-code
static constexpr ColorMatrix<3, 3> xyzToLinear {
1.7166511879712674f, -0.35567078377639233f, -0.25336628137365974f,
-0.6666843518324892f, 1.6164812366349395f, 0.01576854581391113f,
0.017639857445310783f, -0.042770613257808524f, 0.9421031212354738f
};
static constexpr ColorMatrix<3, 3> linearToXYZ {
0.6369580483012914f, 0.14461690358620832f, 0.1688809751641721f,
0.2627002120112671f, 0.6779980715188708f, 0.05930171646986196f,
0.000000000000000f, 0.028072693049087428f, 1.060985057710791f
};
};
template<typename T> using Rec2020 = BoundedGammaEncoded<T, Rec2020Descriptor>;
template<typename T> using LinearRec2020 = BoundedLinearEncoded<T, Rec2020Descriptor>;
// MARK: - Lab Color Type.
template<typename T> struct Lab : ColorWithAlphaHelper<Lab<T>> {
using ComponentType = T;
using Model = LabModel<T>;
static constexpr auto whitePoint = WhitePoint::D50;
using Reference = XYZA<T, whitePoint>;
constexpr Lab(T lightness, T a, T b, T alpha = AlphaTraits<T>::opaque)
: lightness { lightness }
, a { a }
, b { b }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr Lab()
: Lab { 0, 0, 0, 0 }
{
}
T lightness;
T a;
T b;
T alpha;
};
template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const Lab<T>& c)
{
return { c.lightness, c.a, c.b, c.alpha };
}
template<typename ColorType> inline constexpr bool IsLab = std::is_same_v<Lab<typename ColorType::ComponentType>, ColorType>;
// MARK: - LCHA Color Type.
template<typename T> struct LCHA : ColorWithAlphaHelper<LCHA<T>> {
using ComponentType = T;
using Model = LCHModel<T>;
static constexpr auto whitePoint = WhitePoint::D50;
using Reference = Lab<T>;
constexpr LCHA(T lightness, T chroma, T hue, T alpha = AlphaTraits<T>::opaque)
: lightness { lightness }
, chroma { chroma }
, hue { hue }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr LCHA()
: LCHA { 0, 0, 0, 0 }
{
}
T lightness;
T chroma;
T hue;
T alpha;
};
template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const LCHA<T>& c)
{
return { c.lightness, c.chroma, c.hue, c.alpha };
}
template<typename ColorType> inline constexpr bool IsLCHA = std::is_same_v<LCHA<typename ColorType::ComponentType>, ColorType>;
// MARK: - OKLab Color Type.
template<typename T> struct OKLab : ColorWithAlphaHelper<OKLab<T>> {
using ComponentType = T;
using Model = LabModel<T>;
static constexpr auto whitePoint = WhitePoint::D65;
using Reference = XYZA<T, whitePoint>;
constexpr OKLab(T lightness, T a, T b, T alpha = AlphaTraits<T>::opaque)
: lightness { lightness }
, a { a }
, b { b }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr OKLab()
: OKLab { 0, 0, 0, 0 }
{
}
T lightness;
T a;
T b;
T alpha;
};
template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const OKLab<T>& c)
{
return { c.lightness, c.a, c.b, c.alpha };
}
template<typename ColorType> inline constexpr bool IsOKLab = std::is_same_v<OKLab<typename ColorType::ComponentType>, ColorType>;
// MARK: - OKLCHA Color Type.
template<typename T> struct OKLCHA : ColorWithAlphaHelper<OKLCHA<T>> {
using ComponentType = T;
using Model = LCHModel<T>;
static constexpr auto whitePoint = WhitePoint::D65;
using Reference = OKLab<T>;
constexpr OKLCHA(T lightness, T chroma, T hue, T alpha = AlphaTraits<T>::opaque)
: lightness { lightness }
, chroma { chroma }
, hue { hue }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr OKLCHA()
: OKLCHA { 0, 0, 0, 0 }
{
}
T lightness;
T chroma;
T hue;
T alpha;
};
template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const OKLCHA<T>& c)
{
return { c.lightness, c.chroma, c.hue, c.alpha };
}
template<typename ColorType> inline constexpr bool IsOKLCHA = std::is_same_v<OKLCHA<typename ColorType::ComponentType>, ColorType>;
// MARK: - HSLA Color Type.
template<typename T> struct HSLA : ColorWithAlphaHelper<HSLA<T>> {
using ComponentType = T;
using Model = HSLModel<T>;
static constexpr auto whitePoint = WhitePoint::D65;
using Reference = SRGBA<T>;
constexpr HSLA(T hue, T saturation, T lightness, T alpha = AlphaTraits<T>::opaque)
: hue { hue }
, saturation { saturation }
, lightness { lightness }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr HSLA()
: HSLA { 0, 0, 0, 0 }
{
}
T hue;
T saturation;
T lightness;
T alpha;
};
template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const HSLA<T>& c)
{
return { c.hue, c.saturation, c.lightness, c.alpha };
}
template<typename ColorType> inline constexpr bool IsHSLA = std::is_same_v<HSLA<typename ColorType::ComponentType>, ColorType>;
// MARK: - HWBA Color Type.
template<typename T> struct HWBA : ColorWithAlphaHelper<HWBA<T>> {
using ComponentType = T;
using Model = HWBModel<T>;
static constexpr auto whitePoint = WhitePoint::D65;
using Reference = SRGBA<T>;
constexpr HWBA(T hue, T whiteness, T blackness, T alpha = AlphaTraits<T>::opaque)
: hue { hue }
, whiteness { whiteness }
, blackness { blackness }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr HWBA()
: HWBA { 0, 0, 0, 0 }
{
}
T hue;
T whiteness;
T blackness;
T alpha;
};
template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const HWBA<T>& c)
{
return { c.hue, c.whiteness, c.blackness, c.alpha };
}
template<typename ColorType> inline constexpr bool IsHWBA = std::is_same_v<HWBA<typename ColorType::ComponentType>, ColorType>;
// MARK: - XYZ Color Type.
template<typename T, WhitePoint W> struct XYZA : ColorWithAlphaHelper<XYZA<T, W>> {
using ComponentType = T;
using Model = XYZModel<T>;
using ReferenceXYZ = XYZA<T, W>;
static constexpr auto whitePoint = W;
constexpr XYZA(T x, T y, T z, T alpha = AlphaTraits<T>::opaque)
: x { x }
, y { y }
, z { z }
, alpha { alpha }
{
assertInRange(*this);
}
constexpr XYZA()
: XYZA { 0, 0, 0, 0 }
{
}
T x;
T y;
T z;
T alpha;
};
template<typename T, WhitePoint W> constexpr ColorComponents<T, 4> asColorComponents(const XYZA<T, W>& c)
{
return { c.x, c.y, c.z, c.alpha };
}
template<typename ColorType> inline constexpr bool IsXYZA = std::is_same_v<XYZA<typename ColorType::ComponentType, ColorType::whitePoint>, ColorType>;
// Packed Color Formats
namespace PackedColor {
struct RGBA {
constexpr explicit RGBA(uint32_t rgba)
: value { rgba }
{
}
constexpr explicit RGBA(SRGBA<uint8_t> color)
: value { static_cast<uint32_t>(color.red << 24 | color.green << 16 | color.blue << 8 | color.alpha) }
{
}
uint32_t value;
};
struct ARGB {
constexpr explicit ARGB(uint32_t argb)
: value { argb }
{
}
constexpr explicit ARGB(SRGBA<uint8_t> color)
: value { static_cast<uint32_t>(color.alpha << 24 | color.red << 16 | color.green << 8 | color.blue) }
{
}
uint32_t value;
};
}
constexpr SRGBA<uint8_t> asSRGBA(PackedColor::RGBA color)
{
return { static_cast<uint8_t>(color.value >> 24), static_cast<uint8_t>(color.value >> 16), static_cast<uint8_t>(color.value >> 8), static_cast<uint8_t>(color.value) };
}
constexpr SRGBA<uint8_t> asSRGBA(PackedColor::ARGB color)
{
return { static_cast<uint8_t>(color.value >> 16), static_cast<uint8_t>(color.value >> 8), static_cast<uint8_t>(color.value), static_cast<uint8_t>(color.value >> 24) };
}
} // namespace WebCore