Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(336)

Side by Side Diff: ui/gfx/color_transform.cc

Issue 2663453002: Revert of Use SkICC in gfx::ICCProfile and gfx::ColorSpace (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/color_transform.h ('k') | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/color_transform.h" 5 #include "ui/gfx/color_transform.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "ui/gfx/color_space.h" 11 #include "ui/gfx/color_space.h"
12 #include "ui/gfx/icc_profile.h" 12 #include "ui/gfx/icc_profile.h"
13 #include "ui/gfx/transform.h" 13 #include "ui/gfx/transform.h"
14 #include "third_party/qcms/src/qcms.h" 14 #include "third_party/qcms/src/qcms.h"
15 15
16 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H 16 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H
17 extern "C" { 17 extern "C" {
18 #include "third_party/qcms/src/chain.h" 18 #include "third_party/qcms/src/chain.h"
19 }; 19 };
20 #endif 20 #endif
21 21
22 namespace gfx { 22 namespace gfx {
23 23
24 float EvalSkTransferFn(const SkColorSpaceTransferFn& fn, float x) {
25 if (x < 0)
26 return 0;
27 if (x < fn.fD)
28 return fn.fC * x + fn.fF;
29 return powf(fn.fA * x + fn.fB, fn.fG) + fn.fE;
30 }
31
32 Transform Invert(const Transform& t) { 24 Transform Invert(const Transform& t) {
33 Transform ret = t; 25 Transform ret = t;
34 if (!t.GetInverse(&ret)) { 26 if (!t.GetInverse(&ret)) {
35 LOG(ERROR) << "Inverse should alsways be possible."; 27 LOG(ERROR) << "Inverse should alsways be possible.";
36 } 28 }
37 return ret; 29 return ret;
38 } 30 }
39 31
40 float FromLinear(ColorSpace::TransferID id, float v) { 32 GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) {
33 SkColorSpacePrimaries primaries = {0};
34 switch (id) {
35 case ColorSpace::PrimaryID::CUSTOM:
36 NOTREACHED();
37
38 case ColorSpace::PrimaryID::RESERVED0:
39 case ColorSpace::PrimaryID::RESERVED:
40 case ColorSpace::PrimaryID::UNSPECIFIED:
41 case ColorSpace::PrimaryID::UNKNOWN:
42 case ColorSpace::PrimaryID::BT709:
43 // BT709 is our default case. Put it after the switch just
44 // in case we somehow get an id which is not listed in the switch.
45 // (We don't want to use "default", because we want the compiler
46 // to tell us if we forgot some enum values.)
47 primaries.fRX = 0.640f;
48 primaries.fRY = 0.330f;
49 primaries.fGX = 0.300f;
50 primaries.fGY = 0.600f;
51 primaries.fBX = 0.150f;
52 primaries.fBY = 0.060f;
53 primaries.fWX = 0.3127f;
54 primaries.fWY = 0.3290f;
55 break;
56
57 case ColorSpace::PrimaryID::BT470M:
58 primaries.fRX = 0.67f;
59 primaries.fRY = 0.33f;
60 primaries.fGX = 0.21f;
61 primaries.fGY = 0.71f;
62 primaries.fBX = 0.14f;
63 primaries.fBY = 0.08f;
64 primaries.fWX = 0.31f;
65 primaries.fWY = 0.316f;
66 break;
67
68 case ColorSpace::PrimaryID::BT470BG:
69 primaries.fRX = 0.64f;
70 primaries.fRY = 0.33f;
71 primaries.fGX = 0.29f;
72 primaries.fGY = 0.60f;
73 primaries.fBX = 0.15f;
74 primaries.fBY = 0.06f;
75 primaries.fWX = 0.3127f;
76 primaries.fWY = 0.3290f;
77 break;
78
79 case ColorSpace::PrimaryID::SMPTE170M:
80 case ColorSpace::PrimaryID::SMPTE240M:
81 primaries.fRX = 0.630f;
82 primaries.fRY = 0.340f;
83 primaries.fGX = 0.310f;
84 primaries.fGY = 0.595f;
85 primaries.fBX = 0.155f;
86 primaries.fBY = 0.070f;
87 primaries.fWX = 0.3127f;
88 primaries.fWY = 0.3290f;
89 break;
90
91 case ColorSpace::PrimaryID::FILM:
92 primaries.fRX = 0.681f;
93 primaries.fRY = 0.319f;
94 primaries.fGX = 0.243f;
95 primaries.fGY = 0.692f;
96 primaries.fBX = 0.145f;
97 primaries.fBY = 0.049f;
98 primaries.fWX = 0.310f;
99 primaries.fWY = 0.136f;
100 break;
101
102 case ColorSpace::PrimaryID::BT2020:
103 primaries.fRX = 0.708f;
104 primaries.fRY = 0.292f;
105 primaries.fGX = 0.170f;
106 primaries.fGY = 0.797f;
107 primaries.fBX = 0.131f;
108 primaries.fBY = 0.046f;
109 primaries.fWX = 0.3127f;
110 primaries.fWY = 0.3290f;
111 break;
112
113 case ColorSpace::PrimaryID::SMPTEST428_1:
114 primaries.fRX = 1.0f;
115 primaries.fRY = 0.0f;
116 primaries.fGX = 0.0f;
117 primaries.fGY = 1.0f;
118 primaries.fBX = 0.0f;
119 primaries.fBY = 0.0f;
120 primaries.fWX = 1.0f / 3.0f;
121 primaries.fWY = 1.0f / 3.0f;
122 break;
123
124 case ColorSpace::PrimaryID::SMPTEST431_2:
125 primaries.fRX = 0.680f;
126 primaries.fRY = 0.320f;
127 primaries.fGX = 0.265f;
128 primaries.fGY = 0.690f;
129 primaries.fBX = 0.150f;
130 primaries.fBY = 0.060f;
131 primaries.fWX = 0.314f;
132 primaries.fWY = 0.351f;
133 break;
134
135 case ColorSpace::PrimaryID::SMPTEST432_1:
136 primaries.fRX = 0.680f;
137 primaries.fRY = 0.320f;
138 primaries.fGX = 0.265f;
139 primaries.fGY = 0.690f;
140 primaries.fBX = 0.150f;
141 primaries.fBY = 0.060f;
142 primaries.fWX = 0.3127f;
143 primaries.fWY = 0.3290f;
144 break;
145
146 case ColorSpace::PrimaryID::XYZ_D50:
147 primaries.fRX = 1.0f;
148 primaries.fRY = 0.0f;
149 primaries.fGX = 0.0f;
150 primaries.fGY = 1.0f;
151 primaries.fBX = 0.0f;
152 primaries.fBY = 0.0f;
153 primaries.fWX = 0.34567f;
154 primaries.fWY = 0.35850f;
155 break;
156 }
157
158 SkMatrix44 matrix;
159 primaries.toXYZD50(&matrix);
160 return Transform(matrix);
161 }
162
163 GFX_EXPORT float FromLinear(ColorSpace::TransferID id, float v) {
41 switch (id) { 164 switch (id) {
42 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: 165 case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
43 // Should already be handled. 166 // Should already be handled.
167 NOTREACHED();
168 case ColorSpace::TransferID::CUSTOM:
169 // TODO(hubbe): Actually implement custom transfer functions.
170 case ColorSpace::TransferID::RESERVED0:
171 case ColorSpace::TransferID::RESERVED:
172 case ColorSpace::TransferID::UNSPECIFIED:
173 case ColorSpace::TransferID::UNKNOWN:
174 // All unknown values default to BT709
175
176 case ColorSpace::TransferID::BT709:
177 case ColorSpace::TransferID::SMPTE170M:
178 case ColorSpace::TransferID::BT2020_10:
179 case ColorSpace::TransferID::BT2020_12:
180 // BT709 is our "default" cause, so put the code after the switch
181 // to avoid "control reaches end of non-void function" errors.
44 break; 182 break;
45 183
184 case ColorSpace::TransferID::GAMMA22:
185 v = fmax(0.0f, v);
186 return powf(v, 1.0f / 2.2f);
187
188 case ColorSpace::TransferID::GAMMA28:
189 v = fmax(0.0f, v);
190 return powf(v, 1.0f / 2.8f);
191
192 case ColorSpace::TransferID::SMPTE240M: {
193 v = fmax(0.0f, v);
194 float a = 1.11157219592173128753f;
195 float b = 0.02282158552944503135f;
196 if (v <= b) {
197 return 4.0f * v;
198 } else {
199 return a * powf(v, 0.45f) - (a - 1.0f);
200 }
201 }
202
203 case ColorSpace::TransferID::LINEAR:
204 return v;
205
46 case ColorSpace::TransferID::LOG: 206 case ColorSpace::TransferID::LOG:
47 if (v < 0.01f) 207 if (v < 0.01f)
48 return 0.0f; 208 return 0.0f;
49 return 1.0f + log(v) / log(10.0f) / 2.0f; 209 return 1.0f + log(v) / log(10.0f) / 2.0f;
50 210
51 case ColorSpace::TransferID::LOG_SQRT: 211 case ColorSpace::TransferID::LOG_SQRT:
52 if (v < sqrt(10.0f) / 1000.0f) 212 if (v < sqrt(10.0f) / 1000.0f)
53 return 0.0f; 213 return 0.0f;
54 return 1.0f + log(v) / log(10.0f) / 2.5f; 214 return 1.0f + log(v) / log(10.0f) / 2.5f;
55 215
(...skipping 15 matching lines...) Expand all
71 float l = 0.0045f; 231 float l = 0.0045f;
72 if (v < -l) { 232 if (v < -l) {
73 return -(a * powf(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f; 233 return -(a * powf(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f;
74 } else if (v <= b) { 234 } else if (v <= b) {
75 return 4.5f * v; 235 return 4.5f * v;
76 } else { 236 } else {
77 return a * powf(v, 0.45f) - (a - 1.0f); 237 return a * powf(v, 0.45f) - (a - 1.0f);
78 } 238 }
79 } 239 }
80 240
241 case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
242 v = fmax(0.0f, v);
243 float a = 1.055f;
244 float b = 0.0031308f;
245 if (v < b) {
246 return 12.92f * v;
247 } else {
248 return a * powf(v, 1.0f / 2.4f) - (a - 1.0f);
249 }
250 }
81 case ColorSpace::TransferID::SMPTEST2084: { 251 case ColorSpace::TransferID::SMPTEST2084: {
82 // Go from scRGB levels to 0-1. 252 // Go from scRGB levels to 0-1.
83 v *= 80.0f / 10000.0f; 253 v *= 80.0f / 10000.0f;
84 v = fmax(0.0f, v); 254 v = fmax(0.0f, v);
85 float m1 = (2610.0f / 4096.0f) / 4.0f; 255 float m1 = (2610.0f / 4096.0f) / 4.0f;
86 float m2 = (2523.0f / 4096.0f) * 128.0f; 256 float m2 = (2523.0f / 4096.0f) * 128.0f;
87 float c1 = 3424.0f / 4096.0f; 257 float c1 = 3424.0f / 4096.0f;
88 float c2 = (2413.0f / 4096.0f) * 32.0f; 258 float c2 = (2413.0f / 4096.0f) * 32.0f;
89 float c3 = (2392.0f / 4096.0f) * 32.0f; 259 float c3 = (2392.0f / 4096.0f) * 32.0f;
90 return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2); 260 return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2);
91 } 261 }
92 262
263 case ColorSpace::TransferID::SMPTEST428_1:
264 v = fmax(0.0f, v);
265 return powf(48.0f * v + 52.37f, 1.0f / 2.6f);
266
93 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf 267 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf
94 case ColorSpace::TransferID::ARIB_STD_B67: { 268 case ColorSpace::TransferID::ARIB_STD_B67: {
95 const float a = 0.17883277f; 269 const float a = 0.17883277f;
96 const float b = 0.28466892f; 270 const float b = 0.28466892f;
97 const float c = 0.55991073f; 271 const float c = 0.55991073f;
98 v = fmax(0.0f, v); 272 v = fmax(0.0f, v);
99 if (v <= 1) 273 if (v <= 1)
100 return 0.5f * sqrtf(v); 274 return 0.5f * sqrtf(v);
101 else 275 else
102 return a * log(v - b) + c; 276 return a * log(v - b) + c;
103 } 277 }
104 278
105 default: 279 // Chrome-specific values below
106 // Handled by SkColorSpaceTransferFn. 280 case ColorSpace::TransferID::GAMMA24:
107 break; 281 v = fmax(0.0f, v);
282 return powf(v, 1.0f / 2.4f);
108 } 283 }
109 NOTREACHED(); 284
110 return 0; 285 v = fmax(0.0f, v);
286 float a = 1.099296826809442f;
287 float b = 0.018053968510807f;
288 if (v <= b) {
289 return 4.5f * v;
290 } else {
291 return a * powf(v, 0.45f) - (a - 1.0f);
292 }
111 } 293 }
112 294
113 float ToLinear(ColorSpace::TransferID id, float v) { 295 GFX_EXPORT float ToLinear(ColorSpace::TransferID id, float v) {
114 switch (id) { 296 switch (id) {
297 case ColorSpace::TransferID::CUSTOM:
298 // TODO(hubbe): Actually implement custom transfer functions.
299 case ColorSpace::TransferID::RESERVED0:
300 case ColorSpace::TransferID::RESERVED:
301 case ColorSpace::TransferID::UNSPECIFIED:
302 case ColorSpace::TransferID::UNKNOWN:
303 // All unknown values default to BT709
304
305 case ColorSpace::TransferID::BT709:
306 case ColorSpace::TransferID::SMPTE170M:
307 case ColorSpace::TransferID::BT2020_10:
308 case ColorSpace::TransferID::BT2020_12:
309 // BT709 is our "default" cause, so put the code after the switch
310 // to avoid "control reaches end of non-void function" errors.
311 break;
312
313 case ColorSpace::TransferID::GAMMA22:
314 v = fmax(0.0f, v);
315 return powf(v, 2.2f);
316
317 case ColorSpace::TransferID::GAMMA28:
318 v = fmax(0.0f, v);
319 return powf(v, 2.8f);
320
321 case ColorSpace::TransferID::SMPTE240M: {
322 v = fmax(0.0f, v);
323 float a = 1.11157219592173128753f;
324 float b = 0.02282158552944503135f;
325 if (v <= FromLinear(ColorSpace::TransferID::SMPTE240M, b)) {
326 return v / 4.0f;
327 } else {
328 return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
329 }
330 }
331
332 case ColorSpace::TransferID::LINEAR:
333 return v;
334
115 case ColorSpace::TransferID::LOG: 335 case ColorSpace::TransferID::LOG:
116 if (v < 0.0f) 336 if (v < 0.0f)
117 return 0.0f; 337 return 0.0f;
118 return powf(10.0f, (v - 1.0f) * 2.0f); 338 return powf(10.0f, (v - 1.0f) * 2.0f);
119 339
120 case ColorSpace::TransferID::LOG_SQRT: 340 case ColorSpace::TransferID::LOG_SQRT:
121 if (v < 0.0f) 341 if (v < 0.0f)
122 return 0.0f; 342 return 0.0f;
123 return powf(10.0f, (v - 1.0f) * 2.5f); 343 return powf(10.0f, (v - 1.0f) * 2.5f);
124 344
(...skipping 15 matching lines...) Expand all
140 float l = 0.0045f; 360 float l = 0.0045f;
141 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) { 361 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) {
142 return -powf((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f; 362 return -powf((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f;
143 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) { 363 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) {
144 return v / 4.5f; 364 return v / 4.5f;
145 } else { 365 } else {
146 return powf((v + a - 1.0f) / a, 1.0f / 0.45f); 366 return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
147 } 367 }
148 } 368 }
149 369
370 case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
371 v = fmax(0.0f, v);
372 float a = 1.055f;
373 float b = 0.0031308f;
374 if (v < FromLinear(ColorSpace::TransferID::IEC61966_2_1, b)) {
375 return v / 12.92f;
376 } else {
377 return powf((v + a - 1.0f) / a, 2.4f);
378 }
379 }
380
150 case ColorSpace::TransferID::SMPTEST2084: { 381 case ColorSpace::TransferID::SMPTEST2084: {
151 v = fmax(0.0f, v); 382 v = fmax(0.0f, v);
152 float m1 = (2610.0f / 4096.0f) / 4.0f; 383 float m1 = (2610.0f / 4096.0f) / 4.0f;
153 float m2 = (2523.0f / 4096.0f) * 128.0f; 384 float m2 = (2523.0f / 4096.0f) * 128.0f;
154 float c1 = 3424.0f / 4096.0f; 385 float c1 = 3424.0f / 4096.0f;
155 float c2 = (2413.0f / 4096.0f) * 32.0f; 386 float c2 = (2413.0f / 4096.0f) * 32.0f;
156 float c3 = (2392.0f / 4096.0f) * 32.0f; 387 float c3 = (2392.0f / 4096.0f) * 32.0f;
157 v = powf( 388 v = powf(
158 fmax(powf(v, 1.0f / m2) - c1, 0) / (c2 - c3 * powf(v, 1.0f / m2)), 389 fmax(powf(v, 1.0f / m2) - c1, 0) / (c2 - c3 * powf(v, 1.0f / m2)),
159 1.0f / m1); 390 1.0f / m1);
160 // This matches the scRGB definition that 1.0 means 80 nits. 391 // This matches the scRGB definition that 1.0 means 80 nits.
161 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but 392 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but
162 // that might be difficult to do right now. 393 // that might be difficult to do right now.
163 v *= 10000.0f / 80.0f; 394 v *= 10000.0f / 80.0f;
164 return v; 395 return v;
165 } 396 }
166 397
398 case ColorSpace::TransferID::SMPTEST428_1:
399 return (powf(v, 2.6f) - 52.37f) / 48.0f;
400
401 // Chrome-specific values below
402 case ColorSpace::TransferID::GAMMA24:
403 v = fmax(0.0f, v);
404 return powf(v, 2.4f);
405
167 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: 406 case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
168 v = fmax(0.0f, v); 407 v = fmax(0.0f, v);
169 return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f); 408 return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f);
170 409
171 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf 410 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf
172 case ColorSpace::TransferID::ARIB_STD_B67: { 411 case ColorSpace::TransferID::ARIB_STD_B67: {
173 v = fmax(0.0f, v); 412 v = fmax(0.0f, v);
174 const float a = 0.17883277f; 413 const float a = 0.17883277f;
175 const float b = 0.28466892f; 414 const float b = 0.28466892f;
176 const float c = 0.55991073f; 415 const float c = 0.55991073f;
177 float v_ = 0.0f; 416 float v_ = 0.0f;
178 if (v <= 0.5f) { 417 if (v <= 0.5f) {
179 v_ = (v * 2.0f) * (v * 2.0f); 418 v_ = (v * 2.0f) * (v * 2.0f);
180 } else { 419 } else {
181 v_ = exp((v - c) / a) + b; 420 v_ = exp((v - c) / a) + b;
182 } 421 }
183 return v_; 422 return v_;
184 } 423 }
424 }
185 425
186 default: 426 v = fmax(0.0f, v);
187 // Handled by SkColorSpaceTransferFn. 427 float a = 1.099296826809442f;
188 break; 428 float b = 0.018053968510807f;
429 if (v < FromLinear(ColorSpace::TransferID::BT709, b)) {
430 return v / 4.5f;
431 } else {
432 return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
189 } 433 }
190 NOTREACHED();
191 return 0;
192 } 434 }
193 435
194 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) { 436 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) {
195 // Default values for BT709; 437 // Default values for BT709;
196 float Kr = 0.2126f; 438 float Kr = 0.2126f;
197 float Kb = 0.0722f; 439 float Kb = 0.0722f;
198 switch (id) { 440 switch (id) {
199 case ColorSpace::MatrixID::RGB: 441 case ColorSpace::MatrixID::RGB:
200 return Transform(); 442 return Transform();
201 443
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 for (size_t i = 0; i < num; i++) 610 for (size_t i = 0; i < num; i++)
369 matrix_.TransformPoint(colors + i); 611 matrix_.TransformPoint(colors + i);
370 } 612 }
371 613
372 private: 614 private:
373 Transform matrix_; 615 Transform matrix_;
374 }; 616 };
375 617
376 class ColorTransformFromLinear : public ColorTransformInternal { 618 class ColorTransformFromLinear : public ColorTransformInternal {
377 public: 619 public:
378 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer, 620 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer)
379 const SkColorSpaceTransferFn& fn, 621 : transfer_(transfer) {}
380 bool fn_valid)
381 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {}
382 bool Prepend(ColorTransformInternal* prev) override { 622 bool Prepend(ColorTransformInternal* prev) override {
383 return prev->Join(*this); 623 return prev->Join(*this);
384 } 624 }
385 625
386 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } 626 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; }
387 627
388 void transform(ColorTransform::TriStim* colors, size_t num) override { 628 void transform(ColorTransform::TriStim* colors, size_t num) override {
389 if (fn_valid_) { 629 for (size_t i = 0; i < num; i++) {
390 for (size_t i = 0; i < num; i++) { 630 colors[i].set_x(FromLinear(transfer_, colors[i].x()));
391 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x())); 631 colors[i].set_y(FromLinear(transfer_, colors[i].y()));
392 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y())); 632 colors[i].set_z(FromLinear(transfer_, colors[i].z()));
393 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z()));
394 }
395 } else {
396 for (size_t i = 0; i < num; i++) {
397 colors[i].set_x(FromLinear(transfer_, colors[i].x()));
398 colors[i].set_y(FromLinear(transfer_, colors[i].y()));
399 colors[i].set_z(FromLinear(transfer_, colors[i].z()));
400 }
401 } 633 }
402 } 634 }
403 635
404 private: 636 private:
405 friend class ColorTransformToLinear; 637 friend class ColorTransformToLinear;
406 ColorSpace::TransferID transfer_; 638 ColorSpace::TransferID transfer_;
407 SkColorSpaceTransferFn fn_;
408 bool fn_valid_ = false;
409 }; 639 };
410 640
411 class ColorTransformToLinear : public ColorTransformInternal { 641 class ColorTransformToLinear : public ColorTransformInternal {
412 public: 642 public:
413 explicit ColorTransformToLinear(ColorSpace::TransferID transfer, 643 explicit ColorTransformToLinear(ColorSpace::TransferID transfer)
414 const SkColorSpaceTransferFn& fn, 644 : transfer_(transfer) {}
415 bool fn_valid)
416 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {}
417 645
418 bool Prepend(ColorTransformInternal* prev) override { 646 bool Prepend(ColorTransformInternal* prev) override {
419 return prev->Join(*this); 647 return prev->Join(*this);
420 } 648 }
421 649
422 static bool IsGamma22(ColorSpace::TransferID transfer) { 650 static bool IsGamma22(ColorSpace::TransferID transfer) {
423 switch (transfer) { 651 switch (transfer) {
424 // We don't need to check BT709 here because it's been translated into 652 // We don't need to check BT709 here because it's been translated into
425 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below. 653 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below.
426 case ColorSpace::TransferID::GAMMA22: 654 case ColorSpace::TransferID::GAMMA22:
(...skipping 15 matching lines...) Expand all
442 } 670 }
443 671
444 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } 672 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; }
445 673
446 // Assumes BT2020 primaries. 674 // Assumes BT2020 primaries.
447 static float Luma(const ColorTransform::TriStim& c) { 675 static float Luma(const ColorTransform::TriStim& c) {
448 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; 676 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f;
449 } 677 }
450 678
451 void transform(ColorTransform::TriStim* colors, size_t num) override { 679 void transform(ColorTransform::TriStim* colors, size_t num) override {
452 if (fn_valid_) { 680 if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) {
453 for (size_t i = 0; i < num; i++) {
454 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x()));
455 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y()));
456 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z()));
457 }
458 } else if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) {
459 for (size_t i = 0; i < num; i++) { 681 for (size_t i = 0; i < num; i++) {
460 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), 682 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()),
461 ToLinear(transfer_, colors[i].y()), 683 ToLinear(transfer_, colors[i].y()),
462 ToLinear(transfer_, colors[i].z())); 684 ToLinear(transfer_, colors[i].z()));
463 if (Luma(ret) > 0.0) { 685 if (Luma(ret) > 0.0) {
464 ColorTransform::TriStim smpte2084( 686 ColorTransform::TriStim smpte2084(
465 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), 687 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()),
466 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), 688 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()),
467 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); 689 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z()));
468 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); 690 smpte2084.Scale(Luma(ret) / Luma(smpte2084));
469 ret = smpte2084; 691 ret = smpte2084;
470 } 692 }
471 colors[i] = ret; 693 colors[i] = ret;
472 } 694 }
473 } else { 695 } else {
474 for (size_t i = 0; i < num; i++) { 696 for (size_t i = 0; i < num; i++) {
475 colors[i].set_x(ToLinear(transfer_, colors[i].x())); 697 colors[i].set_x(ToLinear(transfer_, colors[i].x()));
476 colors[i].set_y(ToLinear(transfer_, colors[i].y())); 698 colors[i].set_y(ToLinear(transfer_, colors[i].y()));
477 colors[i].set_z(ToLinear(transfer_, colors[i].z())); 699 colors[i].set_z(ToLinear(transfer_, colors[i].z()));
478 } 700 }
479 } 701 }
480 } 702 }
481 703
482 private: 704 private:
483 ColorSpace::TransferID transfer_; 705 ColorSpace::TransferID transfer_;
484 SkColorSpaceTransferFn fn_;
485 bool fn_valid_ = false;
486 }; 706 };
487 707
488 // BT2020 Constant Luminance is different than most other 708 // BT2020 Constant Luminance is different than most other
489 // ways to encode RGB values as YUV. The basic idea is that 709 // ways to encode RGB values as YUV. The basic idea is that
490 // transfer functions are applied on the Y value instead of 710 // transfer functions are applied on the Y value instead of
491 // on the RGB values. However, running the transfer function 711 // on the RGB values. However, running the transfer function
492 // on the U and V values doesn't make any sense since they 712 // on the U and V values doesn't make any sense since they
493 // are centered at 0.5. To work around this, the transfer function 713 // are centered at 0.5. To work around this, the transfer function
494 // is applied to the Y, R and B values, and then the U and V 714 // is applied to the Y, R and B values, and then the U and V
495 // values are calculated from that. 715 // values are calculated from that.
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 void disable_optimizations() { disable_optimizations_ = true; } 851 void disable_optimizations() { disable_optimizations_ = true; }
632 852
633 private: 853 private:
634 bool disable_optimizations_ = false; 854 bool disable_optimizations_ = false;
635 std::vector<std::unique_ptr<ColorTransformInternal>> transforms_; 855 std::vector<std::unique_ptr<ColorTransformInternal>> transforms_;
636 }; 856 };
637 857
638 class ColorSpaceToColorSpaceTransform { 858 class ColorSpaceToColorSpaceTransform {
639 public: 859 public:
640 static Transform GetPrimaryTransform(const ColorSpace& c) { 860 static Transform GetPrimaryTransform(const ColorSpace& c) {
641 SkMatrix44 sk_matrix; 861 if (c.primaries_ == ColorSpace::PrimaryID::CUSTOM) {
642 c.GetPrimaryMatrix(&sk_matrix); 862 return Transform(c.custom_primary_matrix_[0], c.custom_primary_matrix_[1],
643 return Transform(sk_matrix); 863 c.custom_primary_matrix_[2], c.custom_primary_matrix_[3],
864 c.custom_primary_matrix_[4], c.custom_primary_matrix_[5],
865 c.custom_primary_matrix_[6], c.custom_primary_matrix_[7],
866 c.custom_primary_matrix_[8], c.custom_primary_matrix_[9],
867 c.custom_primary_matrix_[10],
868 c.custom_primary_matrix_[11], 0.0f, 0.0f, 0.0f, 1.0f);
869 } else {
870 return GetPrimaryMatrix(c.primaries_);
871 }
644 } 872 }
645 873
646 static void ColorSpaceToColorSpace(ColorSpace from, 874 static void ColorSpaceToColorSpace(ColorSpace from,
647 ColorSpace to, 875 ColorSpace to,
648 ColorTransform::Intent intent, 876 ColorTransform::Intent intent,
649 TransformBuilder* builder) { 877 TransformBuilder* builder) {
650 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { 878 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) {
651 switch (from.transfer_) { 879 switch (from.transfer_) {
652 case ColorSpace::TransferID::UNSPECIFIED: 880 case ColorSpace::TransferID::UNSPECIFIED:
653 case ColorSpace::TransferID::BT709: 881 case ColorSpace::TransferID::BT709:
(...skipping 22 matching lines...) Expand all
676 from.transfer_ = ColorSpace::TransferID::GAMMA24; 904 from.transfer_ = ColorSpace::TransferID::GAMMA24;
677 } 905 }
678 break; 906 break;
679 907
680 default: // Do nothing 908 default: // Do nothing
681 break; 909 break;
682 } 910 }
683 911
684 // TODO(hubbe): shrink gamuts here (never stretch gamuts) 912 // TODO(hubbe): shrink gamuts here (never stretch gamuts)
685 } 913 }
686
687 builder->Append(base::MakeUnique<ColorTransformMatrix>( 914 builder->Append(base::MakeUnique<ColorTransformMatrix>(
688 GetRangeAdjustMatrix(from.range_, from.matrix_))); 915 GetRangeAdjustMatrix(from.range_, from.matrix_)));
689
690 builder->Append(base::MakeUnique<ColorTransformMatrix>( 916 builder->Append(base::MakeUnique<ColorTransformMatrix>(
691 Invert(GetTransferMatrix(from.matrix_)))); 917 Invert(GetTransferMatrix(from.matrix_))));
692 918 builder->Append(base::MakeUnique<ColorTransformToLinear>(from.transfer_));
693 SkColorSpaceTransferFn to_linear_fn;
694 bool to_linear_fn_valid = from.GetTransferFunction(&to_linear_fn);
695 builder->Append(base::MakeUnique<ColorTransformToLinear>(
696 from.transfer_, to_linear_fn, to_linear_fn_valid));
697
698 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { 919 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
699 // BT2020 CL is a special case. 920 // BT2020 CL is a special case.
700 builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>()); 921 builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>());
701 } 922 }
702 builder->Append( 923 builder->Append(
703 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); 924 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from)));
704 925
705 builder->Append(base::MakeUnique<ColorTransformMatrix>( 926 builder->Append(base::MakeUnique<ColorTransformMatrix>(
706 Invert(GetPrimaryTransform(to)))); 927 Invert(GetPrimaryTransform(to))));
707 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { 928 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
708 // BT2020 CL is a special case. 929 // BT2020 CL is a special case.
709 builder->Append(base::MakeUnique<ColorTransformToBT2020CL>()); 930 builder->Append(base::MakeUnique<ColorTransformToBT2020CL>());
710 } 931 }
711 932
712 SkColorSpaceTransferFn from_linear_fn; 933 builder->Append(base::MakeUnique<ColorTransformFromLinear>(to.transfer_));
713 bool from_linear_fn_valid = to.GetInverseTransferFunction(&from_linear_fn);
714 builder->Append(base::MakeUnique<ColorTransformFromLinear>(
715 to.transfer_, from_linear_fn, from_linear_fn_valid));
716
717 builder->Append( 934 builder->Append(
718 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_))); 935 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_)));
719
720 builder->Append(base::MakeUnique<ColorTransformMatrix>( 936 builder->Append(base::MakeUnique<ColorTransformMatrix>(
721 Invert(GetRangeAdjustMatrix(to.range_, to.matrix_)))); 937 Invert(GetRangeAdjustMatrix(to.range_, to.matrix_))));
722 } 938 }
723 }; 939 };
724 940
725 class QCMSColorTransform : public ColorTransformInternal { 941 class QCMSColorTransform : public ColorTransformInternal {
726 public: 942 public:
727 // Takes ownership of the profiles 943 // Takes ownership of the profiles
728 QCMSColorTransform(qcms_profile* from, qcms_profile* to) 944 QCMSColorTransform(qcms_profile* from, qcms_profile* to)
729 : from_(from), to_(to) {} 945 : from_(from), to_(to) {}
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 from_profile ? ColorSpace::CreateXYZD50() : from, 1021 from_profile ? ColorSpace::CreateXYZD50() : from,
806 to_profile ? ColorSpace::CreateXYZD50() : to, intent, &builder); 1022 to_profile ? ColorSpace::CreateXYZD50() : to, intent, &builder);
807 if (to_profile) { 1023 if (to_profile) {
808 builder.Append(std::unique_ptr<ColorTransformInternal>( 1024 builder.Append(std::unique_ptr<ColorTransformInternal>(
809 new QCMSColorTransform(GetXYZD50Profile(), to_profile))); 1025 new QCMSColorTransform(GetXYZD50Profile(), to_profile)));
810 } 1026 }
811 1027
812 return builder.GetTransform(); 1028 return builder.GetTransform();
813 } 1029 }
814 1030
815 // static
816 float ColorTransform::ToLinearForTesting(ColorSpace::TransferID transfer,
817 float v) {
818 ColorSpace space(ColorSpace::PrimaryID::BT709, transfer,
819 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
820 SkColorSpaceTransferFn to_linear_fn;
821 bool to_linear_fn_valid = space.GetTransferFunction(&to_linear_fn);
822 ColorTransformToLinear to_linear_transform(transfer, to_linear_fn,
823 to_linear_fn_valid);
824 TriStim color(v, v, v);
825 to_linear_transform.transform(&color, 1);
826 return color.x();
827 }
828
829 // static
830 float ColorTransform::FromLinearForTesting(ColorSpace::TransferID transfer,
831 float v) {
832 ColorSpace space(ColorSpace::PrimaryID::BT709, transfer,
833 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
834 SkColorSpaceTransferFn from_linear_fn;
835 bool from_linear_fn_valid = space.GetInverseTransferFunction(&from_linear_fn);
836
837 ColorTransformFromLinear from_linear_transform(transfer, from_linear_fn,
838 from_linear_fn_valid);
839 TriStim color(v, v, v);
840 from_linear_transform.transform(&color, 1);
841 return color.x();
842 }
843
844 } // namespace gfx 1031 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/color_transform.h ('k') | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698