| <!DOCTYPE html> | |
| <title>Custom Functions: attr(), url(), tainting</title> | |
| <link rel="help" href="https://drafts.csswg.org/css-mixins-1/#using-custom-functions"> | |
| <link rel="help" href="https://drafts.csswg.org/css-values-5/#attr-security"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src="resources/utils.js"></script> | |
| <style> | |
| #parent { | |
| list-style-image: url(parent); | |
| } | |
| </style> | |
| <div id=parent> | |
| <div id=actual data-42="42px" data-cat="url(cat.png)"></div> | |
| <div id=expected></div> | |
| </div> | |
| <main id=main></main> | |
| <!-- | |
| Each <template> represents a test, and is executed by comparing the computed | |
| values of #actual and #expected. | |
| --> | |
| <script> | |
| // Only these properties are actually compared. | |
| let relevant_properties = ['list-style-image', 'width']; | |
| </script> | |
| <template data-name="Return untyped url() from function"> | |
| <style> | |
| @function --f() { | |
| result: url(img.png); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(img.png); } | |
| </style> | |
| </template> | |
| <template data-name="Return untyped url() from function, quoted"> | |
| <style> | |
| @function --f() { | |
| result: url("img.png"); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url("img.png"); } | |
| </style> | |
| </template> | |
| <template data-name="Return typed url() from function"> | |
| <style> | |
| @function --f() returns <url> { | |
| result: url(img.png); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(img.png); } | |
| </style> | |
| </template> | |
| <template data-name="Return typed url() from function, quoted"> | |
| <style> | |
| @function --f() returns <url> { | |
| result: url("img.png"); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url("img.png"); } | |
| </style> | |
| </template> | |
| <!-- Permitted uses of attr() --> | |
| <template data-name="Return attr(type(<length>)) from untyped function"> | |
| <style> | |
| @function --f() { | |
| result: attr(data-42 type(<length>)); | |
| } | |
| #actual { width: --f(); } | |
| #expected { width: 42px; } | |
| </style> | |
| </template> | |
| <template data-name="Return attr(type(<length>)) from typed function"> | |
| <style> | |
| @function --f() returns <length> { | |
| result: attr(data-42 type(<length>)); | |
| } | |
| #actual { width: --f(); } | |
| #expected { width: 42px; } | |
| </style> | |
| </template> | |
| <template data-name="Return attr(type(*)) from typed function"> | |
| <style> | |
| @function --f() returns <length> { | |
| result: attr(data-42 type(*)); | |
| } | |
| #actual { width: --f(); } | |
| #expected { width: 42px; } | |
| </style> | |
| </template> | |
| <template data-name="Return attr(type(*)) from untyped function"> | |
| <style> | |
| @function --f() { | |
| result: attr(data-42 type(*)); | |
| } | |
| #actual { width: --f(); } | |
| #expected { width: 42px; } | |
| </style> | |
| </template> | |
| <template data-name="attr() in default parameter value"> | |
| <style> | |
| @function --f(--a : attr(data-42 type(*))) { | |
| result: var(--a); | |
| } | |
| #actual { width: --f(); } | |
| #expected { width: 42px; } | |
| </style> | |
| </template> | |
| <template data-name="attr() in local variable"> | |
| <style> | |
| @function --f() { | |
| --l: attr(data-42 type(*)); | |
| result: var(--l); | |
| } | |
| #actual { width: --f(); } | |
| #expected { width: 42px; } | |
| </style> | |
| </template> | |
| <!-- Invalid uses of attr() --> | |
| <template data-name="Returned url() is attr-tainted"> | |
| <style> | |
| @function --f() { | |
| result: attr(data-cat type(*)); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, typed attr()"> | |
| <style> | |
| @function --f() { | |
| result: attr(data-cat type(<url>)); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, typed return"> | |
| <style> | |
| @function --f() returns <url> { | |
| result: attr(data-cat type(*)); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, local"> | |
| <style> | |
| @function --f() returns <url> { | |
| --local: attr(data-cat type(*)); | |
| result: var(--local); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, argument"> | |
| <style> | |
| @function --f(--arg) returns <url> { | |
| result: var(--arg); | |
| } | |
| #actual { list-style-image: --f(attr(data-cat type(*))); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, default"> | |
| <style> | |
| @function --f(--arg: attr(data-cat type(*))) { | |
| result: var(--arg); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, parent stack frame"> | |
| <style> | |
| @function --f() { | |
| --x: attr(data-cat type(*)); | |
| result: --g(); | |
| } | |
| @function --g() { | |
| result: var(--x); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, initial"> | |
| <style> | |
| @function --f(--x: attr(data-cat type(*))) { | |
| --x: initial; | |
| result: --g(); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <template data-name="Returned url() is attr-tainted, inherit"> | |
| <style> | |
| @function --f() { | |
| --x: attr(data-cat type(*)); | |
| result: --g(); | |
| } | |
| @function --g() { | |
| --x: inherit; | |
| result: var(--x); | |
| } | |
| #actual { list-style-image: --f(); } | |
| #expected { list-style-image: url(parent); } | |
| </style> | |
| </template> | |
| <script> | |
| let templates = document.querySelectorAll('template'); | |
| for (let template of templates) { | |
| test((t) => { | |
| t.add_cleanup(() => main.replaceChildren()); | |
| main.append(template.content.cloneNode(true)); | |
| for (let p of relevant_properties) { | |
| assert_equals(getComputedStyle(actual).getPropertyValue(p), | |
| getComputedStyle(expected).getPropertyValue(p)); | |
| } | |
| }, template.getAttribute('data-name')); | |
| } | |
| </script> |