Fix serialization of computed style for 'paint-order'

We were always serializing as the completed (all keywords present) form,
which is not the shortest canonical form.

 https://svgwg.org/svg2-draft/painting.html#PaintOrder

Fold the ComputedStyleUtils helper into the PaintOrder CSSProperty
class, since this is very specific to this property.

Matches WebKit and almost Gecko (which seems to handle some "two
keyword" cases differently.)

Bug: 904898
Change-Id: Ib796a111e601485e339fdf2739a587fb5f893b8a
Reviewed-on: https://chromium-review.googlesource.com/c/1335579
Commit-Queue: Eric Willigers <ericwilligers@chromium.org>
Reviewed-by: Eric Willigers <ericwilligers@chromium.org>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608623}
diff --git a/third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html b/third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html
index 4f35fe6..0d3fe11d 100644
--- a/third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html
@@ -42,7 +42,7 @@
   ['mask-type', 'alpha'],
   ['opacity', '0.25'],
   ['overflow', 'hidden'],
-  ['paint-order', 'fill markers stroke'],
+  ['paint-order', 'fill markers'],
   ['pointer-events', 'all'],
   ['shape-rendering', 'geometricprecision'],
   ['stop-color', 'rgb(1, 2, 3)'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/paint-order-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/paint-order-expected.txt
index 422268b..9e96f0ef 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/paint-order-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/paint-order-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS Can set 'paint-order' to CSS-wide keywords
 PASS Can set 'paint-order' to var() references
-FAIL Can set 'paint-order' to the 'normal' keyword assert_equals: expected "CSSKeywordValue" but got "CSSStyleValue"
+PASS Can set 'paint-order' to the 'normal' keyword
 FAIL Can set 'paint-order' to the 'fill' keyword assert_equals: expected "CSSKeywordValue" but got "CSSStyleValue"
 FAIL Can set 'paint-order' to the 'stroke' keyword assert_equals: expected "CSSKeywordValue" but got "CSSStyleValue"
 FAIL Can set 'paint-order' to the 'markers' keyword assert_equals: expected "CSSKeywordValue" but got "CSSStyleValue"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/inheritance-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/inheritance-expected.txt
index 0359b5a..4a14ba1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/inheritance-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/inheritance-expected.txt
@@ -27,8 +27,8 @@
 PASS Property marker-mid inherits
 PASS Property marker-end has initial value none
 PASS Property marker-end inherits
-FAIL Property paint-order has initial value normal assert_equals: expected "normal" but got "fill stroke markers"
-FAIL Property paint-order inherits assert_equals: expected "markers stroke" but got "markers stroke fill"
+PASS Property paint-order has initial value normal
+PASS Property paint-order inherits
 PASS Property color-interpolation has initial value srgb
 PASS Property color-interpolation inherits
 PASS Property color-rendering has initial value auto
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/scripted/paint-order-computed-value-01.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/scripted/paint-order-computed-value-01.svg
new file mode 100644
index 0000000..7ea669f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/scripted/paint-order-computed-value-01.svg
@@ -0,0 +1,62 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>'paint-order' computed style serialization</title>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <text id="text" x="100" y="100"/>
+  <script><![CDATA[
+    'use strict';
+
+    function make_tests(check, type) {
+      let tests = [
+        // Single keyword
+        ["normal", "normal"],
+        ["fill", "fill"],
+        ["stroke", "stroke"],
+        ["markers", "markers"],
+        // Two keywords
+        ["fill stroke", "fill"],
+        ["fill markers", "fill markers"],
+        ["stroke fill", "stroke"],
+        ["stroke markers", "stroke markers"],
+        ["markers fill", "markers"],
+        ["markers stroke", "markers stroke"],
+        // Three keywords
+        ["fill stroke markers", "fill"],
+        ["fill markers stroke", "fill markers"],
+        ["stroke fill markers", "stroke"],
+        ["stroke markers fill", "stroke markers"],
+        ["markers fill stroke", "markers"],
+        ["markers stroke fill", "markers stroke"],
+        // Invalid
+        ["foo", "normal"],
+        ["fill foo", "normal"],
+        ["stroke foo", "normal"],
+        ["markers foo", "normal"],
+        ["normal foo", "normal"],
+        ["fill markers stroke foo", "normal"],
+      ];
+      for (let [value, expected] of tests) {
+        test(() => {
+          check(value, expected);
+        }, `${document.title}, "${value}" => "${expected}" (${type})`);
+      }
+    }
+
+    const text = document.getElementById("text");
+
+    make_tests((value, expected) => {
+      text.setAttribute("style", "paint-order: " + value);
+      let actual = getComputedStyle(text).paintOrder;
+      text.removeAttribute("style");
+      assert_equals(actual, expected, value);
+    }, "property");
+
+    make_tests((value, expected) => {
+      text.setAttribute("paint-order", value);
+      let actual = getComputedStyle(text).paintOrder;
+      text.removeAttribute("paint-order");
+      assert_equals(actual, expected, value);
+    }, "presentation attribute");
+  ]]>
+  </script>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt
index 9e547a2..949315d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 566 tests; 398 PASS, 168 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 566 tests; 400 PASS, 166 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Setup
 PASS align-content (type: discrete) has testAccumulation function
 PASS align-content: "flex-end" onto "flex-start"
@@ -408,8 +408,8 @@
 PASS page-break-inside: "avoid" onto "auto"
 PASS page-break-inside: "auto" onto "avoid"
 PASS paint-order (type: discrete) has testAccumulation function
-FAIL paint-order: "stroke" onto "fill" assert_equals: The value should be stroke at 0ms expected "stroke" but got "stroke fill markers"
-FAIL paint-order: "fill" onto "stroke" assert_equals: The value should be fill at 0ms expected "fill" but got "fill stroke markers"
+PASS paint-order: "stroke" onto "fill"
+PASS paint-order: "fill" onto "stroke"
 PASS perspective (type: length) has testAccumulation function
 FAIL perspective: length assert_equals: The value should be 20px at 0ms expected "20px" but got "10px"
 FAIL perspective: length of rem assert_equals: The value should be 20px at 0ms expected "20px" but got "10px"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt
index 89a39f6..482d537 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 562 tests; 528 PASS, 34 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 562 tests; 530 PASS, 32 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Setup
 PASS align-content (type: discrete) has testAddition function
 PASS align-content: "flex-end" onto "flex-start"
@@ -408,8 +408,8 @@
 PASS page-break-inside: "avoid" onto "auto"
 PASS page-break-inside: "auto" onto "avoid"
 PASS paint-order (type: discrete) has testAddition function
-FAIL paint-order: "stroke" onto "fill" assert_equals: The value should be stroke at 0ms expected "stroke" but got "stroke fill markers"
-FAIL paint-order: "fill" onto "stroke" assert_equals: The value should be fill at 0ms expected "fill" but got "fill stroke markers"
+PASS paint-order: "stroke" onto "fill"
+PASS paint-order: "fill" onto "stroke"
 PASS perspective (type: length) has testAddition function
 PASS perspective: length
 PASS perspective: length of rem
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt
index 68e3417..6a24e5f4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 701 tests; 640 PASS, 61 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 701 tests; 643 PASS, 58 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Setup
 PASS align-content (type: discrete) has testInterpolation function
 PASS align-content uses discrete animation when animating between "flex-start" and "flex-end" with linear easing
@@ -507,9 +507,9 @@
 PASS page-break-inside uses discrete animation when animating between "auto" and "avoid" with effect easing
 PASS page-break-inside uses discrete animation when animating between "auto" and "avoid" with keyframe easing
 PASS paint-order (type: discrete) has testInterpolation function
-FAIL paint-order uses discrete animation when animating between "fill" and "stroke" with linear easing assert_equals: The value should be fill at 0ms expected "fill" but got "fill stroke markers"
-FAIL paint-order uses discrete animation when animating between "fill" and "stroke" with effect easing assert_equals: The value should be fill at 0ms expected "fill" but got "fill stroke markers"
-FAIL paint-order uses discrete animation when animating between "fill" and "stroke" with keyframe easing assert_equals: The value should be fill at 0ms expected "fill" but got "fill stroke markers"
+PASS paint-order uses discrete animation when animating between "fill" and "stroke" with linear easing
+PASS paint-order uses discrete animation when animating between "fill" and "stroke" with effect easing
+PASS paint-order uses discrete animation when animating between "fill" and "stroke" with keyframe easing
 PASS perspective (type: length) has testInterpolation function
 PASS perspective supports animating as a length
 PASS perspective supports animating as a length of rem
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
index 865a566..8fb0590 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -223,7 +223,7 @@
 padding-left: 0px
 padding-right: 0px
 padding-top: 0px
-paint-order: fill stroke markers
+paint-order: normal
 perspective: none
 perspective-origin: 384.5px 0px
 pointer-events: auto
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
index f625300..7e2b26b 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -223,7 +223,7 @@
 padding-left: 0px
 padding-right: 0px
 padding-top: 0px
-paint-order: fill stroke markers
+paint-order: normal
 perspective: none
 perspective-origin: 50% 50%
 pointer-events: auto
diff --git a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
index a703720d..8f5df78 100644
--- a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
@@ -224,7 +224,7 @@
 padding-left: 0px
 padding-right: 0px
 padding-top: 0px
-paint-order: fill stroke markers
+paint-order: normal
 perspective: none
 perspective-origin: 0px 0px
 pointer-events: auto
diff --git a/third_party/WebKit/LayoutTests/svg/css/script-tests/svg-paint-order.js b/third_party/WebKit/LayoutTests/svg/css/script-tests/svg-paint-order.js
deleted file mode 100644
index d0f70ed..0000000
--- a/third_party/WebKit/LayoutTests/svg/css/script-tests/svg-paint-order.js
+++ /dev/null
@@ -1,101 +0,0 @@
-description("Test paint-order.")
-
-if (window.testRunner)
-    testRunner.dumpAsText();
-createSVGTestCase();
-
-var text = createSVGElement("text");
-text.setAttribute("id", "text");
-text.setAttribute("x", "100px");
-text.setAttribute("y", "100px");
-rootSVGElement.appendChild(text);
-
-function test(valueString, expectedValue) {
-    // Reset paint-order.
-    text.removeAttribute("style");
-
-    // Run test
-    text.setAttribute("style", "paint-order: " + valueString);
-    shouldBeEqualToString("getComputedStyle(text).paintOrder", expectedValue);
-}
-
-function test_attr(valueString, expectedValue) {
-    // Reset paint-order.
-    text.removeAttribute("paint-order");
-
-    // Run test
-    text.setAttribute("paint-order", valueString);
-    shouldBeEqualToString("getComputedStyle(text).paintOrder", expectedValue);
-}
-
-debug("");
-debug("Test pre-normalized correct variants of 'paint-order'");
-test("fill stroke markers", "fill stroke markers");
-test("fill markers stroke", "fill markers stroke");
-test("stroke fill markers", "stroke fill markers");
-test("stroke markers fill", "stroke markers fill");
-test("markers stroke fill", "markers stroke fill");
-test("markers fill stroke", "markers fill stroke");
-
-debug("");
-debug("Test correct single keyword value of 'paint-order'");
-test("normal", "fill stroke markers");
-test("fill", "fill stroke markers");
-test("stroke", "stroke fill markers");
-test("markers", "markers fill stroke");
-
-debug("");
-debug("Test correct dual keyword values of 'paint-order'");
-test("fill stroke", "fill stroke markers");
-test("fill markers", "fill markers stroke");
-test("stroke fill", "stroke fill markers");
-test("stroke markers", "stroke markers fill");
-test("markers fill", "markers fill stroke");
-test("markers stroke", "markers stroke fill");
-
-debug("");
-debug("Test invalid values of 'paint-order'");
-test("foo", "fill stroke markers");
-test("fill foo", "fill stroke markers");
-test("stroke foo", "fill stroke markers");
-test("markers foo", "fill stroke markers");
-test("normal foo", "fill stroke markers");
-test("fill markers stroke foo", "fill stroke markers");
-
-debug("");
-debug("Test pre-normalized correct variants of 'paint-order' (presentation attribute)");
-test_attr("fill stroke markers", "fill stroke markers");
-test_attr("fill markers stroke", "fill markers stroke");
-test_attr("stroke fill markers", "stroke fill markers");
-test_attr("stroke markers fill", "stroke markers fill");
-test_attr("markers stroke fill", "markers stroke fill");
-test_attr("markers fill stroke", "markers fill stroke");
-
-debug("");
-debug("Test correct single keyword value of 'paint-order' (presentation attribute)");
-test_attr("normal", "fill stroke markers");
-test_attr("fill", "fill stroke markers");
-test_attr("stroke", "stroke fill markers");
-test_attr("markers", "markers fill stroke");
-
-debug("");
-debug("Test correct dual keyword values of 'paint-order' (presentation attribute)");
-test_attr("fill stroke", "fill stroke markers");
-test_attr("fill markers", "fill markers stroke");
-test_attr("stroke fill", "stroke fill markers");
-test_attr("stroke markers", "stroke markers fill");
-test_attr("markers fill", "markers fill stroke");
-test_attr("markers stroke", "markers stroke fill");
-
-debug("");
-debug("Test invalid values of 'paint-order' (presentation attribute)");
-test_attr("foo", "fill stroke markers");
-test_attr("fill foo", "fill stroke markers");
-test_attr("stroke foo", "fill stroke markers");
-test_attr("markers foo", "fill stroke markers");
-test_attr("normal foo", "fill stroke markers");
-test_attr("fill markers stroke foo", "fill stroke markers");
-
-var successfullyParsed = true;
-
-completeTest();
diff --git a/third_party/WebKit/LayoutTests/svg/css/svg-paint-order-expected.txt b/third_party/WebKit/LayoutTests/svg/css/svg-paint-order-expected.txt
deleted file mode 100644
index de2bfa3a..0000000
--- a/third_party/WebKit/LayoutTests/svg/css/svg-paint-order-expected.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-Test paint-order.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-
-Test pre-normalized correct variants of 'paint-order'
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill markers stroke"
-PASS getComputedStyle(text).paintOrder is "stroke fill markers"
-PASS getComputedStyle(text).paintOrder is "stroke markers fill"
-PASS getComputedStyle(text).paintOrder is "markers stroke fill"
-PASS getComputedStyle(text).paintOrder is "markers fill stroke"
-
-Test correct single keyword value of 'paint-order'
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "stroke fill markers"
-PASS getComputedStyle(text).paintOrder is "markers fill stroke"
-
-Test correct dual keyword values of 'paint-order'
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill markers stroke"
-PASS getComputedStyle(text).paintOrder is "stroke fill markers"
-PASS getComputedStyle(text).paintOrder is "stroke markers fill"
-PASS getComputedStyle(text).paintOrder is "markers fill stroke"
-PASS getComputedStyle(text).paintOrder is "markers stroke fill"
-
-Test invalid values of 'paint-order'
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-
-Test pre-normalized correct variants of 'paint-order' (presentation attribute)
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill markers stroke"
-PASS getComputedStyle(text).paintOrder is "stroke fill markers"
-PASS getComputedStyle(text).paintOrder is "stroke markers fill"
-PASS getComputedStyle(text).paintOrder is "markers stroke fill"
-PASS getComputedStyle(text).paintOrder is "markers fill stroke"
-
-Test correct single keyword value of 'paint-order' (presentation attribute)
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "stroke fill markers"
-PASS getComputedStyle(text).paintOrder is "markers fill stroke"
-
-Test correct dual keyword values of 'paint-order' (presentation attribute)
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill markers stroke"
-PASS getComputedStyle(text).paintOrder is "stroke fill markers"
-PASS getComputedStyle(text).paintOrder is "stroke markers fill"
-PASS getComputedStyle(text).paintOrder is "markers fill stroke"
-PASS getComputedStyle(text).paintOrder is "markers stroke fill"
-
-Test invalid values of 'paint-order' (presentation attribute)
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS getComputedStyle(text).paintOrder is "fill stroke markers"
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/svg/css/svg-paint-order.html b/third_party/WebKit/LayoutTests/svg/css/svg-paint-order.html
deleted file mode 100644
index f652f54..0000000
--- a/third_party/WebKit/LayoutTests/svg/css/svg-paint-order.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../svg/animations/resources/SVGTestCase.js"></script>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/svg-paint-order.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 2f6d5be..73b8a08f 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -1856,27 +1856,6 @@
   return list;
 }
 
-CSSValue* ComputedStyleUtils::PaintOrderToCSSValueList(
-    const SVGComputedStyle& svg_style) {
-  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  for (int i = 0; i < 3; i++) {
-    EPaintOrderType paint_order_type = svg_style.PaintOrderType(i);
-    switch (paint_order_type) {
-      case PT_FILL:
-      case PT_STROKE:
-      case PT_MARKERS:
-        list->Append(*CSSIdentifierValue::Create(paint_order_type));
-        break;
-      case PT_NONE:
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  return list;
-}
-
 CSSValue* ComputedStyleUtils::AdjustSVGPaintForCurrentColor(
     const SVGPaint& paint,
     const Color& current_color) {
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
index ac673d6..b4133ee 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.h
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -143,7 +143,6 @@
   static CSSValueList* ValueForBorderRadiusShorthand(const ComputedStyle&);
   static CSSValue* StrokeDashArrayToCSSValueList(const SVGDashArray&,
                                                  const ComputedStyle&);
-  static CSSValue* PaintOrderToCSSValueList(const SVGComputedStyle&);
   static CSSValue* AdjustSVGPaintForCurrentColor(const SVGPaint&, const Color&);
   static CSSValue* ValueForSVGResource(const StyleSVGResource*);
   static CSSValue* ValueForShadowData(const ShadowData&,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/paint_order_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/paint_order_custom.cc
index 07bcf3f2..a3c6a6b 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/paint_order_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/paint_order_custom.cc
@@ -6,7 +6,6 @@
 
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
-#include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 
 namespace blink {
@@ -69,9 +68,38 @@
     const ComputedStyle&,
     const SVGComputedStyle& svg_style,
     const LayoutObject*,
-    Node* styled_node,
+    Node*,
     bool allow_visited_style) const {
-  return ComputedStyleUtils::PaintOrderToCSSValueList(svg_style);
+  const EPaintOrder paint_order = svg_style.PaintOrder();
+  if (paint_order == kPaintOrderNormal)
+    return CSSIdentifierValue::Create(CSSValueNormal);
+
+  // Table mapping to the shortest (canonical) form of the property.
+  //
+  // Per spec, if any keyword is omitted it will be added last using
+  // the standard ordering. So "stroke" implies an order "stroke fill
+  // markers" etc. From a serialization PoV this means we never need
+  // to emit the last keyword.
+  //
+  // https://svgwg.org/svg2-draft/painting.html#PaintOrder
+  static const uint8_t canonical_form[][2] = {
+      // kPaintOrderNormal is handled above.
+      {PT_FILL, PT_NONE},       // kPaintOrderFillStrokeMarkers
+      {PT_FILL, PT_MARKERS},    // kPaintOrderFillMarkersStroke
+      {PT_STROKE, PT_NONE},     // kPaintOrderStrokeFillMarkers
+      {PT_STROKE, PT_MARKERS},  // kPaintOrderStrokeMarkersFill
+      {PT_MARKERS, PT_NONE},    // kPaintOrderMarkersFillStroke
+      {PT_MARKERS, PT_STROKE},  // kPaintOrderMarkersStrokeFill
+  };
+  DCHECK_LT(static_cast<size_t>(paint_order) - 1, base::size(canonical_form));
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  for (const auto& keyword : canonical_form[paint_order - 1]) {
+    const auto paint_order_type = static_cast<EPaintOrderType>(keyword);
+    if (paint_order_type == PT_NONE)
+      break;
+    list->Append(*CSSIdentifierValue::Create(paint_order_type));
+  }
+  return list;
 }
 
 }  // namespace CSSLonghand