| Index: ui/gfx/color_transform.cc
|
| diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
|
| index 4d36fe29ca5b4bd32e6e3831c5479dec8c6e390c..3a63643c2a0fea8e6f8743984522a09a6e2e61d5 100644
|
| --- a/ui/gfx/color_transform.cc
|
| +++ b/ui/gfx/color_transform.cc
|
| @@ -21,14 +21,6 @@
|
|
|
| namespace gfx {
|
|
|
| -float EvalSkTransferFn(const SkColorSpaceTransferFn& fn, float x) {
|
| - if (x < 0)
|
| - return 0;
|
| - if (x < fn.fD)
|
| - return fn.fC * x + fn.fF;
|
| - return powf(fn.fA * x + fn.fB, fn.fG) + fn.fE;
|
| -}
|
| -
|
| Transform Invert(const Transform& t) {
|
| Transform ret = t;
|
| if (!t.GetInverse(&ret)) {
|
| @@ -37,11 +29,179 @@
|
| return ret;
|
| }
|
|
|
| -float FromLinear(ColorSpace::TransferID id, float v) {
|
| +GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) {
|
| + SkColorSpacePrimaries primaries = {0};
|
| + switch (id) {
|
| + case ColorSpace::PrimaryID::CUSTOM:
|
| + NOTREACHED();
|
| +
|
| + case ColorSpace::PrimaryID::RESERVED0:
|
| + case ColorSpace::PrimaryID::RESERVED:
|
| + case ColorSpace::PrimaryID::UNSPECIFIED:
|
| + case ColorSpace::PrimaryID::UNKNOWN:
|
| + case ColorSpace::PrimaryID::BT709:
|
| + // BT709 is our default case. Put it after the switch just
|
| + // in case we somehow get an id which is not listed in the switch.
|
| + // (We don't want to use "default", because we want the compiler
|
| + // to tell us if we forgot some enum values.)
|
| + primaries.fRX = 0.640f;
|
| + primaries.fRY = 0.330f;
|
| + primaries.fGX = 0.300f;
|
| + primaries.fGY = 0.600f;
|
| + primaries.fBX = 0.150f;
|
| + primaries.fBY = 0.060f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::BT470M:
|
| + primaries.fRX = 0.67f;
|
| + primaries.fRY = 0.33f;
|
| + primaries.fGX = 0.21f;
|
| + primaries.fGY = 0.71f;
|
| + primaries.fBX = 0.14f;
|
| + primaries.fBY = 0.08f;
|
| + primaries.fWX = 0.31f;
|
| + primaries.fWY = 0.316f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::BT470BG:
|
| + primaries.fRX = 0.64f;
|
| + primaries.fRY = 0.33f;
|
| + primaries.fGX = 0.29f;
|
| + primaries.fGY = 0.60f;
|
| + primaries.fBX = 0.15f;
|
| + primaries.fBY = 0.06f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTE170M:
|
| + case ColorSpace::PrimaryID::SMPTE240M:
|
| + primaries.fRX = 0.630f;
|
| + primaries.fRY = 0.340f;
|
| + primaries.fGX = 0.310f;
|
| + primaries.fGY = 0.595f;
|
| + primaries.fBX = 0.155f;
|
| + primaries.fBY = 0.070f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::FILM:
|
| + primaries.fRX = 0.681f;
|
| + primaries.fRY = 0.319f;
|
| + primaries.fGX = 0.243f;
|
| + primaries.fGY = 0.692f;
|
| + primaries.fBX = 0.145f;
|
| + primaries.fBY = 0.049f;
|
| + primaries.fWX = 0.310f;
|
| + primaries.fWY = 0.136f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::BT2020:
|
| + primaries.fRX = 0.708f;
|
| + primaries.fRY = 0.292f;
|
| + primaries.fGX = 0.170f;
|
| + primaries.fGY = 0.797f;
|
| + primaries.fBX = 0.131f;
|
| + primaries.fBY = 0.046f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTEST428_1:
|
| + primaries.fRX = 1.0f;
|
| + primaries.fRY = 0.0f;
|
| + primaries.fGX = 0.0f;
|
| + primaries.fGY = 1.0f;
|
| + primaries.fBX = 0.0f;
|
| + primaries.fBY = 0.0f;
|
| + primaries.fWX = 1.0f / 3.0f;
|
| + primaries.fWY = 1.0f / 3.0f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTEST431_2:
|
| + primaries.fRX = 0.680f;
|
| + primaries.fRY = 0.320f;
|
| + primaries.fGX = 0.265f;
|
| + primaries.fGY = 0.690f;
|
| + primaries.fBX = 0.150f;
|
| + primaries.fBY = 0.060f;
|
| + primaries.fWX = 0.314f;
|
| + primaries.fWY = 0.351f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTEST432_1:
|
| + primaries.fRX = 0.680f;
|
| + primaries.fRY = 0.320f;
|
| + primaries.fGX = 0.265f;
|
| + primaries.fGY = 0.690f;
|
| + primaries.fBX = 0.150f;
|
| + primaries.fBY = 0.060f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::XYZ_D50:
|
| + primaries.fRX = 1.0f;
|
| + primaries.fRY = 0.0f;
|
| + primaries.fGX = 0.0f;
|
| + primaries.fGY = 1.0f;
|
| + primaries.fBX = 0.0f;
|
| + primaries.fBY = 0.0f;
|
| + primaries.fWX = 0.34567f;
|
| + primaries.fWY = 0.35850f;
|
| + break;
|
| + }
|
| +
|
| + SkMatrix44 matrix;
|
| + primaries.toXYZD50(&matrix);
|
| + return Transform(matrix);
|
| +}
|
| +
|
| +GFX_EXPORT float FromLinear(ColorSpace::TransferID id, float v) {
|
| switch (id) {
|
| case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
|
| // Should already be handled.
|
| - break;
|
| + NOTREACHED();
|
| + case ColorSpace::TransferID::CUSTOM:
|
| + // TODO(hubbe): Actually implement custom transfer functions.
|
| + case ColorSpace::TransferID::RESERVED0:
|
| + case ColorSpace::TransferID::RESERVED:
|
| + case ColorSpace::TransferID::UNSPECIFIED:
|
| + case ColorSpace::TransferID::UNKNOWN:
|
| + // All unknown values default to BT709
|
| +
|
| + case ColorSpace::TransferID::BT709:
|
| + case ColorSpace::TransferID::SMPTE170M:
|
| + case ColorSpace::TransferID::BT2020_10:
|
| + case ColorSpace::TransferID::BT2020_12:
|
| + // BT709 is our "default" cause, so put the code after the switch
|
| + // to avoid "control reaches end of non-void function" errors.
|
| + break;
|
| +
|
| + case ColorSpace::TransferID::GAMMA22:
|
| + v = fmax(0.0f, v);
|
| + return powf(v, 1.0f / 2.2f);
|
| +
|
| + case ColorSpace::TransferID::GAMMA28:
|
| + v = fmax(0.0f, v);
|
| + return powf(v, 1.0f / 2.8f);
|
| +
|
| + case ColorSpace::TransferID::SMPTE240M: {
|
| + v = fmax(0.0f, v);
|
| + float a = 1.11157219592173128753f;
|
| + float b = 0.02282158552944503135f;
|
| + if (v <= b) {
|
| + return 4.0f * v;
|
| + } else {
|
| + return a * powf(v, 0.45f) - (a - 1.0f);
|
| + }
|
| + }
|
| +
|
| + case ColorSpace::TransferID::LINEAR:
|
| + return v;
|
|
|
| case ColorSpace::TransferID::LOG:
|
| if (v < 0.01f)
|
| @@ -78,6 +238,16 @@
|
| }
|
| }
|
|
|
| + case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
|
| + v = fmax(0.0f, v);
|
| + float a = 1.055f;
|
| + float b = 0.0031308f;
|
| + if (v < b) {
|
| + return 12.92f * v;
|
| + } else {
|
| + return a * powf(v, 1.0f / 2.4f) - (a - 1.0f);
|
| + }
|
| + }
|
| case ColorSpace::TransferID::SMPTEST2084: {
|
| // Go from scRGB levels to 0-1.
|
| v *= 80.0f / 10000.0f;
|
| @@ -90,6 +260,10 @@
|
| return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2);
|
| }
|
|
|
| + case ColorSpace::TransferID::SMPTEST428_1:
|
| + v = fmax(0.0f, v);
|
| + return powf(48.0f * v + 52.37f, 1.0f / 2.6f);
|
| +
|
| // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf
|
| case ColorSpace::TransferID::ARIB_STD_B67: {
|
| const float a = 0.17883277f;
|
| @@ -102,16 +276,62 @@
|
| return a * log(v - b) + c;
|
| }
|
|
|
| - default:
|
| - // Handled by SkColorSpaceTransferFn.
|
| - break;
|
| - }
|
| - NOTREACHED();
|
| - return 0;
|
| + // Chrome-specific values below
|
| + case ColorSpace::TransferID::GAMMA24:
|
| + v = fmax(0.0f, v);
|
| + return powf(v, 1.0f / 2.4f);
|
| + }
|
| +
|
| + v = fmax(0.0f, v);
|
| + float a = 1.099296826809442f;
|
| + float b = 0.018053968510807f;
|
| + if (v <= b) {
|
| + return 4.5f * v;
|
| + } else {
|
| + return a * powf(v, 0.45f) - (a - 1.0f);
|
| + }
|
| }
|
|
|
| -float ToLinear(ColorSpace::TransferID id, float v) {
|
| +GFX_EXPORT float ToLinear(ColorSpace::TransferID id, float v) {
|
| switch (id) {
|
| + case ColorSpace::TransferID::CUSTOM:
|
| + // TODO(hubbe): Actually implement custom transfer functions.
|
| + case ColorSpace::TransferID::RESERVED0:
|
| + case ColorSpace::TransferID::RESERVED:
|
| + case ColorSpace::TransferID::UNSPECIFIED:
|
| + case ColorSpace::TransferID::UNKNOWN:
|
| + // All unknown values default to BT709
|
| +
|
| + case ColorSpace::TransferID::BT709:
|
| + case ColorSpace::TransferID::SMPTE170M:
|
| + case ColorSpace::TransferID::BT2020_10:
|
| + case ColorSpace::TransferID::BT2020_12:
|
| + // BT709 is our "default" cause, so put the code after the switch
|
| + // to avoid "control reaches end of non-void function" errors.
|
| + break;
|
| +
|
| + case ColorSpace::TransferID::GAMMA22:
|
| + v = fmax(0.0f, v);
|
| + return powf(v, 2.2f);
|
| +
|
| + case ColorSpace::TransferID::GAMMA28:
|
| + v = fmax(0.0f, v);
|
| + return powf(v, 2.8f);
|
| +
|
| + case ColorSpace::TransferID::SMPTE240M: {
|
| + v = fmax(0.0f, v);
|
| + float a = 1.11157219592173128753f;
|
| + float b = 0.02282158552944503135f;
|
| + if (v <= FromLinear(ColorSpace::TransferID::SMPTE240M, b)) {
|
| + return v / 4.0f;
|
| + } else {
|
| + return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
|
| + }
|
| + }
|
| +
|
| + case ColorSpace::TransferID::LINEAR:
|
| + return v;
|
| +
|
| case ColorSpace::TransferID::LOG:
|
| if (v < 0.0f)
|
| return 0.0f;
|
| @@ -144,6 +364,17 @@
|
| return v / 4.5f;
|
| } else {
|
| return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
|
| + }
|
| + }
|
| +
|
| + case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
|
| + v = fmax(0.0f, v);
|
| + float a = 1.055f;
|
| + float b = 0.0031308f;
|
| + if (v < FromLinear(ColorSpace::TransferID::IEC61966_2_1, b)) {
|
| + return v / 12.92f;
|
| + } else {
|
| + return powf((v + a - 1.0f) / a, 2.4f);
|
| }
|
| }
|
|
|
| @@ -164,6 +395,14 @@
|
| return v;
|
| }
|
|
|
| + case ColorSpace::TransferID::SMPTEST428_1:
|
| + return (powf(v, 2.6f) - 52.37f) / 48.0f;
|
| +
|
| + // Chrome-specific values below
|
| + case ColorSpace::TransferID::GAMMA24:
|
| + v = fmax(0.0f, v);
|
| + return powf(v, 2.4f);
|
| +
|
| case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
|
| v = fmax(0.0f, v);
|
| return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f);
|
| @@ -182,13 +421,16 @@
|
| }
|
| return v_;
|
| }
|
| -
|
| - default:
|
| - // Handled by SkColorSpaceTransferFn.
|
| - break;
|
| - }
|
| - NOTREACHED();
|
| - return 0;
|
| + }
|
| +
|
| + v = fmax(0.0f, v);
|
| + float a = 1.099296826809442f;
|
| + float b = 0.018053968510807f;
|
| + if (v < FromLinear(ColorSpace::TransferID::BT709, b)) {
|
| + return v / 4.5f;
|
| + } else {
|
| + return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
|
| + }
|
| }
|
|
|
| GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) {
|
| @@ -375,10 +617,8 @@
|
|
|
| class ColorTransformFromLinear : public ColorTransformInternal {
|
| public:
|
| - explicit ColorTransformFromLinear(ColorSpace::TransferID transfer,
|
| - const SkColorSpaceTransferFn& fn,
|
| - bool fn_valid)
|
| - : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {}
|
| + explicit ColorTransformFromLinear(ColorSpace::TransferID transfer)
|
| + : transfer_(transfer) {}
|
| bool Prepend(ColorTransformInternal* prev) override {
|
| return prev->Join(*this);
|
| }
|
| @@ -386,34 +626,22 @@
|
| bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; }
|
|
|
| void transform(ColorTransform::TriStim* colors, size_t num) override {
|
| - if (fn_valid_) {
|
| - for (size_t i = 0; i < num; i++) {
|
| - colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x()));
|
| - colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y()));
|
| - colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z()));
|
| - }
|
| - } else {
|
| - for (size_t i = 0; i < num; i++) {
|
| - colors[i].set_x(FromLinear(transfer_, colors[i].x()));
|
| - colors[i].set_y(FromLinear(transfer_, colors[i].y()));
|
| - colors[i].set_z(FromLinear(transfer_, colors[i].z()));
|
| - }
|
| + for (size_t i = 0; i < num; i++) {
|
| + colors[i].set_x(FromLinear(transfer_, colors[i].x()));
|
| + colors[i].set_y(FromLinear(transfer_, colors[i].y()));
|
| + colors[i].set_z(FromLinear(transfer_, colors[i].z()));
|
| }
|
| }
|
|
|
| private:
|
| friend class ColorTransformToLinear;
|
| ColorSpace::TransferID transfer_;
|
| - SkColorSpaceTransferFn fn_;
|
| - bool fn_valid_ = false;
|
| };
|
|
|
| class ColorTransformToLinear : public ColorTransformInternal {
|
| public:
|
| - explicit ColorTransformToLinear(ColorSpace::TransferID transfer,
|
| - const SkColorSpaceTransferFn& fn,
|
| - bool fn_valid)
|
| - : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {}
|
| + explicit ColorTransformToLinear(ColorSpace::TransferID transfer)
|
| + : transfer_(transfer) {}
|
|
|
| bool Prepend(ColorTransformInternal* prev) override {
|
| return prev->Join(*this);
|
| @@ -449,13 +677,7 @@
|
| }
|
|
|
| void transform(ColorTransform::TriStim* colors, size_t num) override {
|
| - if (fn_valid_) {
|
| - for (size_t i = 0; i < num; i++) {
|
| - colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x()));
|
| - colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y()));
|
| - colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z()));
|
| - }
|
| - } else if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) {
|
| + if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) {
|
| for (size_t i = 0; i < num; i++) {
|
| ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()),
|
| ToLinear(transfer_, colors[i].y()),
|
| @@ -481,8 +703,6 @@
|
|
|
| private:
|
| ColorSpace::TransferID transfer_;
|
| - SkColorSpaceTransferFn fn_;
|
| - bool fn_valid_ = false;
|
| };
|
|
|
| // BT2020 Constant Luminance is different than most other
|
| @@ -638,9 +858,17 @@
|
| class ColorSpaceToColorSpaceTransform {
|
| public:
|
| static Transform GetPrimaryTransform(const ColorSpace& c) {
|
| - SkMatrix44 sk_matrix;
|
| - c.GetPrimaryMatrix(&sk_matrix);
|
| - return Transform(sk_matrix);
|
| + if (c.primaries_ == ColorSpace::PrimaryID::CUSTOM) {
|
| + return Transform(c.custom_primary_matrix_[0], c.custom_primary_matrix_[1],
|
| + c.custom_primary_matrix_[2], c.custom_primary_matrix_[3],
|
| + c.custom_primary_matrix_[4], c.custom_primary_matrix_[5],
|
| + c.custom_primary_matrix_[6], c.custom_primary_matrix_[7],
|
| + c.custom_primary_matrix_[8], c.custom_primary_matrix_[9],
|
| + c.custom_primary_matrix_[10],
|
| + c.custom_primary_matrix_[11], 0.0f, 0.0f, 0.0f, 1.0f);
|
| + } else {
|
| + return GetPrimaryMatrix(c.primaries_);
|
| + }
|
| }
|
|
|
| static void ColorSpaceToColorSpace(ColorSpace from,
|
| @@ -683,18 +911,11 @@
|
|
|
| // TODO(hubbe): shrink gamuts here (never stretch gamuts)
|
| }
|
| -
|
| builder->Append(base::MakeUnique<ColorTransformMatrix>(
|
| GetRangeAdjustMatrix(from.range_, from.matrix_)));
|
| -
|
| builder->Append(base::MakeUnique<ColorTransformMatrix>(
|
| Invert(GetTransferMatrix(from.matrix_))));
|
| -
|
| - SkColorSpaceTransferFn to_linear_fn;
|
| - bool to_linear_fn_valid = from.GetTransferFunction(&to_linear_fn);
|
| - builder->Append(base::MakeUnique<ColorTransformToLinear>(
|
| - from.transfer_, to_linear_fn, to_linear_fn_valid));
|
| -
|
| + builder->Append(base::MakeUnique<ColorTransformToLinear>(from.transfer_));
|
| if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
|
| // BT2020 CL is a special case.
|
| builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>());
|
| @@ -709,14 +930,9 @@
|
| builder->Append(base::MakeUnique<ColorTransformToBT2020CL>());
|
| }
|
|
|
| - SkColorSpaceTransferFn from_linear_fn;
|
| - bool from_linear_fn_valid = to.GetInverseTransferFunction(&from_linear_fn);
|
| - builder->Append(base::MakeUnique<ColorTransformFromLinear>(
|
| - to.transfer_, from_linear_fn, from_linear_fn_valid));
|
| -
|
| + builder->Append(base::MakeUnique<ColorTransformFromLinear>(to.transfer_));
|
| builder->Append(
|
| base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_)));
|
| -
|
| builder->Append(base::MakeUnique<ColorTransformMatrix>(
|
| Invert(GetRangeAdjustMatrix(to.range_, to.matrix_))));
|
| }
|
| @@ -812,33 +1028,4 @@
|
| return builder.GetTransform();
|
| }
|
|
|
| -// static
|
| -float ColorTransform::ToLinearForTesting(ColorSpace::TransferID transfer,
|
| - float v) {
|
| - ColorSpace space(ColorSpace::PrimaryID::BT709, transfer,
|
| - ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
|
| - SkColorSpaceTransferFn to_linear_fn;
|
| - bool to_linear_fn_valid = space.GetTransferFunction(&to_linear_fn);
|
| - ColorTransformToLinear to_linear_transform(transfer, to_linear_fn,
|
| - to_linear_fn_valid);
|
| - TriStim color(v, v, v);
|
| - to_linear_transform.transform(&color, 1);
|
| - return color.x();
|
| -}
|
| -
|
| -// static
|
| -float ColorTransform::FromLinearForTesting(ColorSpace::TransferID transfer,
|
| - float v) {
|
| - ColorSpace space(ColorSpace::PrimaryID::BT709, transfer,
|
| - ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
|
| - SkColorSpaceTransferFn from_linear_fn;
|
| - bool from_linear_fn_valid = space.GetInverseTransferFunction(&from_linear_fn);
|
| -
|
| - ColorTransformFromLinear from_linear_transform(transfer, from_linear_fn,
|
| - from_linear_fn_valid);
|
| - TriStim color(v, v, v);
|
| - from_linear_transform.transform(&color, 1);
|
| - return color.x();
|
| -}
|
| -
|
| } // namespace gfx
|
|
|