wpt / svg / geometry / svg-length-convert-to-percentage-precision.html

Status: FAIL | Duration: 48ms | Subtests: 0/1 | Open test on wpt.live | wpt.fyi

/svg/geometry/svg-length-convert-to-percentage-precision.html

<!DOCTYPE html>
<title>SVGLength.convertToSpecifiedUnits percentage precision</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGLength__convertToSpecifiedUnits"/>
<svg width="0" height="0">
  <!-- 120px in a 400-wide viewport: 120/400 = 30% exactly -->
  <svg id="vp1" width="400" height="400">
    <rect id="r1" width="120" height="120"/>
  </svg>
  <!-- 180px in a 600-wide viewport: 180/600 = 30% exactly -->
  <svg id="vp2" width="600" height="400">
    <rect id="r2" width="180" height="120"/>
  </svg>
  <!-- 120px in a 700-wide viewport: 120/700 = 17.142857...% -->
  <svg id="vp3" width="700" height="400">
    <rect id="r3" width="120" height="120"/>
  </svg>
</svg>
<script>
const SVG_LENGTHTYPE_PERCENTAGE = SVGLength.SVG_LENGTHTYPE_PERCENTAGE;

// 120px width in a 400px viewport should convert to exactly 30%
// With float arithmetic: 120.0f / 400.0f = 0.3f = 0.300000011...
//   then * 100 = 30.0000019... (one ULP above 30)
// With double arithmetic: 120.0 / 400.0 * 100 rounds to exactly 30.0
let tWidth400 = async_test("convertToSpecifiedUnits: width 120px in 400px viewport = 30%");
let tWidth400Done = tWidth400.step_func_done(() => {
  let width = document.getElementById("r1").width.baseVal;
  assert_equals(width.value, 120, "r1.width starts at 120 user units");
  width.convertToSpecifiedUnits(SVG_LENGTHTYPE_PERCENTAGE);
  assert_equals(width.valueInSpecifiedUnits, 30,
    "120px / 400px viewport = exactly 30%");
});

// 120px height in a 400px viewport (height dimension)
let tHeight400 = async_test("convertToSpecifiedUnits: height 120px in 400px viewport = 30%");
let tHeight400Done = tHeight400.step_func_done(() => {
  let height = document.getElementById("r1").height.baseVal;
  assert_equals(height.value, 120, "r1.height starts at 120 user units");
  height.convertToSpecifiedUnits(SVG_LENGTHTYPE_PERCENTAGE);
  assert_equals(height.valueInSpecifiedUnits, 30,
    "120px / 400px viewport height = exactly 30%");
});

// 180px in a 600px viewport: 180/600 = 0.3, same float rounding trap
let tWidth600 = async_test("convertToSpecifiedUnits: width 180px in 600px viewport = 30%");
let tWidth600Done = tWidth600.step_func_done(() => {
  let width = document.getElementById("r2").width.baseVal;
  assert_equals(width.value, 180, "r2.width starts at 180 user units");
  width.convertToSpecifiedUnits(SVG_LENGTHTYPE_PERCENTAGE);
  assert_equals(width.valueInSpecifiedUnits, 30,
    "180px / 600px viewport = exactly 30%");
});

// 120px in a 700px viewport: 120/700 is not exactly representable
// in any precision, but double gives a much closer result.
// float:  120.0f / 700.0f * 100 = 17.142858505249023...
// double: 120.0  / 700.0  * 100 = 17.142857142857142...
let tWidth700 = async_test("convertToSpecifiedUnits: 120px in 700px viewport (irrational %)");
let tWidth700Done = tWidth700.step_func_done(() => {
  let width = document.getElementById("r3").width.baseVal;
  assert_equals(width.value, 120, "r3.width starts at 120 user units");
  width.convertToSpecifiedUnits(SVG_LENGTHTYPE_PERCENTAGE);
  let result = width.valueInSpecifiedUnits;
  // With double precision the result should be closer to the exact value
  assert_approx_equals(result, 120 / 700 * 100, 1e-6,
    "120px / 700px viewport should be close to 17.142857...");
});

const main = () => {
  window.requestAnimationFrame(() => {
    tWidth400Done();
    tHeight400Done();
    tWidth600Done();
    tWidth700Done();
  });
};

if (document.readyState === "complete") {
  main();
} else {
  window.addEventListener("load", main);
}
</script>