diff options
Diffstat (limited to 'testing/web-platform/tests/html/rendering/replaced-elements/resources')
-rw-r--r-- | testing/web-platform/tests/html/rendering/replaced-elements/resources/svg-sizing.js | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/rendering/replaced-elements/resources/svg-sizing.js b/testing/web-platform/tests/html/rendering/replaced-elements/resources/svg-sizing.js new file mode 100644 index 0000000000..c212c6b283 --- /dev/null +++ b/testing/web-platform/tests/html/rendering/replaced-elements/resources/svg-sizing.js @@ -0,0 +1,418 @@ +// Simple implementation of SVG sizing + +setup({explicit_done: true}); + +var SVGSizing = (function() { + function parseLength(l) { + var match = /^([-+]?[0-9]+|[-+]?[0-9]*\.[0-9]+)(px|%)?$/.exec(l); + if (!match) + return null; + return new Length(Number(match[1]), match[2] ? match[2] : "px"); + } + + function parseViewBox(input) { + if (!input) + return null; + + var arr = input.split(' '); + return arr.map(function(a) { return parseInt(a); }); + } + + // Only px and % are used + function convertToPx(input, percentRef) { + if (input == null) + return null; + var length = parseLength(input); + if (length.amount == 0) + return 0; + if (!length.unit) + length.unit = "px"; + if (length.unit == "%" && percentRef === undefined) + return null; + return length.amount * { px: 1, + "%": percentRef/100}[length.unit]; + } + + function Length(amount, unit) { + this.amount = amount; + this.unit = unit; + } + + function describe(data) { + function dumpObject(obj) { + var r = ""; + for (var property in obj) { + if (obj.hasOwnProperty(property)) { + var value = obj[property]; + if (typeof value == 'string') + value = "'" + value + "'"; + else if (value == null) + value = "null"; + else if (typeof value == 'object') + { + if (value instanceof Array) + value = "[" + value + "]"; + else + value = "{" + dumpObject(value) + "}"; + } + + if (value != "null") + r += property + ": " + value + ", "; + } + } + return r; + } + var result = dumpObject(data); + if (result == "") + return "(initial values)"; + return result; + } + + function mapPresentationalHintLength(testData, cssProperty, attr) { + if (attr) { + var l = parseLength(attr); + if (l) + testData.style[cssProperty] = l.amount + l.unit; + } + } + + function computedWidthIsAuto(testData) { + return !testData.style["width"] || testData.style["width"] == 'auto'; + } + + function computedHeightIsAuto(testData) { + return !testData.style["height"] || testData.style["height"] == 'auto' || + (parseLength(testData.style["height"]).unit == '%' && + containerComputedHeightIsAuto(testData)); + } + + function containerComputedWidthIsAuto(testData) { + return !testData.config.containerWidthStyle || + testData.config.containerWidthStyle == 'auto'; + } + + function containerComputedHeightIsAuto(testData) { + return !testData.config.containerHeightStyle || + testData.config.containerHeightStyle == 'auto'; + } + + function intrinsicInformation(testData) { + if (testData.config.placeholder == 'iframe') + return {}; + + var w = convertToPx(testData.config.svgWidthAttr) || 0; + var h = convertToPx(testData.config.svgHeightAttr) || 0; + var r = 0; + if (w && h) { + r = w / h; + } else { + var vb = parseViewBox(testData.config.svgViewBoxAttr); + if (vb) { + r = vb[2] / vb[3]; + } + if (r) { + if (!w && h) + w = h * r; + else if (!h && w) + h = w / r; + } + } + return { width: w, height: h, ratio: r }; + }; + + function contentAttributeForPlaceholder(testData) { + if (testData.config.placeholder == 'object') + return "data"; + else + return "src"; + } + + function TestData(config) { + this.config = config; + this.name = describe(config); + this.style = {}; + if (config.placeholder) { + mapPresentationalHintLength(this, "width", config.placeholderWidthAttr); + mapPresentationalHintLength(this, "height", config.placeholderHeightAttr); + } else { + if (config.svgWidthStyle) + this.style["width"] = config.svgWidthStyle; + else + mapPresentationalHintLength(this, "width", config.svgWidthAttr); + + if (config.svgHeightStyle) + this.style["height"] = config.svgHeightStyle; + else + mapPresentationalHintLength(this, "height", config.svgHeightAttr); + } + } + + TestData.prototype.computeInlineReplacedSize = function(outerWidth, outerHeight) { + var intrinsic = intrinsicInformation(this); + var self = this; + + // http://www.w3.org/TR/CSS2/visudet.html#inline-replaced-height + function calculateUsedHeight() { + if (computedHeightIsAuto(self)) { + if (computedWidthIsAuto(self) && intrinsic.height) + return intrinsic.height; + if (intrinsic.ratio) + return calculateUsedWidth() / intrinsic.ratio; + if (intrinsic.height) + return intrinsic.height; + return 150; + } + + return convertToPx(self.style["height"], + convertToPx(self.config.containerHeightStyle, + outerHeight)); + } + + // http://www.w3.org/TR/CSS2/visudet.html#inline-replaced-width + function calculateUsedWidth() { + if (computedWidthIsAuto(self)) { + if (computedHeightIsAuto(self) && intrinsic.width) + return intrinsic.width; + if (!computedHeightIsAuto(self) && intrinsic.ratio) + return calculateUsedHeight() * intrinsic.ratio; + if (computedHeightIsAuto(self) && intrinsic.ratio) { + if (containerComputedWidthIsAuto(self)) { + // Note: While this is actually undefined in CSS + // 2.1, use the suggested value by examining the + // ancestor widths. + return outerWidth; + } else { + return convertToPx(self.config.containerWidthStyle, + outerWidth); + } + } + if (intrinsic.width) + return intrinsic.width; + return 300; + } + + if (containerComputedWidthIsAuto(self)) + return convertToPx(self.style["width"], outerWidth); + else + return convertToPx(self.style["width"], + convertToPx(self.config.containerWidthStyle, + outerWidth)); + } + return { width: calculateUsedWidth(), + height: calculateUsedHeight() }; + }; + + TestData.prototype.buildContainer = function (placeholder, options) { + options = options || {}; + + var container = document.createElement("div"); + + container.id = "container"; + if (this.config.containerWidthStyle) + container.style.width = this.config.containerWidthStyle; + + if (this.config.containerHeightStyle) + container.style.height = this.config.containerHeightStyle; + + if (options.pretty) + container.appendChild(document.createTextNode("\n\t\t")); + container.appendChild(placeholder); + if (options.pretty) + container.appendChild(document.createTextNode("\n\t")); + + return container; + }; + + TestData.prototype.buildSVGOrPlaceholder = function (options) { + options = options || {}; + var self = this; + + if (this.config.placeholder) { + var generateSVGURI = function(testData, encoder) { + var res = '<svg xmlns="http://www.w3.org/2000/svg"'; + function addAttr(attr, prop) { + if (testData.config[prop]) + res += ' ' + attr + '="' + testData.config[prop] + '"'; + } + addAttr("width", "svgWidthAttr"); + addAttr("height", "svgHeightAttr"); + addAttr("viewBox", "svgViewBoxAttr"); + res += '></svg>'; + return 'data:image/svg+xml' + encoder(res); + }; + var placeholder = document.createElement(this.config.placeholder); + if (options.pretty) { + placeholder.appendChild(document.createTextNode("\n\t\t\t")); + placeholder.appendChild( + document.createComment( + generateSVGURI(this, function(x) { return "," + x; }))); + placeholder.appendChild(document.createTextNode("\n\t\t")); + } + placeholder.setAttribute("id", "test"); + if (this.config.placeholderWidthAttr) + placeholder.setAttribute("width", this.config.placeholderWidthAttr); + if (this.config.placeholderHeightAttr) + placeholder.setAttribute("height", this.config.placeholderHeightAttr); + placeholder.setAttribute(contentAttributeForPlaceholder(this), + generateSVGURI(this, function(x) { + return ";base64," + btoa(x); + })); + return placeholder; + } else { + var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svgElement.setAttribute("id", "test"); + if (self.config.svgWidthStyle) + svgElement.style.width = self.config.svgWidthStyle; + if (self.config.svgHeightStyle) + svgElement.style.height = self.config.svgHeightStyle; + if (self.config.svgWidthAttr) + svgElement.setAttribute("width", self.config.svgWidthAttr); + if (self.config.svgHeightAttr) + svgElement.setAttribute("height", self.config.svgHeightAttr); + if (self.config.svgViewBoxAttr) + svgElement.setAttribute("viewBox", self.config.svgViewBoxAttr); + return svgElement; + } + }; + + TestData.prototype.buildDemo = function (expectedRect, id) { + // Non-essential debugging tool + var self = this; + + function buildDemoSerialization() { + var outerWidth = 800; + var outerHeight = 600; + + var options = { pretty: true }; + var container = + self.buildContainer(self.buildSVGOrPlaceholder(options), options); + + var root = document.createElement("html"); + var style = document.createElement("style"); + + style.textContent = "\n" + + "\tbody { margin: 0; font-family: sans-serif }\n" + + "\tiframe { border: none }\n" + + "\t#expected {\n" + + "\t\twidth: " + (expectedRect.width) + "px; height: " + + (expectedRect.height) + "px;\n" + + "\t\tborder: 10px solid lime; position: absolute;\n" + + "\t\tbackground-color: red }\n" + + "\t#testContainer { position: absolute;\n" + + "\t\ttop: 10px; left: 10px; width: " + outerWidth + "px;\n" + + "\t\theight: " + outerHeight + "px }\n" + + "\t#test { background-color: green }\n" + + "\t.result { position: absolute; top: 0; right: 0;\n" + + "\t\tbackground-color: hsla(0,0%, 0%, 0.85); border-radius: 0.5em;\n" + + "\t\tpadding: 0.5em; border: 0.25em solid black }\n" + + "\t.pass { color: lime }\n" + + "\t.fail { color: red }\n"; + + root.appendChild(document.createTextNode("\n")); + root.appendChild(style); + root.appendChild(document.createTextNode("\n")); + + var script = document.createElement("script"); + script.textContent = "\n" + + "onload = function() {\n" + + "\tvar svgRect =\n" + + "\t\tdocument.querySelector('#test').getBoundingClientRect();\n" + + "\tpassed = (svgRect.width == " + expectedRect.width + " && " + + "svgRect.height == " + expectedRect.height + ");\n" + + "\tdocument.body.insertAdjacentHTML('beforeEnd',\n" + + "\t\t'<span class=\"result '+ (passed ? 'pass' : 'fail') " + + "+ '\">' + (passed ? 'Pass' : 'Fail') + '</span>');\n" + + "};\n"; + + root.appendChild(script); + root.appendChild(document.createTextNode("\n")); + + var expectedElement = document.createElement("div"); + expectedElement.id = "expected"; + root.appendChild(expectedElement); + root.appendChild(document.createTextNode("\n")); + + var testContainer = document.createElement("div"); + testContainer.id = "testContainer"; + testContainer.appendChild(document.createTextNode("\n\t")); + testContainer.appendChild(container); + testContainer.appendChild(document.createTextNode("\n")); + root.appendChild(testContainer); + root.appendChild(document.createTextNode("\n")); + + return "<!DOCTYPE html>\n" + root.outerHTML; + } + + function pad(n, width, z) { + z = z || '0'; + n = n + ''; + return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; + } + + function heightToDescription(height) { + if (!height || height == "auto") + return "auto"; + if (parseLength(height).unit == '%') + return "percentage"; + return "fixed"; + } + + var demoRoot = document.querySelector('#demo'); + if (demoRoot) { + var demo = buildDemoSerialization(); + var iframe = document.createElement('iframe'); + iframe.style.width = (Math.max(900, expectedRect.width)) + "px"; + iframe.style.height = (Math.max(400, expectedRect.height)) + "px"; + iframe.src = "data:text/html;charset=utf-8," + encodeURIComponent(demo); + demoRoot.appendChild(iframe); + demoRoot.insertAdjacentHTML( + 'beforeEnd', + '<p><a href="data:application/octet-stream;charset=utf-8;base64,' + + btoa(demo) + '" download="svg-in-' + this.config.placeholder + "-" + + heightToDescription(this.config.placeholderHeightAttr) + "-" + pad(id, 3) + + '.html">Download</a></p>'); + } + }; + + return { + TestData: TestData, + doCombinationTest: function(values, func, testSingleId) { + function computeConfig(id) { + id--; + var multiplier = 1; + var config = {}; + for (var i=0; i<values.length; i++) { + // Compute offset into current array + var ii = (Math.floor(id / multiplier)) % values[i][1].length; + // Set corresponding value + config[values[i][0]] = values[i][1][ii]; + // Compute new multiplier + multiplier *= values[i][1].length; + } + if (id >= multiplier) + return null; + return config; + } + + function cont(id) { + var config = computeConfig(id); + if (config && (!testSingleId || testSingleId == id)) { + var next = function() {func(config, id, cont)}; + // Make sure we don't blow the stack, without too much slowness + if (id % 20 === 0) { + step_timeout(next, 0); + } else { + next(); + } + } else { + done(); + } + }; + + if (testSingleId) + cont(testSingleId); + else + cont(1); + } + }; +})(); |