1// LAF OS Library
2// Copyright (C) 2018-2021 Igara Studio S.A.
3//
4// This file is released under the terms of the MIT license.
5// Read LICENSE.txt for more information.
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "os/skia/skia_color_space.h"
12
13#include "base/debug.h"
14
15#include "include/core/SkImageInfo.h"
16#include "include/core/SkString.h"
17#include "include/third_party/skcms/skcms.h"
18#include "src/core/SkConvertPixels.h"
19
20#include <algorithm>
21
22// Defined in skia/src/core/SkICC.cpp
23const char* get_color_profile_description(const skcms_TransferFunction& fn,
24 const skcms_Matrix3x3& toXYZD50);
25
26namespace os {
27
28// Copied from skia/src/core/SkColorSpacePriv.h
29static constexpr float gSRGB_toXYZD50[] {
30 0.4360747f, 0.3850649f, 0.1430804f, // Rx, Gx, Bx
31 0.2225045f, 0.7168786f, 0.0606169f, // Ry, Gy, By
32 0.0139322f, 0.0971045f, 0.7141733f, // Rz, Gz, Bz
33};
34
35SkiaColorSpace::SkiaColorSpace(const gfx::ColorSpaceRef& gfxcs)
36 : m_gfxcs(gfxcs),
37 m_skcs(nullptr)
38{
39 switch (m_gfxcs->type()) {
40
41 case gfx::ColorSpace::None:
42 if (m_gfxcs->name().empty())
43 m_gfxcs->setName("None");
44 break;
45
46 case gfx::ColorSpace::sRGB:
47 case gfx::ColorSpace::RGB:
48 if (gfxcs->hasGamma()) {
49 if (gfxcs->gamma() == 1.0)
50 m_skcs = SkColorSpace::MakeSRGBLinear();
51 else {
52 skcms_TransferFunction fn;
53 fn.a = 1.0f;
54 fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f;
55 fn.g = gfxcs->gamma();
56 m_skcs = SkColorSpace::MakeRGB(fn, SkNamedGamut::kSRGB);
57 }
58 }
59 else {
60 skcms_TransferFunction skFn;
61 skcms_Matrix3x3 toXYZD50;
62
63 if (m_gfxcs->hasPrimaries()) {
64 const gfx::ColorSpacePrimaries* primaries = m_gfxcs->primaries();
65 if (!skcms_PrimariesToXYZD50(primaries->rx, primaries->ry,
66 primaries->gx, primaries->gy,
67 primaries->bx, primaries->by,
68 primaries->wx, primaries->wy, &toXYZD50)) {
69 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
70 }
71 }
72
73 if (m_gfxcs->hasTransferFn()) {
74 const gfx::ColorSpaceTransferFn* fn = m_gfxcs->transferFn();
75 skFn.g = fn->g;
76 skFn.a = fn->a;
77 skFn.b = fn->b;
78 skFn.c = fn->c;
79 skFn.d = fn->d;
80 skFn.e = fn->e;
81 skFn.f = fn->f;
82 }
83
84 if (m_gfxcs->hasTransferFn()) {
85 if (!m_gfxcs->hasPrimaries()) {
86 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
87 }
88 m_skcs = SkColorSpace::MakeRGB(skFn, toXYZD50);
89 }
90 else if (m_gfxcs->hasPrimaries()) {
91 m_skcs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, toXYZD50);
92 }
93 else {
94 m_skcs = SkColorSpace::MakeSRGB();
95 }
96 }
97 break;
98
99 case gfx::ColorSpace::ICC: {
100 skcms_ICCProfile icc;
101 if (skcms_Parse(m_gfxcs->iccData(),
102 m_gfxcs->iccSize(), &icc)) {
103 m_skcs = SkColorSpace::Make(icc);
104 }
105 break;
106 }
107 }
108
109 // TODO read color profile name from ICC data
110
111 if (m_skcs && m_gfxcs->name().empty()) {
112 skcms_TransferFunction fn;
113 skcms_Matrix3x3 toXYZD50;
114 if (m_skcs->isNumericalTransferFn(&fn) &&
115 m_skcs->toXYZD50(&toXYZD50)) {
116 const char* desc = get_color_profile_description(fn, toXYZD50);
117 if (desc)
118 m_gfxcs->setName(desc);
119 }
120 }
121
122 if (m_gfxcs->name().empty())
123 m_gfxcs->setName("Custom Profile");
124}
125
126SkiaColorSpaceConversion::SkiaColorSpaceConversion(
127 const os::ColorSpaceRef& srcColorSpace,
128 const os::ColorSpaceRef& dstColorSpace)
129 : m_srcCS(srcColorSpace),
130 m_dstCS(dstColorSpace)
131{
132 ASSERT(srcColorSpace);
133 ASSERT(dstColorSpace);
134}
135
136bool SkiaColorSpaceConversion::convertRgba(uint32_t* dst, const uint32_t* src, int n)
137{
138 auto dstInfo = SkImageInfo::Make(n, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType,
139 static_cast<const SkiaColorSpace*>(m_dstCS.get())->skColorSpace());
140 auto srcInfo = SkImageInfo::Make(n, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType,
141 static_cast<const SkiaColorSpace*>(m_srcCS.get())->skColorSpace());
142 return SkConvertPixels(dstInfo, dst, 4 * n, srcInfo, src, 4 * n);
143}
144
145bool SkiaColorSpaceConversion::convertGray(uint8_t* dst, const uint8_t* src, int n)
146{
147 auto dstInfo = SkImageInfo::Make(n, 1, kGray_8_SkColorType, kOpaque_SkAlphaType,
148 static_cast<const SkiaColorSpace*>(m_dstCS.get())->skColorSpace());
149 auto srcInfo = SkImageInfo::Make(n, 1, kGray_8_SkColorType, kOpaque_SkAlphaType,
150 static_cast<const SkiaColorSpace*>(m_srcCS.get())->skColorSpace());
151 return SkConvertPixels(dstInfo, dst, n, srcInfo, src, n);
152}
153
154} // namespace os
155