OLD | NEW |
---|---|
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 <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <list> | 9 #include <list> |
10 #include <memory> | 10 #include <memory> |
(...skipping 17 matching lines...) Expand all Loading... | |
28 using std::log; | 28 using std::log; |
29 using std::max; | 29 using std::max; |
30 using std::min; | 30 using std::min; |
31 using std::pow; | 31 using std::pow; |
32 using std::sqrt; | 32 using std::sqrt; |
33 | 33 |
34 namespace gfx { | 34 namespace gfx { |
35 | 35 |
36 namespace { | 36 namespace { |
37 | 37 |
38 std::string Str(float f) { | |
39 return base::StringPrintf("%f", f); | |
40 } | |
41 | |
38 // Helper for scoped QCMS profiles. | 42 // Helper for scoped QCMS profiles. |
39 struct QcmsProfileDeleter { | 43 struct QcmsProfileDeleter { |
40 void operator()(qcms_profile* p) { | 44 void operator()(qcms_profile* p) { |
41 if (p) { | 45 if (p) { |
42 qcms_profile_release(p); | 46 qcms_profile_release(p); |
43 } | 47 } |
44 } | 48 } |
45 }; | 49 }; |
46 using ScopedQcmsProfile = std::unique_ptr<qcms_profile, QcmsProfileDeleter>; | 50 using ScopedQcmsProfile = std::unique_ptr<qcms_profile, QcmsProfileDeleter>; |
47 | 51 |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 | 224 |
221 Transform GetPrimaryTransform(const gfx::ColorSpace& color_space) { | 225 Transform GetPrimaryTransform(const gfx::ColorSpace& color_space) { |
222 SkMatrix44 primary_matrix; | 226 SkMatrix44 primary_matrix; |
223 color_space.GetPrimaryMatrix(&primary_matrix); | 227 color_space.GetPrimaryMatrix(&primary_matrix); |
224 return Transform(primary_matrix); | 228 return Transform(primary_matrix); |
225 } | 229 } |
226 | 230 |
227 } // namespace | 231 } // namespace |
228 | 232 |
229 class ColorTransformMatrix; | 233 class ColorTransformMatrix; |
234 class ColorTransformSkTransferFn; | |
230 class ColorTransformFromLinear; | 235 class ColorTransformFromLinear; |
231 class ColorTransformToBT2020CL; | 236 class ColorTransformToBT2020CL; |
232 class ColorTransformFromBT2020CL; | 237 class ColorTransformFromBT2020CL; |
233 class ColorTransformNull; | 238 class ColorTransformNull; |
234 class QCMSColorTransform; | 239 class QCMSColorTransform; |
235 | 240 |
236 class ColorTransformStep { | 241 class ColorTransformStep { |
237 public: | 242 public: |
238 ColorTransformStep() {} | 243 ColorTransformStep() {} |
239 virtual ~ColorTransformStep() {} | 244 virtual ~ColorTransformStep() {} |
240 virtual ColorTransformFromLinear* GetFromLinear() { return nullptr; } | 245 virtual ColorTransformFromLinear* GetFromLinear() { return nullptr; } |
241 virtual ColorTransformToBT2020CL* GetToBT2020CL() { return nullptr; } | 246 virtual ColorTransformToBT2020CL* GetToBT2020CL() { return nullptr; } |
242 virtual ColorTransformFromBT2020CL* GetFromBT2020CL() { return nullptr; } | 247 virtual ColorTransformFromBT2020CL* GetFromBT2020CL() { return nullptr; } |
248 virtual ColorTransformSkTransferFn* GetSkTransferFn() { return nullptr; } | |
243 virtual ColorTransformMatrix* GetMatrix() { return nullptr; } | 249 virtual ColorTransformMatrix* GetMatrix() { return nullptr; } |
244 virtual ColorTransformNull* GetNull() { return nullptr; } | 250 virtual ColorTransformNull* GetNull() { return nullptr; } |
245 virtual QCMSColorTransform* GetQCMS() { return nullptr; } | 251 virtual QCMSColorTransform* GetQCMS() { return nullptr; } |
246 | 252 |
247 // Join methods, returns true if the |next| transform was successfully | 253 // Join methods, returns true if the |next| transform was successfully |
248 // assimilated into |this|. | 254 // assimilated into |this|. |
249 // If Join() returns true, |next| is no longer needed and can be deleted. | 255 // If Join() returns true, |next| is no longer needed and can be deleted. |
250 virtual bool Join(ColorTransformStep* next) { return false; } | 256 virtual bool Join(ColorTransformStep* next) { return false; } |
251 | 257 |
252 // Return true if this is a null transform. | 258 // Return true if this is a null transform. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
341 m.get(0, 0), m.get(1, 0), m.get(2, 0), // column 1 | 347 m.get(0, 0), m.get(1, 0), m.get(2, 0), // column 1 |
342 m.get(0, 1), m.get(1, 1), m.get(2, 1), // column 2 | 348 m.get(0, 1), m.get(1, 1), m.get(2, 1), // column 2 |
343 m.get(0, 2), m.get(1, 2), m.get(2, 2)); // column 3 | 349 m.get(0, 2), m.get(1, 2), m.get(2, 2)); // column 3 |
344 SRC("color += vec3(%f, %f, %f);", m.get(0, 3), m.get(1, 3), m.get(2, 3)); | 350 SRC("color += vec3(%f, %f, %f);", m.get(0, 3), m.get(1, 3), m.get(2, 3)); |
345 } | 351 } |
346 | 352 |
347 private: | 353 private: |
348 class Transform matrix_; | 354 class Transform matrix_; |
349 }; | 355 }; |
350 | 356 |
357 class ColorTransformSkTransferFn : public ColorTransformStep { | |
358 public: | |
359 explicit ColorTransformSkTransferFn(const SkColorSpaceTransferFn& fn) | |
360 : fn_(fn) {} | |
361 ColorTransformSkTransferFn* GetSkTransferFn() override { return this; } | |
362 | |
363 bool Join(ColorTransformStep* next_untyped) override { | |
364 ColorTransformSkTransferFn* next = next_untyped->GetSkTransferFn(); | |
365 if (!next) | |
366 return false; | |
367 if (SkTransferFnsApproximatelyCancel(fn_, next->fn_)) { | |
368 // Set to be the identity. | |
369 fn_.fA = 1; | |
370 fn_.fB = 0; | |
371 fn_.fC = 1; | |
372 fn_.fD = 0; | |
373 fn_.fE = 0; | |
374 fn_.fF = 0; | |
375 fn_.fG = 1; | |
376 return true; | |
377 } | |
378 return false; | |
379 } | |
380 | |
381 bool IsNull() override { return SkTransferFnIsApproximatelyIdentity(fn_); } | |
382 | |
383 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | |
384 for (size_t i = 0; i < num; i++) { | |
385 colors[i].set_x(SkTransferFnEval(fn_, colors[i].x())); | |
386 colors[i].set_y(SkTransferFnEval(fn_, colors[i].y())); | |
387 colors[i].set_z(SkTransferFnEval(fn_, colors[i].z())); | |
388 } | |
389 } | |
390 | |
391 bool CanAppendShaderSource() override { return true; } | |
392 | |
393 void AppendShaderSourceChannel(std::string* result, const char* value) { | |
hubbe
2017/02/16 23:06:38
Please add some tests for this.
It would also help
ccameron
2017/02/16 23:51:58
Mmh, good point -- this was hit a little bit by th
hubbe
2017/02/17 00:06:00
Could I get one of two tests on the form:
string
ccameron
2017/02/19 22:28:07
I don't feel that that sort of test is particularl
hubbe
2017/02/20 05:01:02
That is exactly the point. I don't want a lot of t
ccameron
2017/02/21 22:32:42
Ah, that's a good idea.
I've added one test which
| |
394 const float kEpsilon = 1.f / 1024.f; | |
395 | |
396 // Construct the linear segment | |
397 // linear = C * x + F | |
398 // Elide operations that will be close to the identity. | |
399 std::string linear = value; | |
400 if (std::abs(fn_.fC - 1.f) > kEpsilon) | |
401 linear = Str(fn_.fC) + " * " + linear; | |
402 if (std::abs(fn_.fF) > kEpsilon) | |
403 linear = linear + "+ " + Str(fn_.fF); | |
404 | |
405 // Construct the nonlinear segment. | |
406 // nonlinear = pow(A * x + B, G) + E | |
407 // Elide operations (especially the pow) that will be close to the | |
408 // identity. | |
409 std::string nonlinear = value; | |
410 if (std::abs(fn_.fA - 1.f) > kEpsilon) | |
411 nonlinear = Str(fn_.fA) + " * " + nonlinear; | |
412 if (std::abs(fn_.fB) > kEpsilon) | |
413 nonlinear = nonlinear + " + " + Str(fn_.fB); | |
414 if (std::abs(fn_.fG - 1.f) > kEpsilon) | |
415 nonlinear = "pow(" + nonlinear + ", " + Str(fn_.fG) + ")"; | |
416 if (std::abs(fn_.fE) > kEpsilon) | |
417 nonlinear = nonlinear + " + " + Str(fn_.fE); | |
418 | |
419 // Add both parts, as needed. | |
420 SRC("// Apply transfer function."); | |
421 if (fn_.fD > kEpsilon) { | |
422 SRC("if (%s < %f)", value, fn_.fD); | |
423 SRC(" %s = %s;", value, linear.c_str()); | |
424 SRC("else"); | |
425 SRC(" %s = %s;", value, nonlinear.c_str()); | |
426 } else { | |
427 SRC("%s = %s;", value, nonlinear.c_str()); | |
428 } | |
429 } | |
430 | |
431 void AppendShaderSource(std::string* result) override { | |
432 // Append the transfer function for each channel. | |
433 AppendShaderSourceChannel(result, "color.r"); | |
hubbe
2017/02/16 23:06:38
Is the compiler smart enough to vectorize these?
I
ccameron
2017/02/16 23:51:58
I can't speak to anything but NVIDIA GPUs, but I'm
hubbe
2017/02/17 00:06:00
That's very interesting. It's my impression that s
| |
434 AppendShaderSourceChannel(result, "color.g"); | |
435 AppendShaderSourceChannel(result, "color.b"); | |
436 } | |
437 | |
438 private: | |
439 SkColorSpaceTransferFn fn_; | |
440 }; | |
441 | |
351 class ColorTransformFromLinear : public ColorTransformStep { | 442 class ColorTransformFromLinear : public ColorTransformStep { |
352 public: | 443 public: |
353 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer, | 444 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) |
354 const SkColorSpaceTransferFn& fn, | 445 : transfer_(transfer) {} |
355 bool fn_valid) | |
356 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) { | |
357 if (transfer_ == ColorSpace::TransferID::LINEAR_HDR) | |
358 transfer_ = ColorSpace::TransferID::LINEAR; | |
359 } | |
360 ColorTransformFromLinear* GetFromLinear() override { return this; } | 446 ColorTransformFromLinear* GetFromLinear() override { return this; } |
361 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 447 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
362 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 448 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
363 if (fn_valid_) { | 449 for (size_t i = 0; i < num; i++) { |
364 for (size_t i = 0; i < num; i++) { | 450 colors[i].set_x(FromLinear(transfer_, colors[i].x())); |
365 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x())); | 451 colors[i].set_y(FromLinear(transfer_, colors[i].y())); |
366 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y())); | 452 colors[i].set_z(FromLinear(transfer_, colors[i].z())); |
367 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z())); | |
368 } | |
369 } else { | |
370 for (size_t i = 0; i < num; i++) { | |
371 colors[i].set_x(FromLinear(transfer_, colors[i].x())); | |
372 colors[i].set_y(FromLinear(transfer_, colors[i].y())); | |
373 colors[i].set_z(FromLinear(transfer_, colors[i].z())); | |
374 } | |
375 } | 453 } |
376 } | 454 } |
377 | 455 |
378 private: | 456 private: |
379 friend class ColorTransformToLinear; | 457 friend class ColorTransformToLinear; |
380 ColorSpace::TransferID transfer_; | 458 ColorSpace::TransferID transfer_; |
381 SkColorSpaceTransferFn fn_; | |
382 bool fn_valid_ = false; | |
383 }; | 459 }; |
384 | 460 |
385 class ColorTransformToLinear : public ColorTransformStep { | 461 class ColorTransformToLinear : public ColorTransformStep { |
386 public: | 462 public: |
387 explicit ColorTransformToLinear(ColorSpace::TransferID transfer, | 463 explicit ColorTransformToLinear(ColorSpace::TransferID transfer) |
388 const SkColorSpaceTransferFn& fn, | 464 : transfer_(transfer) {} |
389 bool fn_valid) | |
390 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) { | |
391 if (transfer_ == ColorSpace::TransferID::LINEAR_HDR) | |
392 transfer_ = ColorSpace::TransferID::LINEAR; | |
393 } | |
394 | |
395 static bool IsGamma22(ColorSpace::TransferID transfer) { | |
396 switch (transfer) { | |
397 // We don't need to check BT709 here because it's been translated into | |
398 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below. | |
399 case ColorSpace::TransferID::GAMMA22: | |
400 case ColorSpace::TransferID::IEC61966_2_1: // SRGB | |
401 return true; | |
402 | |
403 default: | |
404 return false; | |
405 } | |
406 } | |
407 | 465 |
408 bool Join(ColorTransformStep* next_untyped) override { | 466 bool Join(ColorTransformStep* next_untyped) override { |
409 ColorTransformFromLinear* next = next_untyped->GetFromLinear(); | 467 ColorTransformFromLinear* next = next_untyped->GetFromLinear(); |
410 if (!next) | 468 if (!next) |
411 return false; | 469 return false; |
412 // TODO(ccameron): Use SkTransferFnsApproximatelyCancel and | 470 if (transfer_ == next->transfer_) { |
413 // SkTransferFnIsApproximatelyIdentity to merge parametric transfer | |
414 // functions. | |
415 if (transfer_ == next->transfer_ || | |
416 (IsGamma22(transfer_) && IsGamma22(next->transfer_))) { | |
417 transfer_ = ColorSpace::TransferID::LINEAR; | 471 transfer_ = ColorSpace::TransferID::LINEAR; |
418 return true; | 472 return true; |
419 } | 473 } |
420 return false; | 474 return false; |
421 } | 475 } |
422 | 476 |
423 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 477 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
424 | 478 |
425 // Assumes BT2020 primaries. | 479 // Assumes BT2020 primaries. |
426 static float Luma(const ColorTransform::TriStim& c) { | 480 static float Luma(const ColorTransform::TriStim& c) { |
427 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; | 481 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; |
428 } | 482 } |
429 | 483 |
430 static ColorTransform::TriStim ClipToWhite(ColorTransform::TriStim& c) { | 484 static ColorTransform::TriStim ClipToWhite(ColorTransform::TriStim& c) { |
431 float maximum = max(max(c.x(), c.y()), c.z()); | 485 float maximum = max(max(c.x(), c.y()), c.z()); |
432 if (maximum > 1.0f) { | 486 if (maximum > 1.0f) { |
433 float l = Luma(c); | 487 float l = Luma(c); |
434 c.Scale(1.0f / maximum); | 488 c.Scale(1.0f / maximum); |
435 ColorTransform::TriStim white(1.0f, 1.0f, 1.0f); | 489 ColorTransform::TriStim white(1.0f, 1.0f, 1.0f); |
436 white.Scale((1.0f - 1.0f / maximum) * l / Luma(white)); | 490 white.Scale((1.0f - 1.0f / maximum) * l / Luma(white)); |
437 ColorTransform::TriStim black(0.0f, 0.0f, 0.0f); | 491 ColorTransform::TriStim black(0.0f, 0.0f, 0.0f); |
438 c += white - black; | 492 c += white - black; |
439 } | 493 } |
440 return c; | 494 return c; |
441 } | 495 } |
442 | 496 |
443 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 497 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
444 if (fn_valid_) { | 498 if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { |
445 for (size_t i = 0; i < num; i++) { | |
446 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x())); | |
447 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y())); | |
448 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z())); | |
449 } | |
450 } else if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { | |
451 for (size_t i = 0; i < num; i++) { | 499 for (size_t i = 0; i < num; i++) { |
452 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), | 500 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), |
453 ToLinear(transfer_, colors[i].y()), | 501 ToLinear(transfer_, colors[i].y()), |
454 ToLinear(transfer_, colors[i].z())); | 502 ToLinear(transfer_, colors[i].z())); |
455 if (Luma(ret) > 0.0) { | 503 if (Luma(ret) > 0.0) { |
456 ColorTransform::TriStim smpte2084( | 504 ColorTransform::TriStim smpte2084( |
457 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), | 505 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), |
458 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), | 506 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), |
459 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); | 507 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); |
460 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); | 508 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); |
461 ret = ClipToWhite(smpte2084); | 509 ret = ClipToWhite(smpte2084); |
462 } | 510 } |
463 colors[i] = ret; | 511 colors[i] = ret; |
464 } | 512 } |
465 } else { | 513 } else { |
466 for (size_t i = 0; i < num; i++) { | 514 for (size_t i = 0; i < num; i++) { |
467 colors[i].set_x(ToLinear(transfer_, colors[i].x())); | 515 colors[i].set_x(ToLinear(transfer_, colors[i].x())); |
468 colors[i].set_y(ToLinear(transfer_, colors[i].y())); | 516 colors[i].set_y(ToLinear(transfer_, colors[i].y())); |
469 colors[i].set_z(ToLinear(transfer_, colors[i].z())); | 517 colors[i].set_z(ToLinear(transfer_, colors[i].z())); |
470 } | 518 } |
471 } | 519 } |
472 } | 520 } |
473 | 521 |
474 private: | 522 private: |
475 ColorSpace::TransferID transfer_; | 523 ColorSpace::TransferID transfer_; |
476 SkColorSpaceTransferFn fn_; | |
477 bool fn_valid_ = false; | |
478 }; | 524 }; |
479 | 525 |
480 // BT2020 Constant Luminance is different than most other | 526 // BT2020 Constant Luminance is different than most other |
481 // ways to encode RGB values as YUV. The basic idea is that | 527 // ways to encode RGB values as YUV. The basic idea is that |
482 // transfer functions are applied on the Y value instead of | 528 // transfer functions are applied on the Y value instead of |
483 // on the RGB values. However, running the transfer function | 529 // on the RGB values. However, running the transfer function |
484 // on the U and V values doesn't make any sense since they | 530 // on the U and V values doesn't make any sense since they |
485 // are centered at 0.5. To work around this, the transfer function | 531 // are centered at 0.5. To work around this, the transfer function |
486 // is applied to the Y, R and B values, and then the U and V | 532 // is applied to the Y, R and B values, and then the U and V |
487 // values are calculated from that. | 533 // values are calculated from that. |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
614 | 660 |
615 steps_.push_back( | 661 steps_.push_back( |
616 base::MakeUnique<ColorTransformMatrix>(Invert(GetTransferMatrix(from)))); | 662 base::MakeUnique<ColorTransformMatrix>(Invert(GetTransferMatrix(from)))); |
617 | 663 |
618 // If the target color space is not defined, just apply the adjust and | 664 // If the target color space is not defined, just apply the adjust and |
619 // tranfer matrices. | 665 // tranfer matrices. |
620 if (!to.IsValid()) | 666 if (!to.IsValid()) |
621 return; | 667 return; |
622 | 668 |
623 SkColorSpaceTransferFn to_linear_fn; | 669 SkColorSpaceTransferFn to_linear_fn; |
624 bool to_linear_fn_valid = from.GetTransferFunction(&to_linear_fn); | 670 if (from.GetTransferFunction(&to_linear_fn)) { |
625 steps_.push_back(base::MakeUnique<ColorTransformToLinear>( | 671 steps_.push_back( |
626 from.transfer_, to_linear_fn, to_linear_fn_valid)); | 672 base::MakeUnique<ColorTransformSkTransferFn>(to_linear_fn)); |
673 } else { | |
674 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); | |
675 } | |
627 | 676 |
628 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 677 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
629 // BT2020 CL is a special case. | 678 // BT2020 CL is a special case. |
630 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); | 679 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); |
631 } | 680 } |
632 steps_.push_back( | 681 steps_.push_back( |
633 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); | 682 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); |
634 | 683 |
635 steps_.push_back( | 684 steps_.push_back( |
636 base::MakeUnique<ColorTransformMatrix>(Invert(GetPrimaryTransform(to)))); | 685 base::MakeUnique<ColorTransformMatrix>(Invert(GetPrimaryTransform(to)))); |
637 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 686 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
638 // BT2020 CL is a special case. | 687 // BT2020 CL is a special case. |
639 steps_.push_back(base::MakeUnique<ColorTransformToBT2020CL>()); | 688 steps_.push_back(base::MakeUnique<ColorTransformToBT2020CL>()); |
640 } | 689 } |
641 | 690 |
642 SkColorSpaceTransferFn from_linear_fn; | 691 SkColorSpaceTransferFn from_linear_fn; |
643 bool from_linear_fn_valid = to.GetInverseTransferFunction(&from_linear_fn); | 692 if (to.GetInverseTransferFunction(&from_linear_fn)) { |
644 steps_.push_back(base::MakeUnique<ColorTransformFromLinear>( | 693 steps_.push_back( |
645 to.transfer_, from_linear_fn, from_linear_fn_valid)); | 694 base::MakeUnique<ColorTransformSkTransferFn>(from_linear_fn)); |
695 } else { | |
696 steps_.push_back(base::MakeUnique<ColorTransformFromLinear>(to.transfer_)); | |
697 } | |
646 | 698 |
647 steps_.push_back( | 699 steps_.push_back( |
648 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to))); | 700 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to))); |
649 | 701 |
650 steps_.push_back( | 702 steps_.push_back( |
651 base::MakeUnique<ColorTransformMatrix>(Invert(GetRangeAdjustMatrix(to)))); | 703 base::MakeUnique<ColorTransformMatrix>(Invert(GetRangeAdjustMatrix(to)))); |
652 } | 704 } |
653 | 705 |
654 class QCMSColorTransform : public ColorTransformStep { | 706 class QCMSColorTransform : public ColorTransformStep { |
655 public: | 707 public: |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
810 const ColorSpace& to, | 862 const ColorSpace& to, |
811 Intent intent) { | 863 Intent intent) { |
812 return std::unique_ptr<ColorTransform>( | 864 return std::unique_ptr<ColorTransform>( |
813 new ColorTransformInternal(from, to, intent)); | 865 new ColorTransformInternal(from, to, intent)); |
814 } | 866 } |
815 | 867 |
816 ColorTransform::ColorTransform() {} | 868 ColorTransform::ColorTransform() {} |
817 ColorTransform::~ColorTransform() {} | 869 ColorTransform::~ColorTransform() {} |
818 | 870 |
819 } // namespace gfx | 871 } // namespace gfx |
OLD | NEW |