Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1703)

Side by Side Diff: LayoutTests/svg/in-html/sizing/svg-inline.js

Issue 26390004: Rework SVG sizing (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Minor touch-ups to the tests; only fail now should be crbug.com/363126 Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // global async_test, assert_equals
2 //
3 // This test generates a couple of scenarios (each a TestData) for
4 // sizing inline <svg> and has a simple JavaScript sizing
5 // implementation that handles the generated scenarios. It generates a
6 // DOM corresponding to the scenario and compares the laid out size to
7 // the calculated size.
8 //
9 // The tests loops through different combinations of:
10 //
11 // * width and height on <svg>, both through style and attributes
12 //
13 // * viewBox on <svg> (gives intrinsic ratio)
14 //
15 // * width and height on containing block of <object>
16 //
17 // All these contribute to the final size of the SVG in some way.
18 //
19 // The test focuses on the size of the CSS box generated by the SVG.
20 // The SVG is always empty by itself so no actual SVG are tested.
21 //
22 // Focus is also put on how the different attributes interact, little
23 // focus is put on variations within an attribute that doesn't affect
24 // the relationship to other attributes, i.e only px and % units are
25 // used since that covers the interactions.
26 //
27 // To debug a specific test append ?<test-id> to the URL. An <iframe>
28 // is generated with equivalent test and the source of the test is
29 // added to a <pre> element.
30
31 (function() {
32 function parseLength(l) {
33 var match = /^([-+]?[0-9]+|[-+]?[0-9]*\.[0-9]+)(px|%)?$/.exec(l);
34 if (!match)
35 return null;
36 return new Length(Number(match[1]), match[2] ? match[2] : "px");
37 }
38
39 function parseViewBox(input) {
40 if (!input)
41 return null;
42
43 var arr = input.split(' ');
44 return arr.map(function(a) { return parseInt(a); });
45 }
46
47 // Only px and % are used
48 function convertToPx(input, percentRef) {
49 if (input == null)
50 return null;
51 var length = parseLength(input);
52 if (length.amount == 0)
53 return 0;
54 if (!length.unit)
55 length.unit = "px";
56 if (length.unit == "%" && percentRef === undefined)
57 return null;
58 return length.amount * { px: 1,
59 "%": percentRef/100}[length.unit];
60 }
61
62 function Length(amount, unit) {
63 this.amount = amount;
64 this.unit = unit;
65 }
66
67 function describe(data) {
68 function dumpObject(obj) {
69 var r = "";
70 for (var property in obj) {
71 if (obj.hasOwnProperty(property)) {
72 var value = obj[property];
73 if (typeof value == 'string')
74 value = "'" + value + "'";
75 else if (value == null)
76 value = "null";
77 else if (typeof value == 'object')
78 {
79 if (value instanceof Array)
80 value = "[" + value + "]";
81 else
82 value = "{" + dumpObject(value) + "}";
83 }
84
85 if (value != "null")
86 r += property + ": " + value + ", ";
87 }
88 }
89 return r;
90 }
91 var result = dumpObject(data);
92 if (result == "")
93 return "(initial values)";
94 return result;
95 }
96
97 function TestData(config) {
98 this.config = config;
99 this.name = describe(config);
100 this.style = {};
101 if (config.svgWidthStyle)
102 this.style["width"] = config.svgWidthStyle;
103 else
104 this.mapPresentationalHintLength("width", config.svgWidthAttr);
105
106 if (config.svgHeightStyle)
107 this.style["height"] = config.svgHeightStyle;
108 else
109 this.mapPresentationalHintLength("height", config.svgHeightAttr);
110 }
111
112 TestData.prototype.mapPresentationalHintLength =
113 function(cssProperty, attr) {
114 if (attr) {
115 var l = parseLength(attr);
116 if (l)
117 this.style[cssProperty] = l.amount + l.unit;
118 }
119 };
120
121 TestData.prototype.computedWidthIsAuto = function() {
122 return !this.style["width"] || this.style["width"] == 'auto';
123 };
124
125 TestData.prototype.computedHeightIsAuto = function() {
126 return !this.style["height"] || this.style["height"] == 'auto' ||
127 (parseLength(this.style["height"]).unit == '%' &&
128 this.containerComputedHeightIsAuto());
129 };
130
131 TestData.prototype.containerComputedWidthIsAuto = function() {
132 return !this.config.containerWidthStyle ||
133 this.config.containerWidthStyle == 'auto';
134 };
135
136 TestData.prototype.containerComputedHeightIsAuto = function() {
137 return !this.config.containerHeightStyle ||
138 this.config.containerHeightStyle == 'auto';
139 };
140
141 TestData.prototype.intrinsicInformation = function() {
142 var w = convertToPx(this.config.svgWidthAttr) || 0;
143 var h = convertToPx(this.config.svgHeightAttr) || 0;
144 var r = 0;
145 if (w && h) {
146 r = w / h;
147 } else {
148 var vb = parseViewBox(this.config.svgViewBoxAttr);
149 if (vb) {
150 r = vb[2] / vb[3];
151 }
152 if (r) {
153 if (!w && h)
154 w = h * r;
155 else if (!h && w)
156 h = w / r;
157 }
158 }
159 return { width: w, height: h, ratio: r };
160 };
161
162
163 TestData.prototype.computeInlineReplacedSize = function() {
164 var intrinsic = this.intrinsicInformation();
165 var self = this;
166
167 // http://www.w3.org/TR/CSS2/visudet.html#inline-replaced-height
168 function calculateUsedHeight() {
169 if (self.computedHeightIsAuto()) {
170 if (self.computedWidthIsAuto() && intrinsic.height)
171 return intrinsic.height;
172 if (intrinsic.ratio)
173 return calculateUsedWidth() / intrinsic.ratio;
174 if (intrinsic.height)
175 return intrinsic.height;
176 return 150;
177 }
178
179 return convertToPx(self.style["height"],
180 convertToPx(self.config.containerHeightStyle,
181 self.outerHeight));
182 }
183
184 // http://www.w3.org/TR/CSS2/visudet.html#inline-replaced-width
185 function calculateUsedWidth() {
186 if (self.computedWidthIsAuto()) {
187 if (self.computedHeightIsAuto() && intrinsic.width)
188 return intrinsic.width;
189 if (!self.computedHeightIsAuto() && intrinsic.ratio)
190 return calculateUsedHeight() * intrinsic.ratio;
191 if (self.computedHeightIsAuto() && intrinsic.ratio) {
192 if (self.containerComputedWidthIsAuto()) {
193 // Note: While this is actually undefined in CSS
194 // 2.1, use the suggested value by examining the
195 // ancestor widths.
196 return self.outerWidth;
197 } else {
198 return convertToPx(self.config.containerWidthStyle,
199 self.outerWidth);
200 }
201 }
202 if (intrinsic.width)
203 return intrinsic.width;
204 return 300;
205 }
206
207 if (self.containerComputedWidthIsAuto())
208 return convertToPx(self.style["width"], self.outerWidth);
209 else
210 return convertToPx(self.style["width"],
211 convertToPx(self.config.containerWidthStyle,
212 self.outerWidth));
213 }
214 return { width: calculateUsedWidth(),
215 height: calculateUsedHeight() };
216 };
217
218 var testContainer = document.querySelector('#testContainer');
219 TestData.prototype.outerWidth = testContainer.getBoundingClientRect().width;
220 TestData.prototype.outerHeight = testContainer.getBoundingClientRect().heigh t;
221
222 window.TestData = TestData;
223 })();
224
225 function setupContainer(testData, svgElement, options) {
226 options = options || {};
227
228 var container = document.createElement("div");
229
230 container.id = "container";
231 if (testData.config.containerWidthStyle)
232 container.style.width = testData.config.containerWidthStyle;
233
234 if (testData.config.containerHeightStyle)
235 container.style.height = testData.config.containerHeightStyle;
236
237 if (options.pretty)
238 container.appendChild(document.createTextNode("\n\t\t"));
239 container.appendChild(svgElement);
240 if (options.pretty)
241 container.appendChild(document.createTextNode("\n\t"));
242
243 return container;
244 }
245
246 function setupSVGElement(testData) {
247 var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg ");
248 svgElement.setAttribute("id", "test");
249 if (testData.config.svgWidthStyle)
250 svgElement.style.width = testData.config.svgWidthStyle;
251 if (testData.config.svgHeightStyle)
252 svgElement.style.height = testData.config.svgHeightStyle;
253 if (testData.config.svgWidthAttr)
254 svgElement.setAttribute("width", testData.config.svgWidthAttr);
255 if (testData.config.svgHeightAttr)
256 svgElement.setAttribute("height", testData.config.svgHeightAttr);
257 if (testData.config.svgViewBoxAttr)
258 svgElement.setAttribute("viewBox", testData.config.svgViewBoxAttr);
259
260 return svgElement;
261 }
262
263 function buildDemo(testData) {
264 // Non-essential debugging tool
265
266 var options = { pretty: true };
267 var expectedRect =
268 testData.computeInlineReplacedSize();
269 var container =
270 setupContainer(testData, setupSVGElement(testData), options);
271
272 var root = document.createElement("html");
273 var style = document.createElement("style");
274
275 style.textContent = "\n" +
276 "\tbody { margin: 0; font-family: sans-serif }\n" +
277 "\t#expected {\n" +
278 "\t\twidth: " + (expectedRect.width) + "px; height: "
279 + (expectedRect.height) + "px;\n" +
280 "\t\tborder: 10px solid lime; position: absolute;\n" +
281 "\t\tbackground-color: red }\n" +
282 "\t#testContainer { position: absolute;\n" +
283 "\t\ttop: 10px; left: 10px; width: 800px; height: 600px }\n" +
284 "\tsvg { background-color: green }\n" +
285 "\t.result { position: absolute; top: 0; right: 0;\n" +
286 "\t\tbackground-color: hsla(0,0%, 0%, 0.85); border-radius: 0.5em;\n" +
287 "\t\tpadding: 0.5em; border: 0.25em solid black }\n" +
288 "\t.pass { color: lime }\n" +
289 "\t.fail { color: red }\n";
290
291 root.appendChild(document.createTextNode("\n"));
292 root.appendChild(style);
293 root.appendChild(document.createTextNode("\n"));
294
295 var script = document.createElement("script");
296 script.textContent = "\n" +
297 "onload = function() {\n" +
298 "\tvar svgRect = \n" +
299 "\t\tdocument.querySelector('#test').getBoundingClientRect();\n" +
300 "\tpassed = (svgRect.width == " + expectedRect.width + " && " +
301 "svgRect.height == " + expectedRect.height + ");\n" +
302 "\tdocument.body.insertAdjacentHTML('beforeEnd',\n" +
303 "\t\t'<span class=\"result '+ (passed ? 'pass' : 'fail') " +
304 "+ '\">' + (passed ? 'Pass' : 'Fail') + '</span>');\n" +
305 "};\n";
306
307 root.appendChild(script);
308 root.appendChild(document.createTextNode("\n"));
309
310 var expectedElement = document.createElement("div");
311 expectedElement.id = "expected";
312 root.appendChild(expectedElement);
313 root.appendChild(document.createTextNode("\n"));
314
315 var testContainer = document.createElement("div");
316 testContainer.id = "testContainer";
317 testContainer.appendChild(document.createTextNode("\n\t"));
318 testContainer.appendChild(container);
319 testContainer.appendChild(document.createTextNode("\n"));
320 root.appendChild(testContainer);
321 root.appendChild(document.createTextNode("\n"));
322
323 return "<!DOCTYPE html>\n" + root.outerHTML;
324 }
325
326 function doCombinationTest(values, func)
327 {
328 // Recursively construct all possible combinations of values and
329 // send them to |func|. Example:
330 //
331 // values: [["X", ["a", "b"]],
332 // ["Y", ["c", "d"]]]
333 //
334 // generates the objects:
335 //
336 // 1: { "X": "a", "Y": "c" }
337 // 2: { "X": "a", "Y": "d" }
338 // 3: { "X": "b", "Y": "c" }
339 // 4: { "X": "b", "Y": "d" }
340 //
341 // and each will be sent to |func| with the corresponding prefixed
342 // id (modulo order).
343
344 var combinationId = 1;
345 function doCombinationTestRecursive(slicedValues, config) {
346 if (slicedValues.length > 0) {
347 var configKey = slicedValues[0][0];
348 slicedValues[0][1].forEach(function(configValue) {
349 var new_config = {};
350 for (k in config)
351 new_config[k] = config[k];
352 new_config[configKey] = configValue;
353 doCombinationTestRecursive(slicedValues.slice(1), new_config);
354 });
355 } else {
356 func(config, combinationId++);
357 }
358 }
359 doCombinationTestRecursive(values, {});
360 }
361
362 var debugHint = function(id) { return "(append ?"+id+" to debug) " };
363 var testSingleId;
364 if (window.location.search) {
365 testSingleId = window.location.search.substring(1);
366 debugHint = function(id) { return ""; };
367 }
368
369 doCombinationTest(
Erik Dahlström (inactive) 2014/04/15 09:37:43 shouldn't there be tests for explicit 'auto' and '
davve 2014/04/15 15:55:23 For 'auto', I'd rather only add combinations that
370 [["containerWidthStyle", [null, "400px"]],
371 ["containerHeightStyle", [null, "400px"]],
372 ["svgViewBoxAttr", [ null, "0 0 100 200" ]],
373 ["svgWidthStyle", [ null, "100px", "50%" ]],
374 ["svgHeightStyle", [ null, "100px", "50%" ]],
375 ["svgWidthAttr", [ null, "200", "25%" ]],
376 ["svgHeightAttr", [ null, "200", "25%" ]]],
377 function(config, id) {
378 if (!testSingleId || testSingleId == id) {
379 var testData = new TestData(config);
380
381 var expectedRect =
382 testData.computeInlineReplacedSize();
383 var svgElement = setupSVGElement(testData);
384 var container =
385 setupContainer(testData, svgElement);
386
387 var checkSize = function() {
388 var svgRect =
389 svgElement.getBoundingClientRect();
390
391 try {
392 assert_equals(svgRect.width,
393 expectedRect.width,
394 debugHint(id) + "Wrong width");
395 assert_equals(svgRect.height,
396 expectedRect.height,
397 debugHint(id) + "Wrong height");
398 } finally {
399 testContainer.removeChild(container);
400 if (testSingleId)
401 document.body.removeChild(testContainer);
402 }
403 };
404
405 testContainer.appendChild(container);
406 test(checkSize, testData.name);
407 }
408
409 if (testSingleId == id) {
410 var pad = function(n, width, z) {
411 z = z || '0';
412 n = n + '';
413 return n.length >= width ? n : new Array(width - n.length + 1).j oin(z) + n;
414 };
415
416 var demo = buildDemo(testData);
417 var iframe = document.createElement('iframe');
418 iframe.style.width = (Math.max(900, expectedRect.width)) + "px";
419 iframe.style.height = (Math.max(400, expectedRect.height)) + "px";
420 iframe.src = "data:text/html;charset=utf-8," + encodeURIComponent(de mo);
421 document.body.appendChild(iframe);
422
423 document.body.insertAdjacentHTML(
424 'beforeEnd',
425 '<p><a href="data:application/octet-stream;charset=utf-8;base64, ' +
426 btoa(demo) + '" download="svg-in-object-test-' + pad(id, 3) + '.html">Download</a></p>');
427 }
428 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698