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

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

Issue 2697413002: color: Add analytic transfer functions in shaders (Closed)
Patch Set: Created 3 years, 10 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 | « no previous file | 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 <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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698