summaryrefslogtreecommitdiffstats
path: root/dom/svg/test/reftest_viewport_noninteger.html
blob: 3f4852b53925fd0e67d83b9a7ef30867bc2cde17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>SVG size test</title>
    <style>
      body {
        margin: 30px;
        font-family: sans-serif;
      }

      #tests {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        grid-gap: 30px;
      }

      #tests div:hover {
        opacity: 1 !important;
      }

      #tests p {
        text-decoration: underline dotted black;
      }

      svg {
        background: lightgrey;
      }
    </style>
  </head>
  <body>
    <h1>SVG size test</h1>

    <p>The grey boxes below are <code>&lt;svg&gt;</code> elements.</p>
    <p>All SVGs in each row should have the exact same size.</p>
    <p>Each row has its own viewBox width and height: <code>viewBox="0 0 width height"</code>.</p>
    <p>Each column has its own width/height styling. For example, <code>style="width: 200px; height: auto;"</code>.</p>
    <p>The first column has both an explicit widht and an explicit height, so there's not much that can go wrong there. It acts as a reference.</p>
    <p>The first row has integer viewBox width and height. Firefox then sizes all SVGs correctly.</p>
    <p>The remaining rows have at least one non-integer viewBox width and height. Firefox then sizes the SVGs a bit wrong.</p>
    <p>Chrome, Safari and Edge seem to pass all tests.</p>

    <p id="summary"></p>

    <div id="tests"></div>

    <script>
      const testsElement = document.getElementById("tests");
      const summaryElement = document.getElementById("summary");

      // Turn for instance `2.3` into `230` (px). Round to avoid floating point
      // issues.
      const scale = (number) => Math.round(100 * number);

      const widths = [2, 2.3, 2.5, 2.8];
      const heights = [3, 3.3, 3.5, 3.8];

      let numPassed = 0;
      let numFailed = 0;

      for (const width of widths) {
        for (const height of heights) {
          const variations = [
            {width, height},
            {width: "auto", height},
            {width, height: "auto"},
            {width: "auto", height: "auto"},
          ];

          for (const variation of variations) {
            const cellElement = document.createElement("div");

            const titleElement = document.createElement("h2");
            titleElement.appendChild(makeTitle(width, height, variation));

            const sizeElement = document.createElement("p");

            const svgWrapperElement = document.createElement("div");
            svgWrapperElement.style.width =
              variation.width === "auto" && variation.height === "auto"
                ? `${scale(width)}px`
                : "auto";

            const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svgElement.setAttribute("viewBox", `0 0 ${width} ${height}`);
            svgElement.style.width =
              typeof variation.width === "number"
                ? `${scale(variation.width)}px`
                : variation.width;
            svgElement.style.height =
              typeof variation.height === "number"
                ? `${scale(variation.height)}px`
                : variation.height;

            svgWrapperElement.appendChild(svgElement);

            cellElement.appendChild(titleElement);
            cellElement.appendChild(sizeElement);
            cellElement.appendChild(svgWrapperElement);

            testsElement.appendChild(cellElement);

            const rect = svgElement.getBoundingClientRect();
            const actual = {
              width: Math.round(rect.width),
              height: Math.round(rect.height),
            };
            const expected = {
              width: scale(width),
              height: scale(height),
            };
            const passed =
              actual.width === expected.width &&
              actual.height === expected.height;

            const icon = passed ? "✔" : "✘";
            const iconText = passed ? "PASS" : "FAIL";
            const expectedText = passed ? "" : `\nExpected size: ${expected.width}x${expected.height}`;
            sizeElement.textContent = `${icon} ${actual.width}x${actual.height}`;
            sizeElement.title = `${iconText}. Actual size, as measured by element.getBoundingClientRect().${expectedText}`;
            sizeElement.style.color = passed ? "lime" : "red";
            sizeElement.style.fontWeight = passed ? "normal" : "bold";

            cellElement.style.opacity = passed ? 0.5 : 1;

            if (passed) {
              numPassed++;
            } else {
              numFailed++;
            }
          }
        }
      }

      const numTotal = numPassed + numFailed;
      const passed = numFailed === 0;
      const icon = passed ? "✔" : "✘";
      summaryElement.textContent = `${icon} ${numPassed}/${numTotal} tests passed.`;
      summaryElement.style.color = passed ? "lime" : "red";
      summaryElement.style.fontWeight = "bold";

      function makeTitle(width, height, variation) {
        const fragment = document.createDocumentFragment();

        const first = document.createElement("abbr");
        first.textContent = `${width}/${height}`;
        first.title = `SVG viewBox width/height: viewBox="0 0 ${width} ${height}"`;

        const separator = document.createTextNode(" | ");

        const second = document.createElement("abbr");

        const widthString = typeof variation.width === "number" ? "px" : variation.width;
        const heightString = typeof variation.height === "number" ? "px" : variation.height;
        second.textContent = `${widthString}/${heightString}`;

        const widthExplanation =
          typeof variation.width === "number"
            ? "explicit width (px)"
            : `${variation.width} width`
        const heightExplanation =
          typeof variation.height === "number"
            ? "explicit height (px)"
            : `${variation.height} height`
        second.title = `${widthExplanation}, ${heightExplanation}`;

        fragment.appendChild(first);
        fragment.appendChild(separator);
        fragment.appendChild(second);

        return fragment;
      }
    </script>
  </body>
</html>