function-attr.html (6394B)
1 <!DOCTYPE html> 2 <title>Custom Functions: attr(), url(), tainting</title> 3 <link rel="help" href="https://drafts.csswg.org/css-mixins-1/#using-custom-functions"> 4 <link rel="help" href="https://drafts.csswg.org/css-values-5/#attr-security"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="resources/utils.js"></script> 8 9 <style> 10 #parent { 11 list-style-image: url(parent); 12 } 13 </style> 14 <div id=parent> 15 <div id=actual data-42="42px" data-cat="url(cat.png)"></div> 16 <div id=expected></div> 17 </div> 18 <main id=main></main> 19 20 <!-- 21 Each <template> represents a test, and is executed by comparing the computed 22 values of #actual and #expected. 23 --> 24 <script> 25 // Only these properties are actually compared. 26 let relevant_properties = ['list-style-image', 'width']; 27 </script> 28 29 <template data-name="Return untyped url() from function"> 30 <style> 31 @function --f() { 32 result: url(img.png); 33 } 34 #actual { list-style-image: --f(); } 35 #expected { list-style-image: url(img.png); } 36 </style> 37 </template> 38 39 <template data-name="Return untyped url() from function, quoted"> 40 <style> 41 @function --f() { 42 result: url("img.png"); 43 } 44 #actual { list-style-image: --f(); } 45 #expected { list-style-image: url("img.png"); } 46 </style> 47 </template> 48 49 <template data-name="Return typed url() from function"> 50 <style> 51 @function --f() returns <url> { 52 result: url(img.png); 53 } 54 #actual { list-style-image: --f(); } 55 #expected { list-style-image: url(img.png); } 56 </style> 57 </template> 58 59 <template data-name="Return typed url() from function, quoted"> 60 <style> 61 @function --f() returns <url> { 62 result: url("img.png"); 63 } 64 #actual { list-style-image: --f(); } 65 #expected { list-style-image: url("img.png"); } 66 </style> 67 </template> 68 69 <!-- Permitted uses of attr() --> 70 71 <template data-name="Return attr(type(<length>)) from untyped function"> 72 <style> 73 @function --f() { 74 result: attr(data-42 type(<length>)); 75 } 76 #actual { width: --f(); } 77 #expected { width: 42px; } 78 </style> 79 </template> 80 81 <template data-name="Return attr(type(<length>)) from typed function"> 82 <style> 83 @function --f() returns <length> { 84 result: attr(data-42 type(<length>)); 85 } 86 #actual { width: --f(); } 87 #expected { width: 42px; } 88 </style> 89 </template> 90 91 <template data-name="Return attr(type(*)) from typed function"> 92 <style> 93 @function --f() returns <length> { 94 result: attr(data-42 type(*)); 95 } 96 #actual { width: --f(); } 97 #expected { width: 42px; } 98 </style> 99 </template> 100 101 <template data-name="Return attr(type(*)) from untyped function"> 102 <style> 103 @function --f() { 104 result: attr(data-42 type(*)); 105 } 106 #actual { width: --f(); } 107 #expected { width: 42px; } 108 </style> 109 </template> 110 111 <template data-name="attr() in default parameter value"> 112 <style> 113 @function --f(--a : attr(data-42 type(*))) { 114 result: var(--a); 115 } 116 #actual { width: --f(); } 117 #expected { width: 42px; } 118 </style> 119 </template> 120 121 <template data-name="attr() in local variable"> 122 <style> 123 @function --f() { 124 --l: attr(data-42 type(*)); 125 result: var(--l); 126 } 127 #actual { width: --f(); } 128 #expected { width: 42px; } 129 </style> 130 </template> 131 132 <!-- Invalid uses of attr() --> 133 134 <template data-name="Returned url() is attr-tainted"> 135 <style> 136 @function --f() { 137 result: attr(data-cat type(*)); 138 } 139 #actual { list-style-image: --f(); } 140 #expected { list-style-image: url(parent); } 141 </style> 142 </template> 143 144 <template data-name="Returned url() is attr-tainted, typed attr()"> 145 <style> 146 @function --f() { 147 result: attr(data-cat type(<url>)); 148 } 149 #actual { list-style-image: --f(); } 150 #expected { list-style-image: url(parent); } 151 </style> 152 </template> 153 154 <template data-name="Returned url() is attr-tainted, typed return"> 155 <style> 156 @function --f() returns <url> { 157 result: attr(data-cat type(*)); 158 } 159 #actual { list-style-image: --f(); } 160 #expected { list-style-image: url(parent); } 161 </style> 162 </template> 163 164 <template data-name="Returned url() is attr-tainted, local"> 165 <style> 166 @function --f() returns <url> { 167 --local: attr(data-cat type(*)); 168 result: var(--local); 169 } 170 #actual { list-style-image: --f(); } 171 #expected { list-style-image: url(parent); } 172 </style> 173 </template> 174 175 <template data-name="Returned url() is attr-tainted, argument"> 176 <style> 177 @function --f(--arg) returns <url> { 178 result: var(--arg); 179 } 180 #actual { list-style-image: --f(attr(data-cat type(*))); } 181 #expected { list-style-image: url(parent); } 182 </style> 183 </template> 184 185 <template data-name="Returned url() is attr-tainted, default"> 186 <style> 187 @function --f(--arg: attr(data-cat type(*))) { 188 result: var(--arg); 189 } 190 #actual { list-style-image: --f(); } 191 #expected { list-style-image: url(parent); } 192 </style> 193 </template> 194 195 <template data-name="Returned url() is attr-tainted, parent stack frame"> 196 <style> 197 @function --f() { 198 --x: attr(data-cat type(*)); 199 result: --g(); 200 } 201 @function --g() { 202 result: var(--x); 203 } 204 #actual { list-style-image: --f(); } 205 #expected { list-style-image: url(parent); } 206 </style> 207 </template> 208 209 <template data-name="Returned url() is attr-tainted, initial"> 210 <style> 211 @function --f(--x: attr(data-cat type(*))) { 212 --x: initial; 213 result: --g(); 214 } 215 #actual { list-style-image: --f(); } 216 #expected { list-style-image: url(parent); } 217 </style> 218 </template> 219 220 <template data-name="Returned url() is attr-tainted, inherit"> 221 <style> 222 @function --f() { 223 --x: attr(data-cat type(*)); 224 result: --g(); 225 } 226 @function --g() { 227 --x: inherit; 228 result: var(--x); 229 } 230 #actual { list-style-image: --f(); } 231 #expected { list-style-image: url(parent); } 232 </style> 233 </template> 234 235 <script> 236 let templates = document.querySelectorAll('template'); 237 for (let template of templates) { 238 test((t) => { 239 t.add_cleanup(() => main.replaceChildren()); 240 main.append(template.content.cloneNode(true)); 241 for (let p of relevant_properties) { 242 assert_equals(getComputedStyle(actual).getPropertyValue(p), 243 getComputedStyle(expected).getPropertyValue(p)); 244 } 245 }, template.getAttribute('data-name')); 246 } 247 </script>