1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/cfx_color.h"
8
9 #include <algorithm>
10
11 #include "third_party/base/notreached.h"
12
13 // Color types are ordered by increasing number of components so we can choose
14 // a best color type during some conversions.
15 static_assert(CFX_Color::Type::kTransparent < CFX_Color::Type::kGray,
16 "color type values must be ordered");
17 static_assert(CFX_Color::Type::kGray < CFX_Color::Type::kRGB,
18 "color type values must be ordered");
19 static_assert(CFX_Color::Type::kRGB < CFX_Color::Type::kCMYK,
20 "color type values must be ordered");
21
22 namespace {
23
InRange(float comp)24 bool InRange(float comp) {
25 return comp >= 0.0f && comp <= 1.0f;
26 }
27
ConvertCMYK2GRAY(float dC,float dM,float dY,float dK)28 CFX_Color ConvertCMYK2GRAY(float dC, float dM, float dY, float dK) {
29 if (!InRange(dC) || !InRange(dM) || !InRange(dY) || !InRange(dK))
30 return CFX_Color(CFX_Color::Type::kGray);
31 return CFX_Color(
32 CFX_Color::Type::kGray,
33 1.0f - std::min(1.0f, 0.3f * dC + 0.59f * dM + 0.11f * dY + dK));
34 }
35
ConvertGRAY2CMYK(float dGray)36 CFX_Color ConvertGRAY2CMYK(float dGray) {
37 if (!InRange(dGray))
38 return CFX_Color(CFX_Color::Type::kCMYK);
39 return CFX_Color(CFX_Color::Type::kCMYK, 0.0f, 0.0f, 0.0f, 1.0f - dGray);
40 }
41
ConvertGRAY2RGB(float dGray)42 CFX_Color ConvertGRAY2RGB(float dGray) {
43 if (!InRange(dGray))
44 return CFX_Color(CFX_Color::Type::kRGB);
45 return CFX_Color(CFX_Color::Type::kRGB, dGray, dGray, dGray);
46 }
47
ConvertRGB2GRAY(float dR,float dG,float dB)48 CFX_Color ConvertRGB2GRAY(float dR, float dG, float dB) {
49 if (!InRange(dR) || !InRange(dG) || !InRange(dB))
50 return CFX_Color(CFX_Color::Type::kGray);
51 return CFX_Color(CFX_Color::Type::kGray, 0.3f * dR + 0.59f * dG + 0.11f * dB);
52 }
53
ConvertCMYK2RGB(float dC,float dM,float dY,float dK)54 CFX_Color ConvertCMYK2RGB(float dC, float dM, float dY, float dK) {
55 if (!InRange(dC) || !InRange(dM) || !InRange(dY) || !InRange(dK))
56 return CFX_Color(CFX_Color::Type::kRGB);
57 return CFX_Color(CFX_Color::Type::kRGB, 1.0f - std::min(1.0f, dC + dK),
58 1.0f - std::min(1.0f, dM + dK),
59 1.0f - std::min(1.0f, dY + dK));
60 }
61
ConvertRGB2CMYK(float dR,float dG,float dB)62 CFX_Color ConvertRGB2CMYK(float dR, float dG, float dB) {
63 if (!InRange(dR) || !InRange(dG) || !InRange(dB))
64 return CFX_Color(CFX_Color::Type::kCMYK);
65
66 float c = 1.0f - dR;
67 float m = 1.0f - dG;
68 float y = 1.0f - dB;
69 return CFX_Color(CFX_Color::Type::kCMYK, c, m, y,
70 std::min(c, std::min(m, y)));
71 }
72
73 } // namespace
74
ConvertColorType(Type nConvertColorType) const75 CFX_Color CFX_Color::ConvertColorType(Type nConvertColorType) const {
76 if (nColorType == nConvertColorType)
77 return *this;
78
79 CFX_Color ret;
80 switch (nColorType) {
81 case CFX_Color::Type::kTransparent:
82 ret = *this;
83 ret.nColorType = CFX_Color::Type::kTransparent;
84 break;
85 case CFX_Color::Type::kGray:
86 switch (nConvertColorType) {
87 case CFX_Color::Type::kTransparent:
88 break;
89 case CFX_Color::Type::kGray:
90 NOTREACHED();
91 break;
92 case CFX_Color::Type::kRGB:
93 ret = ConvertGRAY2RGB(fColor1);
94 break;
95 case CFX_Color::Type::kCMYK:
96 ret = ConvertGRAY2CMYK(fColor1);
97 break;
98 }
99 break;
100 case CFX_Color::Type::kRGB:
101 switch (nConvertColorType) {
102 case CFX_Color::Type::kTransparent:
103 break;
104 case CFX_Color::Type::kGray:
105 ret = ConvertRGB2GRAY(fColor1, fColor2, fColor3);
106 break;
107 case CFX_Color::Type::kRGB:
108 NOTREACHED();
109 break;
110 case CFX_Color::Type::kCMYK:
111 ret = ConvertRGB2CMYK(fColor1, fColor2, fColor3);
112 break;
113 }
114 break;
115 case CFX_Color::Type::kCMYK:
116 switch (nConvertColorType) {
117 case CFX_Color::Type::kTransparent:
118 break;
119 case CFX_Color::Type::kGray:
120 ret = ConvertCMYK2GRAY(fColor1, fColor2, fColor3, fColor4);
121 break;
122 case CFX_Color::Type::kRGB:
123 ret = ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4);
124 break;
125 case CFX_Color::Type::kCMYK:
126 NOTREACHED();
127 break;
128 }
129 break;
130 }
131 return ret;
132 }
133
ToFXColor(int32_t nTransparency) const134 FX_COLORREF CFX_Color::ToFXColor(int32_t nTransparency) const {
135 CFX_Color ret;
136 switch (nColorType) {
137 case CFX_Color::Type::kTransparent: {
138 ret = CFX_Color(CFX_Color::Type::kTransparent, 0, 0, 0, 0);
139 break;
140 }
141 case CFX_Color::Type::kGray: {
142 ret = ConvertGRAY2RGB(fColor1);
143 ret.fColor4 = nTransparency;
144 break;
145 }
146 case CFX_Color::Type::kRGB: {
147 ret = CFX_Color(CFX_Color::Type::kRGB, fColor1, fColor2, fColor3);
148 ret.fColor4 = nTransparency;
149 break;
150 }
151 case CFX_Color::Type::kCMYK: {
152 ret = ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4);
153 ret.fColor4 = nTransparency;
154 break;
155 }
156 }
157 return ArgbEncode(ret.fColor4, static_cast<int32_t>(ret.fColor1 * 255),
158 static_cast<int32_t>(ret.fColor2 * 255),
159 static_cast<int32_t>(ret.fColor3 * 255));
160 }
161
operator -(float fColorSub) const162 CFX_Color CFX_Color::operator-(float fColorSub) const {
163 CFX_Color sRet(nColorType);
164 switch (nColorType) {
165 case CFX_Color::Type::kTransparent:
166 sRet.nColorType = CFX_Color::Type::kRGB;
167 sRet.fColor1 = std::max(1.0f - fColorSub, 0.0f);
168 sRet.fColor2 = std::max(1.0f - fColorSub, 0.0f);
169 sRet.fColor3 = std::max(1.0f - fColorSub, 0.0f);
170 break;
171 case CFX_Color::Type::kRGB:
172 case CFX_Color::Type::kGray:
173 case CFX_Color::Type::kCMYK:
174 sRet.fColor1 = std::max(fColor1 - fColorSub, 0.0f);
175 sRet.fColor2 = std::max(fColor2 - fColorSub, 0.0f);
176 sRet.fColor3 = std::max(fColor3 - fColorSub, 0.0f);
177 sRet.fColor4 = std::max(fColor4 - fColorSub, 0.0f);
178 break;
179 }
180 return sRet;
181 }
182
operator /(float fColorDivide) const183 CFX_Color CFX_Color::operator/(float fColorDivide) const {
184 CFX_Color sRet(nColorType);
185 switch (nColorType) {
186 case CFX_Color::Type::kTransparent:
187 sRet.nColorType = CFX_Color::Type::kRGB;
188 sRet.fColor1 = 1.0f / fColorDivide;
189 sRet.fColor2 = 1.0f / fColorDivide;
190 sRet.fColor3 = 1.0f / fColorDivide;
191 break;
192 case CFX_Color::Type::kRGB:
193 case CFX_Color::Type::kGray:
194 case CFX_Color::Type::kCMYK:
195 sRet = *this;
196 sRet.fColor1 /= fColorDivide;
197 sRet.fColor2 /= fColorDivide;
198 sRet.fColor3 /= fColorDivide;
199 sRet.fColor4 /= fColorDivide;
200 break;
201 }
202 return sRet;
203 }
204