AGTM: Remove JSON prototype

Change GetSerializedAgtmItutT35 to only parse the ITU-T T.35 header, and
nothing else (not the version inside ST 2094-50, etc).

Update tests to reflect this.

Remove the JSON-based prototype AGTM implementation, and instead hook up
the skhdr::Agtm based implementation.

Bug: 395659818
Change-Id: I3a864f11f8d928fbe7e68dbbc4bfcca8086eaad2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7256035
Commit-Queue: ccameron chromium <ccameron@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1558413}
diff --git a/cc/paint/tone_map_util.cc b/cc/paint/tone_map_util.cc
index 0cbeeb45..7d30e9c 100644
--- a/cc/paint/tone_map_util.cc
+++ b/cc/paint/tone_map_util.cc
@@ -5,6 +5,7 @@
 #include "cc/paint/tone_map_util.h"
 
 #include <cmath>
+#include <memory>
 #include <string_view>
 #include <utility>
 
@@ -15,7 +16,8 @@
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/effects/SkColorMatrix.h"
 #include "third_party/skia/include/effects/SkRuntimeEffect.h"
-#include "ui/gfx/hdr_metadata_agtm.h"
+#include "third_party/skia/include/private/SkHdrMetadata.h"
+#include "ui/gfx/hdr_metadata.h"
 
 namespace cc {
 
@@ -81,107 +83,6 @@
       SkNamedTransferFn::kLinear, SkNamedGamut::kRec2020));
 }
 
-// AGTM tone mapping shader.
-static constexpr char kAgtmToneMapSKSL[] =
-    "uniform half altr_i_weight;\n"
-    "uniform half altr_j_weight;\n"
-    "uniform half4 altr_i_mix_rgbx;\n"
-    "uniform half4 altr_j_mix_rgbx;\n"
-    "uniform half4 altr_i_mix_Mmcx;\n"
-    "uniform half4 altr_j_mix_Mmcx;\n"
-    "uniform shader altr_i_curve;\n"
-    "uniform shader altr_j_curve;\n"
-    "uniform half gain_min;\n"
-    "uniform half gain_span;\n"
-    "uniform half gain_application_offset;\n"
-    "uniform half curve_scale;\n"
-    "\n"
-    "half3 EvalComponentMixing(half3 color, bool j) {\n"
-    "  half4 rgbx = j ? altr_j_mix_rgbx : altr_i_mix_rgbx;\n"
-    "  half4 Mmcx = j ? altr_j_mix_Mmcx : altr_i_mix_Mmcx;\n"
-    "  half M = max(max(color.r, color.g), color.b);\n"
-    "  half m = min(min(color.r, color.g), color.b);\n"
-    "  half common = dot(rgbx.rgb, color) +\n"
-    "                Mmcx[0] * M +\n"
-    "                Mmcx[1] * m;\n"
-    "  return Mmcx[2] * color + half3(common);\n"
-    "}\n"
-    "half EvalGain(half color, bool j) {\n"
-    "  half2 tc = half2(curve_scale * color + 0.5, 0.5);\n"
-    "  half y = j ? altr_j_curve.eval(tc).a : altr_i_curve.eval(tc).a;\n"
-    "  return gain_min + gain_span * y;\n"
-    "}\n"
-    "half4 main(half4 color) {\n"
-    "  half3 G = half3(0.0);\n"
-    "  if (altr_i_weight > 0.0) {\n"
-    "    half3 mixed = EvalComponentMixing(color.rgb, false);\n"
-    "    G += altr_i_weight * half3(EvalGain(mixed.r, false),\n"
-    "                               EvalGain(mixed.g, false),\n"
-    "                               EvalGain(mixed.b, false));\n"
-    "  }\n"
-    "  if (altr_j_weight > 0.0) {\n"
-    "    half3 mixed = EvalComponentMixing(color.rgb, true);\n"
-    "    G += altr_j_weight * half3(EvalGain(mixed.r, true),\n"
-    "                               EvalGain(mixed.g, true),\n"
-    "                               EvalGain(mixed.b, true));\n"
-    "  }\n"
-    "  color.rgb *= exp2(G);\n"
-    "  return color;\n"
-    "}\n";
-
-sk_sp<SkColorFilter> GetAgtmFilter(const gfx::HdrMetadataAgtmParsed& params,
-                                   float H_target) {
-  auto result = SkRuntimeEffect::MakeForColorFilter(
-      SkString(kAgtmToneMapSKSL, sizeof(kAgtmToneMapSKSL) - 1),
-      /*options=*/{});
-  CHECK(result.effect) << result.errorText.c_str();
-
-  SkRuntimeShaderBuilder builder(result.effect);
-  builder.uniform("gain_min") = params.gain_min;
-  builder.uniform("gain_span") = params.gain_span;
-  builder.uniform("gain_application_offset") = params.gain_application_offset;
-
-  // Set the alternate representation weightings and parameters.
-  size_t altr_i = gfx::HdrMetadataAgtmParsed::kBaselineIndex;
-  size_t altr_j = gfx::HdrMetadataAgtmParsed::kBaselineIndex;
-  float altr_i_weight = 0.f;
-  float altr_j_weight = 0.f;
-  params.ComputeAlternateWeights(H_target, altr_i, altr_i_weight, altr_j,
-                                 altr_j_weight);
-  builder.uniform("altr_i_weight") = altr_i_weight;
-  if (altr_i == gfx::HdrMetadataAgtmParsed::kBaselineIndex) {
-    DCHECK_EQ(altr_i_weight, 0.f);
-    DCHECK_EQ(altr_j, gfx::HdrMetadataAgtmParsed::kBaselineIndex);
-    builder.child("altr_i_curve") = nullptr;
-    builder.uniform("altr_i_mix_rgbx") = SkColor4f();
-    builder.uniform("altr_i_mix_Mmcx") = SkColor4f();
-  } else {
-    const auto& altr = params.alternates[altr_i];
-    builder.child("altr_i_curve") =
-        altr.curve->makeRawShader(SkSamplingOptions(SkFilterMode::kLinear));
-    builder.uniform("altr_i_mix_rgbx") = altr.mix_rgbx;
-    builder.uniform("altr_i_mix_Mmcx") = altr.mix_Mmcx;
-    builder.uniform("curve_scale") =
-        params.baseline_max_component / (altr.curve->width() - 1.f);
-  }
-  builder.uniform("altr_j_weight") = altr_j_weight;
-  if (altr_j == gfx::HdrMetadataAgtmParsed::kBaselineIndex) {
-    DCHECK_EQ(altr_j_weight, 0.f);
-    builder.child("altr_j_curve") = nullptr;
-    builder.uniform("altr_j_mix_rgbx") = SkColor4f();
-    builder.uniform("altr_j_mix_Mmcx") = SkColor4f();
-  } else {
-    const auto& altr = params.alternates[altr_j];
-    builder.child("altr_j_curve") =
-        altr.curve->makeRawShader(SkSamplingOptions(SkFilterMode::kLinear));
-    builder.uniform("altr_j_mix_rgbx") = altr.mix_rgbx;
-    builder.uniform("altr_j_mix_Mmcx") = altr.mix_Mmcx;
-  }
-  auto filter = builder.makeColorFilter();
-  CHECK(filter);
-  return filter->makeWithWorkingColorSpace(params.gain_application_color_space);
-}
-
 }  // namespace
 
 bool ToneMapUtil::UseGlobalToneMapFilter(const SkImage* image,
@@ -220,8 +121,11 @@
   skcms_TransferFunction trfn;
   image->colorSpace()->transferFn(&trfn);
 
-  gfx::HdrMetadataAgtmParsed agtm;
-  const bool agtm_parsed = agtm.Parse(metadata.getSerializedAgtm());
+  // Parse AGTM, only if the feature is enabled.
+  std::unique_ptr<skhdr::Agtm> agtm_parsed;
+  if (gfx::HdrMetadataAgtm::IsEnabled()) {
+    agtm_parsed = skhdr::Agtm::Make(metadata.getSerializedAgtm());
+  }
 
   // The remainder of the function will construct `filter` to perform all
   // transformations (scaling, OOTF, and tone mapping).
@@ -232,7 +136,7 @@
   auto compute_reference_white_luminance = [&]() {
     // AGTM metadata gets priority.
     if (agtm_parsed) {
-      return agtm.hdr_reference_white;
+      return agtm_parsed->getHdrReferenceWhite();
     }
     // Then NDWL.
     if (metadata.ndwl.has_value() && metadata.ndwl->nits > 0.f) {
@@ -257,7 +161,7 @@
 
   // Apply tone mapping.
   if (agtm_parsed) {
-    auto tone_map_filter = GetAgtmFilter(agtm, target_hdr_headroom);
+    auto tone_map_filter = agtm_parsed->makeColorFilter(target_hdr_headroom);
     filter = SkColorFilters::Compose(tone_map_filter, std::move(filter));
   } else {
     const float content_max_luminance =
diff --git a/media/base/agtm.cc b/media/base/agtm.cc
index 90a1d396..23a3eb0 100644
--- a/media/base/agtm.cc
+++ b/media/base/agtm.cc
@@ -12,19 +12,19 @@
 sk_sp<const SkData> GetSerializedAgtmItutT35(
     uint8_t t35_country_code,
     base::span<const uint8_t> t35_payload) {
-  // The minimum header size needed for valid Agtm metadata.
-  static constexpr size_t kItuT35HeaderSize = 6;
+  // The size of the ITU-T T.35 header.
+  static constexpr size_t kItuT35HeaderSize = 4;
+  // The minimum body size needed for valid Agtm metadata.
+  static constexpr size_t kAgtmMinSize = 2;
   static constexpr uint8_t kItuT35USCountryCode = 0xB5;
 
   // Defined in SMPTE ST 2094-50: Annex D and Annex C (C.2.1).
   const bool is_agtm = t35_country_code == kItuT35USCountryCode &&
-                       t35_payload.size() >= kItuT35HeaderSize &&
+                       t35_payload.size() >= kItuT35HeaderSize + kAgtmMinSize &&
                        // itu_t_t35_us_terminal_provider_code u(16)
                        t35_payload[0] == 0x00 && t35_payload[1] == 0x90 &&
                        // itu_t_t35_smpte_terminal_provider_oriented_code u(16)
-                       t35_payload[2] == 0x00 && t35_payload[3] == 0x01 &&
-                       // application_version u(8)
-                       t35_payload[4] == 0x01;
+                       t35_payload[2] == 0x00 && t35_payload[3] == 0x01;
   if (!is_agtm) {
     return nullptr;
   }
diff --git a/media/base/agtm_unittest.cc b/media/base/agtm_unittest.cc
index bef9a3c..f5d1f797 100644
--- a/media/base/agtm_unittest.cc
+++ b/media/base/agtm_unittest.cc
@@ -15,8 +15,8 @@
                                      0x00, 0x01, 0x02, 0x03};
   const auto agtm = GetSerializedAgtmItutT35(t35_country_code, data);
   ASSERT_TRUE(agtm);
-  EXPECT_EQ(agtm->size(), 3u);
-  const std::vector<uint8_t> expected = {0x01, 0x02, 0x03};
+  EXPECT_EQ(agtm->size(), 5u);
+  const std::vector<uint8_t> expected = {0x01, 0x00, 0x01, 0x02, 0x03};
   EXPECT_TRUE(SkData::Equals(
       agtm.get(),
       SkData::MakeWithCopy(expected.data(), expected.size()).get()));
diff --git a/media/filters/dav1d_video_decoder_unittest.cc b/media/filters/dav1d_video_decoder_unittest.cc
index 83fb350..4b6645a1 100644
--- a/media/filters/dav1d_video_decoder_unittest.cc
+++ b/media/filters/dav1d_video_decoder_unittest.cc
@@ -277,7 +277,7 @@
 
   const auto& frame = output_frames_.front();
   ASSERT_TRUE(frame->hdr_metadata().getSerializedAgtm());
-  EXPECT_EQ(frame->hdr_metadata().getSerializedAgtm()->size(), 99u);
+  EXPECT_EQ(frame->hdr_metadata().getSerializedAgtm()->size(), 101u);
 }
 
 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
diff --git a/media/filters/vpx_video_decoder_unittest.cc b/media/filters/vpx_video_decoder_unittest.cc
index b72b640..c7f6d13 100644
--- a/media/filters/vpx_video_decoder_unittest.cc
+++ b/media/filters/vpx_video_decoder_unittest.cc
@@ -391,7 +391,7 @@
 
   const auto& frame = output_frames_.front();
   ASSERT_TRUE(frame->hdr_metadata().getSerializedAgtm());
-  EXPECT_EQ(frame->hdr_metadata().getSerializedAgtm()->size(), 533u);
+  EXPECT_EQ(frame->hdr_metadata().getSerializedAgtm()->size(), 535u);
 
   Destroy();
 }
@@ -421,7 +421,7 @@
 
   const auto& frame = output_frames_.front();
   ASSERT_TRUE(frame->hdr_metadata().getSerializedAgtm());
-  EXPECT_EQ(frame->hdr_metadata().getSerializedAgtm()->size(), 533u);
+  EXPECT_EQ(frame->hdr_metadata().getSerializedAgtm()->size(), 535u);
 
   Destroy();
 }
diff --git a/media/gpu/av1_decoder_unittest.cc b/media/gpu/av1_decoder_unittest.cc
index c20f2141..c76e6cd 100644
--- a/media/gpu/av1_decoder_unittest.cc
+++ b/media/gpu/av1_decoder_unittest.cc
@@ -1046,7 +1046,7 @@
   EXPECT_EQ(results, expected);
   const gfx::HDRMetadata hdr_metadata = decoder_->GetHDRMetadata();
   ASSERT_TRUE(hdr_metadata.getSerializedAgtm());
-  EXPECT_EQ(hdr_metadata.getSerializedAgtm()->size(), 99u);
+  EXPECT_EQ(hdr_metadata.getSerializedAgtm()->size(), 101u);
 }
 
 // TODO(hiroh): Add more tests: reference frame tracking, render size change,
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 252dedd..f369aa98 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -429,8 +429,6 @@
     "display_color_spaces.h",
     "hdr_metadata.cc",
     "hdr_metadata.h",
-    "hdr_metadata_agtm.cc",
-    "hdr_metadata_agtm.h",
     "hdr_static_metadata.cc",
     "hdr_static_metadata.h",
     "icc_profile.cc",
diff --git a/ui/gfx/hdr_metadata.cc b/ui/gfx/hdr_metadata.cc
index d2b30ea9..db5ceb3 100644
--- a/ui/gfx/hdr_metadata.cc
+++ b/ui/gfx/hdr_metadata.cc
@@ -11,6 +11,7 @@
 #include "skia/ext/skcolorspace_primaries.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
 #include "third_party/skia/include/core/SkData.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/skia_span_util.h"
 #include "ui/gfx/switches.h"
 
@@ -33,7 +34,7 @@
       size_cmp != std::weak_ordering::equivalent) {
     return size_cmp;
   }
-  return gfx::SkDataToSpan(a) <=> SkDataToSpan(b);
+  return SkDataToSpan(a) <=> SkDataToSpan(b);
 }
 
 }  // namespace
@@ -121,7 +122,7 @@
 HDRMetadata::~HDRMetadata() = default;
 
 // static
-float HDRMetadata::GetContentMaxLuminance(const gfx::HDRMetadata& metadata) {
+float HDRMetadata::GetContentMaxLuminance(const HDRMetadata& metadata) {
   if (metadata.cta_861_3.has_value() &&
       metadata.cta_861_3->max_content_light_level > 0.f) {
     return metadata.cta_861_3->max_content_light_level;
@@ -134,8 +135,34 @@
 }
 
 // static
+float HDRMetadata::GetWaylandReferenceLuminance(
+    const ColorSpace& color_space,
+    const HDRMetadata& hdr_metadata) {
+  if (HdrMetadataAgtm::IsEnabled()) {
+    if (auto agtm_parsed =
+            skhdr::Agtm::Make(hdr_metadata.getSerializedAgtm())) {
+      return agtm_parsed->getHdrReferenceWhite();
+    }
+  }
+
+  if (hdr_metadata.ndwl.has_value() && hdr_metadata.ndwl->nits > 0.f) {
+    return hdr_metadata.ndwl->nits;
+  }
+
+  if (color_space.GetTransferID() == ColorSpace::TransferID::PQ ||
+      color_space.GetTransferID() == ColorSpace::TransferID::HLG) {
+    auto sk_color_space = color_space.ToSkColorSpace();
+    skcms_TransferFunction transfer_fn;
+    sk_color_space->transferFn(&transfer_fn);
+    return transfer_fn.a;
+  }
+
+  return ColorSpace::kDefaultSDRWhiteLevel;
+}
+
+// static
 HDRMetadata HDRMetadata::PopulateUnspecifiedWithDefaults(
-    const gfx::HDRMetadata& hdr_metadata) {
+    const HDRMetadata& hdr_metadata) {
   constexpr HdrMetadataSmpteSt2086 kDefaults2086(SkNamedPrimaries::kRec2020,
                                                  1000.f, 0.f);
 
diff --git a/ui/gfx/hdr_metadata.h b/ui/gfx/hdr_metadata.h
index 936d887..78afe3f 100644
--- a/ui/gfx/hdr_metadata.h
+++ b/ui/gfx/hdr_metadata.h
@@ -19,6 +19,8 @@
 
 namespace gfx {
 
+class ColorSpace;
+
 // Content light level info (CLLI) metadata from CTA 861.3.
 struct COLOR_SPACE_EXPORT HdrMetadataCta861_3 {
   constexpr HdrMetadataCta861_3() = default;
@@ -161,7 +163,11 @@
   // - return the CTA 861.3 max content light level metadata, if present
   // - return the SMPTE ST 2086 luminance max metadata, if present
   // - otherwise return 1,000 nits
-  static float GetContentMaxLuminance(const gfx::HDRMetadata& metadata);
+  static float GetContentMaxLuminance(const HDRMetadata& metadata);
+
+  // Compute the reference luminance for use with Wayland color management.
+  static float GetWaylandReferenceLuminance(const ColorSpace& color_space,
+                                            const HDRMetadata& hdr_metadata);
 
   // Return a copy of `hdr_metadata` with its `smpte_st_2086` fully
   // populated. Any unspecified values are set to default values (in particular,
@@ -170,7 +176,7 @@
   // `max_frame_average_light_level` values are not changed (they may stay
   // zero).
   static HDRMetadata PopulateUnspecifiedWithDefaults(
-      const gfx::HDRMetadata& hdr_metadata);
+      const HDRMetadata& hdr_metadata);
 
   std::string ToString() const;
 
diff --git a/ui/gfx/hdr_metadata_agtm.cc b/ui/gfx/hdr_metadata_agtm.cc
deleted file mode 100644
index e3719c38..0000000
--- a/ui/gfx/hdr_metadata_agtm.cc
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/hdr_metadata_agtm.h"
-
-#include "base/json/json_reader.h"
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkData.h"
-#include "ui/gfx/hdr_metadata.h"
-
-namespace gfx {
-
-namespace {
-
-bool ReadFloat(const base::DictValue* dict, const char* key, float& value) {
-  if (!dict) {
-    return false;
-  }
-  if (auto v = dict->FindDouble(key)) {
-    value = v.value();
-    return true;
-  }
-  return false;
-}
-
-// Read a piecewise cubic into a sampled SkImage
-bool ReadPiecewiseCubic(const base::DictValue* dict, sk_sp<SkImage>& curve) {
-  if (!dict) {
-    DVLOG(1) << "Piecewise cubic is missing";
-    return false;
-  }
-  // The parameters for the piecewise cubic segment.
-  float m_min = 0.f, m_span = 0.f;
-  float x0 = -1.f, y0 = 0.f, m0 = 0.f;
-  float x1 = -1.f, y1 = 0.f, m1 = 0.f;
-
-  // The output SkBitmap.
-  const size_t kSamples = 1024;
-  SkBitmap bm;
-  if (!bm.tryAllocPixels(SkImageInfo::Make(kSamples, 1, kA16_unorm_SkColorType,
-                                           kUnpremul_SkAlphaType))) {
-    DVLOG(1) << "Failed to allocate pixels for gain curve";
-    return false;
-  }
-
-  // The sample x value that is being written into `bm`.
-  size_t xi = 0;
-
-  // Function to evalue the current piecewise cubic segment.
-  auto eval_piecewise_cubic = [&](float x) {
-    // If x0 >= x1, then hold the y0 value. This can happen for repeated control
-    // points, or initializing values beyond the control points.
-    if (x0 >= x1) {
-      return y0;
-    }
-    const float m0p = (m_min + m_span * m0) * (x1 - x0);
-    const float m1p = (m_min + m_span * m1) * (x1 - x0);
-    const float c3 = (2.0 * y0 + m0p - 2.0 * y1 + m1p);
-    const float c2 = (-3.0 * y0 + 3.0 * y1 - 2.0 * m0p - m1p);
-    const float c1 = m0p;
-    const float c0 = y0;
-    const float t = (x - x0) / (x1 - x0);
-    return c0 + t * (c1 + t * (c2 + t * c3));
-  };
-
-  // Function to increment `xi` until it is past `x1`, writing values into `bm`
-  // along the way.
-  auto write_samples_through_x1 = [&]() {
-    while (xi < kSamples && xi / (kSamples - 1.f) < x1) {
-      const float y = eval_piecewise_cubic(xi / (kSamples - 1.f));
-      *bm.pixmap().writable_addr16(xi, 0) =
-          std::round(65535.f * std::clamp(y, 0.f, 1.f));
-      xi += 1;
-    }
-  };
-
-  // Read the parameters and control points, writing to `bm` along the way.
-  if (!ReadFloat(dict, "m_min", m_min) && !ReadFloat(dict, "m_span", m_span)) {
-    DVLOG(1) << "Missing slope minimum or span";
-    return false;
-  }
-  const auto* cp_list = dict->FindList("control_points");
-  if (!cp_list || cp_list->size() < 1 || cp_list->size() > 64) {
-    DVLOG(1) << "Control point list missing or incorrect size";
-    return false;
-  }
-  bool is_first_control_point = true;
-  for (const auto& control_point : *cp_list) {
-    x0 = x1;
-    y0 = y1;
-    m0 = m1;
-    const auto* control_point_dict = control_point.GetIfDict();
-    if (!ReadFloat(control_point_dict, "x", x1) ||
-        !ReadFloat(control_point_dict, "y", y1) ||
-        !ReadFloat(control_point_dict, "m", m1)) {
-      DVLOG(1) << "Control point missing x, y, or m value";
-      return false;
-    }
-    // Repeat the first control point, so that the piecewise cubic segment
-    // function will evaluate to a constant.
-    if (is_first_control_point) {
-      is_first_control_point = false;
-      x0 = x1;
-      y0 = y1;
-      m0 = m1;
-    }
-    // Samples must be sorted in increasing order.
-    if (x0 > x1) {
-      DVLOG(1) << "Sample x values not sorted";
-      return false;
-    }
-    // The function must have C0 continuity.
-    if (x0 == x1 && y0 != y1) {
-      DVLOG(1) << "Function not continuous";
-      return false;
-    }
-    // Write and increment xi until we need to read past x1.
-    write_samples_through_x1();
-  }
-
-  // Write all samples past the last control point. Repeat the last control
-  // point, so that the piecewise cubic segment function will evaluate to a
-  // constant.
-  x0 = x1;
-  y0 = y1;
-  m0 = m1;
-  write_samples_through_x1();
-
-  curve = SkImages::RasterFromPixmapCopy(bm.pixmap());
-  return true;
-}
-
-bool ReadAgtmAlternate(const base::DictValue* dict,
-                       HdrMetadataAgtmParsed::Alternate& altr) {
-  if (!ReadFloat(dict, "hdr_headroom", altr.hdr_headroom)) {
-    DVLOG(1) << "Alternate representation missing HDR headroom";
-    return false;
-  }
-  if (const auto* v = dict->FindDict("component_mix_params")) {
-    if (!ReadFloat(v, "red", altr.mix_rgbx[0]) &&
-        !ReadFloat(v, "green", altr.mix_rgbx[1]) &&
-        !ReadFloat(v, "blue", altr.mix_rgbx[2]) &&
-        !ReadFloat(v, "max", altr.mix_Mmcx[0]) &&
-        !ReadFloat(v, "min", altr.mix_Mmcx[1]) &&
-        !ReadFloat(v, "component", altr.mix_Mmcx[2])) {
-      DVLOG(1) << "Alternate missing component mix params";
-      return false;
-    }
-  } else {
-    DVLOG(1) << "Alternate missing component mix dictionary";
-    return false;
-  }
-  if (!ReadPiecewiseCubic(dict->FindDict("piecewise_cubic"), altr.curve)) {
-    DVLOG(1) << "Failed to piecewise cubic";
-    return false;
-  }
-  return true;
-}
-
-bool ReadAgtmRoot(const base::Value& value, HdrMetadataAgtmParsed& params) {
-  const auto* dict = value.GetIfDict();
-  if (!dict) {
-    DVLOG(1) << "Agtm root is not dictionary";
-    return false;
-  }
-  if (!ReadFloat(dict, "hdr_reference_white", params.hdr_reference_white) ||
-      !ReadFloat(dict, "baseline_hdr_headroom", params.baseline_hdr_headroom) ||
-      !ReadFloat(dict, "baseline_max_component",
-                 params.baseline_max_component) ||
-      !ReadFloat(dict, "gain_min", params.gain_min) ||
-      !ReadFloat(dict, "gain_span", params.gain_span) ||
-      !ReadFloat(dict, "gain_application_offset",
-                 params.gain_application_offset)) {
-    DVLOG(1) << "Required values are absent";
-    return false;
-  }
-  if (auto v = dict->FindInt("gain_application_space_primaries")) {
-    params.gain_application_color_space =
-        SkColorSpace::MakeCICP(static_cast<SkNamedPrimaries::CicpId>(v.value()),
-                               SkNamedTransferFn::CicpId::kLinear);
-  }
-  if (!params.gain_application_color_space) {
-    DVLOG(1) << "Invalid or absent gain application space primaries";
-    return false;
-  }
-  const auto* altr_list = dict->FindList("alternates");
-  if (altr_list) {
-    if (altr_list->size() > 4) {
-      DVLOG(1) << "Too many alternates";
-      return false;
-    }
-    for (const auto& altr_value : *altr_list) {
-      HdrMetadataAgtmParsed::Alternate altr;
-      if (!ReadAgtmAlternate(altr_value.GetIfDict(), altr)) {
-        DVLOG(1) << "Failed to read alternate parameters";
-        return false;
-      }
-      params.alternates.push_back(altr);
-    }
-  }
-  return true;
-}
-
-}  // namespace
-
-HdrMetadataAgtmParsed::HdrMetadataAgtmParsed() = default;
-HdrMetadataAgtmParsed::~HdrMetadataAgtmParsed() = default;
-
-bool HdrMetadataAgtmParsed::Parse(const SkData* payload) {
-  if (!HdrMetadataAgtm::IsEnabled()) {
-    return false;
-  }
-  if (!payload) {
-    DVLOG(1) << "Empty AGTM payload";
-    return false;
-  }
-  auto value = base::JSONReader::Read(
-      std::string_view(reinterpret_cast<const char*>(payload->data()),
-                       payload->size()),
-      base::JSON_PARSE_CHROMIUM_EXTENSIONS);
-  if (!value) {
-    DVLOG(1) << "Failed to parse AGTM metadata JSON";
-    return false;
-  }
-  if (!ReadAgtmRoot(value.value(), *this)) {
-    return false;
-  }
-  return true;
-}
-
-void HdrMetadataAgtmParsed::ComputeAlternateWeights(float H_target,
-                                                    size_t& i,
-                                                    float& w_i,
-                                                    size_t& j,
-                                                    float& w_j) const {
-  const float H_base = baseline_hdr_headroom;
-
-  // Let H_i and H_j be the HDR headrooms of the ith and jth representation.
-  // Set them to the same value to indicate that the ith representation should
-  // be used in full.
-  i = j = kBaselineIndex;
-  float H_i = H_base;
-  float H_j = H_base;
-
-  // Special-case the absence of any alternate representations.
-  if (alternates.empty()) {
-    w_i = w_j = 0.f;
-    return;
-  }
-
-  for (i = 0; i < alternates.size(); ++i) {
-    j = kBaselineIndex;
-    H_i = alternates[i].hdr_headroom;
-    H_j = H_base;
-
-    // Mix of i = 0 and potentially baseline
-    if (H_target <= H_i) {
-      DCHECK_EQ(i, 0u);
-      j = kBaselineIndex;
-      if (H_base <= H_i) {
-        H_j = H_base;
-      } else {
-        H_j = H_i;
-      }
-      break;
-    }
-
-    // Mix of i = N-1 and potentially baseline.
-    if (i == alternates.size() - 1) {
-      DCHECK_GT(H_target, H_i);
-      j = kBaselineIndex;
-      if (H_base >= H_i) {
-        H_j = H_base;
-      } else {
-        H_j = H_i;
-      }
-      break;
-    }
-
-    // Consider the interval between alternate representations i and i+1 only if
-    // H_target is in that interval.
-    j = i + 1;
-    H_j = alternates[j].hdr_headroom;
-    if (H_i <= H_target && H_target <= H_j) {
-      // If it's the case that i < target < base < i+1, then we will only mix
-      // i and base.
-      if (H_i <= H_target && H_target <= H_base && H_base <= H_j) {
-        j = kBaselineIndex;
-        H_j = H_base;
-      }
-
-      // If it's the case that i < base < target < i+1, then we will only mix
-      // i+1 and base.
-      if (H_i <= H_base && H_base <= H_target && H_target <= H_j) {
-        i = j;
-        H_i = H_j;
-        j = kBaselineIndex;
-        H_j = H_base;
-        break;
-      }
-
-      // Otherwise, it's the case that i < target < i+1 and base isn't in that
-      // interval.
-      DCHECK(H_i <= H_target && H_target <= H_j);
-      break;
-    }
-  }
-
-  // Compute the weights for the two representations.
-  if (H_j == H_i) {
-    w_i = 1.f;
-  } else {
-    w_i = std::min(std::max((H_target - H_j) / (H_i - H_j), 0.f), 1.f);
-  }
-  w_j = 1.f - w_i;
-
-  // Zero out baseline weights.
-  if (i == kBaselineIndex) {
-    w_i = 0.f;
-  }
-  if (j == kBaselineIndex) {
-    w_j = 0.f;
-  }
-}
-
-HdrMetadataAgtmParsed::Alternate::Alternate() = default;
-HdrMetadataAgtmParsed::Alternate::Alternate(const Alternate&) = default;
-HdrMetadataAgtmParsed::Alternate::Alternate(Alternate&&) = default;
-HdrMetadataAgtmParsed::Alternate& HdrMetadataAgtmParsed::Alternate::operator=(
-    const Alternate&) = default;
-HdrMetadataAgtmParsed::Alternate& HdrMetadataAgtmParsed::Alternate::operator=(
-    Alternate&&) = default;
-HdrMetadataAgtmParsed::Alternate::~Alternate() = default;
-
-}  // namespace gfx
diff --git a/ui/gfx/hdr_metadata_agtm.h b/ui/gfx/hdr_metadata_agtm.h
deleted file mode 100644
index 4631f453..0000000
--- a/ui/gfx/hdr_metadata_agtm.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_HDR_METADATA_AGTM_H_
-#define UI_GFX_HDR_METADATA_AGTM_H_
-
-#include <vector>
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkColorSpace.h"
-#include "third_party/skia/include/core/SkImage.h"
-#include "ui/gfx/color_space_export.h"
-
-namespace gfx {
-
-struct COLOR_SPACE_EXPORT HdrMetadataAgtmParsed {
-  HdrMetadataAgtmParsed();
-  HdrMetadataAgtmParsed(const HdrMetadataAgtmParsed&) = delete;
-  HdrMetadataAgtmParsed& operator=(const HdrMetadataAgtmParsed&) = delete;
-  ~HdrMetadataAgtmParsed();
-
-  bool Parse(const SkData* data);
-
-  // Compute the alternate indices and their weights for tone mapping targeting
-  // H_target. If w_i==0, then i may be kBaselineIndex, indicating that it does
-  // not refer to a valid alternate representation. Likewise for w_j. If i is
-  // kBaselineIndex then j is also kBaselineIndex.
-  static constexpr size_t kBaselineIndex = -1;
-  void ComputeAlternateWeights(float H_target,
-                               size_t& i,
-                               float& w_i,
-                               size_t& j,
-                               float& w_j) const;
-
-  // Luminance of HDR reference white in nits.
-  float hdr_reference_white = 0.f;
-
-  // Baseline representation HDR headroom.
-  float baseline_hdr_headroom = 0.f;
-
-  // The maximum component of the baseline image in the gain application space,
-  // used to convert from gain application space to [0,1] for evaluation.
-  float baseline_max_component = 0.f;
-
-  // Gain parameters to convert from [0,1] to real values.
-  float gain_min = 0.f;
-  float gain_span = 0.f;
-
-  // Gain application parameters.
-  float gain_application_offset = 0.f;
-  sk_sp<SkColorSpace> gain_application_color_space;
-
-  // Alternate representations' headrooms and gain curves.
-  struct Alternate {
-    Alternate();
-    Alternate(const Alternate&);
-    Alternate(Alternate&&);
-    Alternate& operator=(const Alternate&);
-    Alternate& operator=(Alternate&&);
-    ~Alternate();
-
-    // HDR headroom for the alternate representation.
-    float hdr_headroom;
-
-    // Component mixing function and gain curve parameters.
-    SkColor4f mix_rgbx{0.f, 0.f, 0.f, 0.f};
-    SkColor4f mix_Mmcx{1.f, 0.f, 0.f, 0.f};
-    sk_sp<SkImage> curve;
-  };
-  std::vector<Alternate> alternates;
-};
-
-}  // namespace gfx
-
-#endif  // UI_GFX_HDR_METADATA_AGTM_H_
diff --git a/ui/ozone/platform/wayland/host/wayland_wp_color_manager.cc b/ui/ozone/platform/wayland/host/wayland_wp_color_manager.cc
index a8e232d..c47b9b6 100644
--- a/ui/ozone/platform/wayland/host/wayland_wp_color_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_wp_color_manager.cc
@@ -8,7 +8,6 @@
 
 #include "base/feature_list.h"
 #include "base/logging.h"
-#include "ui/gfx/hdr_metadata_agtm.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
 
@@ -101,28 +100,6 @@
   }
 }
 
-float GetReferenceLuminance(const gfx::ColorSpace& color_space,
-                            const gfx::HDRMetadata& hdr_metadata) {
-  gfx::HdrMetadataAgtmParsed agtm;
-  if (agtm.Parse(hdr_metadata.getSerializedAgtm())) {
-    return agtm.hdr_reference_white;
-  }
-
-  if (hdr_metadata.ndwl.has_value() && hdr_metadata.ndwl->nits > 0.f) {
-    return hdr_metadata.ndwl->nits;
-  }
-
-  if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ ||
-      color_space.GetTransferID() == gfx::ColorSpace::TransferID::HLG) {
-    auto sk_color_space = color_space.ToSkColorSpace();
-    skcms_TransferFunction transfer_fn;
-    sk_color_space->transferFn(&transfer_fn);
-    return transfer_fn.a;
-  }
-
-  return gfx::ColorSpace::kDefaultSDRWhiteLevel;
-}
-
 }  // namespace
 
 // static
@@ -323,7 +300,8 @@
       }
     }
 
-    const float ref_luma = GetReferenceLuminance(color_space, hdr_metadata);
+    const float ref_luma = gfx::HDRMetadata::GetWaylandReferenceLuminance(
+        color_space, hdr_metadata);
     if (IsSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES)) {
       wp_image_description_creator_params_v1_set_luminances(
           creator, 0, gfx::HDRMetadata::GetContentMaxLuminance(hdr_metadata),