Chromium Code Reviews| 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 |