/* * Copyright (c) 2024, Lucas Chollet * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include namespace Gfx { namespace Details { struct ColorSpaceImpl { sk_sp color_space; }; } ColorSpace::ColorSpace() : m_color_space(make()) { } ColorSpace::ColorSpace(ColorSpace const& other) : m_color_space(make(other.m_color_space->color_space)) { } ColorSpace& ColorSpace::operator=(ColorSpace const& other) { m_color_space = make(other.m_color_space->color_space); return *this; } ColorSpace::ColorSpace(ColorSpace&& other) = default; ColorSpace& ColorSpace::operator=(ColorSpace&&) = default; ColorSpace::~ColorSpace() = default; ColorSpace::ColorSpace(NonnullOwnPtr&& color_space) : m_color_space(move(color_space)) { } ErrorOr ColorSpace::from_cicp(Media::CodingIndependentCodePoints cicp) { if (cicp.matrix_coefficients() != Media::MatrixCoefficients::Identity) return Error::from_string_literal("Unsupported matrix coefficients for CICP"); if (cicp.video_full_range_flag() != Media::VideoFullRangeFlag::Full) return Error::from_string_literal("Unsupported matrix coefficients for CICP"); skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB; switch (cicp.color_primaries()) { case Media::ColorPrimaries::BT709: gamut = SkNamedGamut::kSRGB; break; case Media::ColorPrimaries::BT2020: gamut = SkNamedGamut::kRec2020; break; case Media::ColorPrimaries::XYZ: gamut = SkNamedGamut::kXYZ; break; case Media::ColorPrimaries::SMPTE432: gamut = SkNamedGamut::kDisplayP3; break; default: return Error::from_string_literal("FIXME: Unsupported color primaries"); } skcms_TransferFunction transfer_function = SkNamedTransferFn::kSRGB; switch (cicp.transfer_characteristics()) { case Media::TransferCharacteristics::Linear: transfer_function = SkNamedTransferFn::kLinear; break; case Media::TransferCharacteristics::SRGB: transfer_function = SkNamedTransferFn::kSRGB; break; case Media::TransferCharacteristics::SMPTE2084: transfer_function = SkNamedTransferFn::kPQ; break; case Media::TransferCharacteristics::HLG: transfer_function = SkNamedTransferFn::kHLG; break; default: return Error::from_string_literal("FIXME: Unsupported transfer function"); } return ColorSpace { make(SkColorSpace::MakeRGB(transfer_function, gamut)) }; } ErrorOr ColorSpace::load_from_icc_bytes(ReadonlyBytes icc_bytes) { if (icc_bytes.size() != 0) { skcms_ICCProfile icc_profile {}; if (!skcms_Parse(icc_bytes.data(), icc_bytes.size(), &icc_profile)) return Error::from_string_literal("Failed to parse the ICC profile"); return ColorSpace { make(SkColorSpace::Make(icc_profile)) }; } return ColorSpace {}; } template<> sk_sp& ColorSpace::color_space() { return m_color_space->color_space; } } namespace IPC { template<> ErrorOr encode(Encoder& encoder, Gfx::ColorSpace const& color_space) { if (!color_space.m_color_space->color_space) { TRY(encoder.encode(0)); return {}; } auto serialized = color_space.m_color_space->color_space->serialize(); TRY(encoder.encode(serialized->size())); TRY(encoder.append(serialized->bytes(), serialized->size())); return {}; } template<> ErrorOr decode(Decoder& decoder) { auto size = TRY(decoder.decode()); if (size == 0) return Gfx::ColorSpace {}; auto buffer = TRY(ByteBuffer::create_uninitialized(size)); TRY(decoder.decode_into(buffer.bytes())); auto color_space = SkColorSpace::Deserialize(buffer.data(), buffer.size()); return Gfx::ColorSpace { make<::Gfx::Details::ColorSpaceImpl>(move(color_space)) }; } }