| Index: ui/gfx/color_transform.cc
|
| diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
|
| index f513d4de6d1763f2277b10ebda9f1d8177616d3b..7e5f05a7178a61582a7cb96fd2ad96109ce16442 100644
|
| --- a/ui/gfx/color_transform.cc
|
| +++ b/ui/gfx/color_transform.cc
|
| @@ -8,7 +8,15 @@
|
|
|
| #include "base/logging.h"
|
| #include "ui/gfx/color_space.h"
|
| +#include "ui/gfx/icc_profile.h"
|
| #include "ui/gfx/transform.h"
|
| +#include "third_party/qcms/src/qcms.h"
|
| +
|
| +#ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H
|
| +extern "C" {
|
| +#include "third_party/qcms/src/chain.h"
|
| +};
|
| +#endif
|
|
|
| namespace gfx {
|
|
|
| @@ -178,7 +186,7 @@ GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) {
|
| dest_response.y() / source_response.y(),
|
| dest_response.z() / source_response.z());
|
|
|
| - return bradford * adapter * Invert(bradford) * ret;
|
| + return Invert(bradford) * adapter * bradford * ret;
|
| }
|
|
|
| GFX_EXPORT float FromLinear(ColorSpace::TransferID id, float v) {
|
| @@ -547,14 +555,104 @@ class ColorSpaceToColorSpaceTransform : public ColorTransform {
|
| Transform c_;
|
| };
|
|
|
| +class QCMSColorTransform : public ColorTransform {
|
| + public:
|
| + // Takes ownership of the profiles
|
| + QCMSColorTransform(qcms_profile* from, qcms_profile* to)
|
| + : from_(from), to_(to) {}
|
| + ~QCMSColorTransform() {
|
| + qcms_profile_release(from_);
|
| + qcms_profile_release(to_);
|
| + }
|
| + void transform(TriStim* colors, size_t num) override {
|
| + CHECK(sizeof(TriStim) == sizeof(float[3]));
|
| + // QCMS doesn't like numbers outside 0..1
|
| + for (size_t i = 0; i < num; i++) {
|
| + colors[i].set_x(fmin(1.0f, fmax(0.0f, colors[i].x())));
|
| + colors[i].set_y(fmin(1.0f, fmax(0.0f, colors[i].y())));
|
| + colors[i].set_z(fmin(1.0f, fmax(0.0f, colors[i].z())));
|
| + }
|
| + qcms_chain_transform(from_, to_, reinterpret_cast<float*>(colors),
|
| + reinterpret_cast<float*>(colors), num * 3);
|
| + }
|
| +
|
| + private:
|
| + qcms_profile *from_, *to_;
|
| +};
|
| +
|
| +class ChainColorTransform : public ColorTransform {
|
| + public:
|
| + ChainColorTransform(std::unique_ptr<ColorTransform> a,
|
| + std::unique_ptr<ColorTransform> b)
|
| + : a_(std::move(a)), b_(std::move(b)) {}
|
| +
|
| + private:
|
| + void transform(TriStim* colors, size_t num) override {
|
| + a_->transform(colors, num);
|
| + b_->transform(colors, num);
|
| + }
|
| + std::unique_ptr<ColorTransform> a_;
|
| + std::unique_ptr<ColorTransform> b_;
|
| +};
|
| +
|
| +qcms_profile* GetQCMSProfileIfAvailable(const ColorSpace& color_space) {
|
| + ICCProfile icc_profile = ICCProfile::FromColorSpace(color_space);
|
| + if (icc_profile.GetData().empty())
|
| + return nullptr;
|
| + return qcms_profile_from_memory(icc_profile.GetData().data(),
|
| + icc_profile.GetData().size());
|
| +}
|
| +
|
| +qcms_profile* GetXYZD50Profile() {
|
| + // QCMS is trixy, it has a datatype called qcms_CIE_xyY, but what it expects
|
| + // is in fact not xyY color coordinates, it just wants the x/y values of the
|
| + // primaries with Y equal to 1.0.
|
| + qcms_CIE_xyYTRIPLE xyz;
|
| + qcms_CIE_xyY w;
|
| + xyz.red.x = 1.0f;
|
| + xyz.red.y = 0.0f;
|
| + xyz.red.Y = 1.0f;
|
| + xyz.green.x = 0.0f;
|
| + xyz.green.y = 1.0f;
|
| + xyz.green.Y = 1.0f;
|
| + xyz.blue.x = 0.0f;
|
| + xyz.blue.y = 0.0f;
|
| + xyz.blue.Y = 1.0f;
|
| + w.x = 0.34567f;
|
| + w.y = 0.35850f;
|
| + w.Y = 1.0f;
|
| + return qcms_profile_create_rgb_with_gamma(w, xyz, 1.0f);
|
| +}
|
| +
|
| std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform(
|
| const ColorSpace& from,
|
| const ColorSpace& to,
|
| Intent intent) {
|
| - // TODO(Hubbe): Check if from and/or to can be mapped to ICC profiles and
|
| - // provide better transforms in those cases.
|
| - return std::unique_ptr<ColorTransform>(
|
| - new ColorSpaceToColorSpaceTransform(from, to, intent));
|
| + qcms_profile* from_profile = GetQCMSProfileIfAvailable(from);
|
| + qcms_profile* to_profile = GetQCMSProfileIfAvailable(to);
|
| + if (from_profile) {
|
| + if (to_profile) {
|
| + return std::unique_ptr<ColorTransform>(
|
| + new QCMSColorTransform(from_profile, to_profile));
|
| + } else {
|
| + return std::unique_ptr<ColorTransform>(new ChainColorTransform(
|
| + std::unique_ptr<ColorTransform>(
|
| + new QCMSColorTransform(from_profile, GetXYZD50Profile())),
|
| + std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform(
|
| + ColorSpace::CreateXYZD50(), to, intent))));
|
| + }
|
| + } else {
|
| + if (to_profile) {
|
| + return std::unique_ptr<ColorTransform>(new ChainColorTransform(
|
| + std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform(
|
| + from, ColorSpace::CreateXYZD50(), intent)),
|
| + std::unique_ptr<ColorTransform>(
|
| + new QCMSColorTransform(GetXYZD50Profile(), to_profile))));
|
| + } else {
|
| + return std::unique_ptr<ColorTransform>(
|
| + new ColorSpaceToColorSpaceTransform(from, to, intent));
|
| + }
|
| + }
|
| }
|
|
|
| } // namespace gfx
|
|
|