feature-detection.js (10765B)
1 // This is a helper for MathML feature detection. 2 // It is indented to be used to prevent false negative test results. 3 4 var MathMLFeatureDetection = { 5 6 "has_annotation": function() { 7 // FIXME: Improve feature detection. 8 return this.has_mspace(); 9 }, 10 11 "has_annotation-xml": function() { 12 // FIXME: Improve feature detection. 13 return this.has_mspace(); 14 }, 15 16 "has_maction": function() { 17 // FIXME: Improve feature detection. 18 return this.has_mspace(); 19 }, 20 21 "has_math": function() { 22 // FIXME: Improve feature detection. 23 return this.has_mspace(); 24 }, 25 26 "has_menclose": function() { 27 // Just check whether <mrow> is supported because discussion on this is 28 // still open ( https://github.com/mathml-refresh/mathml/issues/105 ) 29 // and it would have to behave at least like an mrow, even if it becomes 30 // an unknown element at the end. 31 return this.has_mrow(); 32 }, 33 34 "has_merror": function() { 35 // FIXME: Improve feature detection. 36 return this.has_mspace(); 37 }, 38 39 "has_mfrac": function() { 40 if (!this.hasOwnProperty("_has_mfrac")) { 41 // Use tall enough fraction to avoid side effect of min num/denum shifts. 42 document.body.insertAdjacentHTML("beforeend", "<math>\ 43 <mfrac>\ 44 <mspace height='50px' depth='50px'></mspace>\ 45 <mspace height='50px' depth='50px'></mspace>\ 46 </mfrac>\ 47 <mfrac>\ 48 <mspace height='60px' depth='60px'></mspace>\ 49 <mspace height='60px' depth='60px'></mspace>\ 50 </mfrac>\ 51 </math>"); 52 var math = document.body.lastElementChild; 53 var mfrac = math.getElementsByTagName("mfrac"); 54 // height/depth will add 40px per MathML, 20px if mfrac does not stack its children and none if mspace is not supported. 55 this._has_mfrac = 56 mfrac[1].getBoundingClientRect().height - 57 mfrac[0].getBoundingClientRect().height > 30; 58 document.body.removeChild(math); 59 } 60 return this._has_mfrac; 61 }, 62 63 "has_mi": function() { 64 // FIXME: Improve feature detection. 65 return this.has_mspace(); 66 }, 67 68 "has_mmultiscripts": function() { 69 // FIXME: Improve feature detection. 70 return this.has_mspace(); 71 }, 72 73 "has_mn": function() { 74 // FIXME: Improve feature detection. 75 return this.has_mspace(); 76 }, 77 78 "has_mo": function() { 79 // FIXME: Improve feature detection. 80 return this.has_mspace(); 81 }, 82 83 "has_mover": function() { 84 // FIXME: Improve feature detection. 85 return this.has_munderover(); 86 }, 87 88 "has_mpadded": function() { 89 // FIXME: Improve feature detection. 90 return this.has_mspace(); 91 }, 92 93 "has_mphantom": function() { 94 // FIXME: Improve feature detection. 95 return this.has_mspace(); 96 }, 97 98 "has_mprescripts": function() { 99 // FIXME: Improve feature detection. 100 return this.has_mspace(); 101 }, 102 103 "has_mroot": function() { 104 // FIXME: Improve feature detection. 105 return this.has_msqrt(); 106 }, 107 108 "has_mrow": function() { 109 // FIXME: Improve feature detection. 110 return this.has_mspace(); 111 }, 112 113 "has_ms": function() { 114 // FIXME: Improve feature detection. 115 return this.has_mspace(); 116 }, 117 118 "has_mspace": function() { 119 // https://w3c.github.io/mathml-core/#space-mspace 120 if (!this.hasOwnProperty("_has_mspace")) { 121 document.body.insertAdjacentHTML("beforeend", "<math>\ 122 <mspace></mspace>\ 123 <mspace width='20px'></mspace>\ 124 </math>"); 125 var math = document.body.lastElementChild; 126 // The width attribute will add 20px per MathML and none if not supported. 127 this._has_mspace = 128 math.lastChild.getBoundingClientRect().width - 129 math.firstChild.getBoundingClientRect().width > 10; 130 document.body.removeChild(math); 131 } 132 return this._has_mspace; 133 }, 134 135 "has_msqrt": function() { 136 if (!this.hasOwnProperty("_has_msqrt")) { 137 document.body.insertAdjacentHTML("beforeend", "<math>\ 138 <mrow style='font-size: 20px !important'>\ 139 <mtext>A</mtext>\ 140 </mrow>\ 141 <msqrt style='font-size: 20px !important'>\ 142 <mtext>A</mtext>\ 143 </msqrt>\ 144 </math>"); 145 var math = document.body.lastElementChild; 146 // The radical symbol will make msqrt wider than mrow, if the former is supported. 147 this._has_msqrt = 148 math.lastElementChild.getBoundingClientRect().width - 149 math.firstElementChild.getBoundingClientRect().width > 5; 150 document.body.removeChild(math); 151 } 152 return this._has_msqrt; 153 }, 154 155 "has_mstyle": function() { 156 // FIXME: Improve feature detection. 157 return this.has_mspace(); 158 }, 159 160 "has_msub": function() { 161 // FIXME: Improve feature detection. 162 return this.has_mspace(); 163 }, 164 165 "has_msubsup": function() { 166 // FIXME: Improve feature detection. 167 return this.has_mspace(); 168 }, 169 170 "has_msup": function() { 171 // FIXME: Improve feature detection. 172 return this.has_mspace(); 173 }, 174 175 "has_mtable": function() { 176 // FIXME: Improve feature detection. 177 return this.has_mspace(); 178 }, 179 180 "has_mtd": function() { 181 // FIXME: Improve feature detection. 182 return this.has_mspace(); 183 }, 184 185 "has_mtext": function() { 186 // FIXME: Improve feature detection. 187 return this.has_mspace(); 188 }, 189 190 "has_mtr": function() { 191 // FIXME: Improve feature detection. 192 return this.has_mspace(); 193 }, 194 195 "has_munder": function() { 196 // FIXME: Improve feature detection. 197 return this.has_munderover(); 198 }, 199 200 "has_munderover": function() { 201 if (!this.hasOwnProperty("_has_munderover")) { 202 document.body.insertAdjacentHTML("beforeend", "<math>\ 203 <munderover>\ 204 <mspace width='20px'></mspace>\ 205 <mspace width='20px'></mspace>\ 206 <mspace width='20px'></mspace>\ 207 </munderover>\ 208 <munderover>\ 209 <mspace width='40px'></mspace>\ 210 <mspace width='40px'></mspace>\ 211 <mspace width='40px'></mspace>\ 212 </munderover>\ 213 </math>"); 214 var math = document.body.lastElementChild; 215 var munderover = math.getElementsByTagName("munderover"); 216 // width_delta will be 20px per MathML, 3 * 20 = 60px if mundeover does not stack its children and 0px if mspace is not supported. 217 var width_delta = 218 munderover[1].getBoundingClientRect().width - 219 munderover[0].getBoundingClientRect().width; 220 this._has_munderover = width_delta > 10 && width_delta < 30; 221 document.body.removeChild(math); 222 } 223 return this._has_munderover; 224 }, 225 226 "has_none": function() { 227 // FIXME: Improve feature detection. 228 return this.has_mspace(); 229 }, 230 231 "has_semantics": function() { 232 // FIXME: Improve feature detection. 233 return this.has_mspace(); 234 }, 235 236 "has_dir": function() { 237 if (!this.hasOwnProperty("_has_dir")) { 238 document.body.insertAdjacentHTML("beforeend", "<math style='direction: ltr !important;'>\ 239 <mtext dir='rtl'></mtext>\ 240 </math>"); 241 var math = document.body.lastElementChild; 242 this._has_dir = 243 window.getComputedStyle(math.firstElementChild). 244 getPropertyValue('direction') === 'rtl'; 245 document.body.removeChild(math); 246 } 247 return this._has_dir; 248 }, 249 250 "has_mathsize": function() { 251 if (!this.hasOwnProperty("_has_mathsize")) { 252 document.body.insertAdjacentHTML("beforeend", "<math style='font-size: 64px !important;'>\ 253 <mtext mathsize='32px'></mtext>\ 254 </math>"); 255 var math = document.body.lastElementChild; 256 this._has_mathsize = 257 window.getComputedStyle(math.firstElementChild). 258 getPropertyValue('font-size') === '32px'; 259 document.body.removeChild(math); 260 } 261 return this._has_mathsize; 262 }, 263 264 "has_movablelimits": function() { 265 if (!this.hasOwnProperty("_has_movablelimits")) { 266 document.body.insertAdjacentHTML("beforeend", "<math>\ 267 <munder>\ 268 <mo style='font-size: 30px !important' movablelimits='false'>A</mo>\ 269 <mspace width='100px'></mspace>\ 270 </munder>\ 271 <munder>\ 272 <mo style='font-size: 30px !important' movablelimits='true'>A</mo>\ 273 <mspace width='100px'></mspace>\ 274 </munder>\ 275 </math>"); 276 var math = document.body.lastElementChild; 277 var munder = math.getElementsByTagName("munder"); 278 // If movablelimits is supported, the <mspace> will be placed next 279 // to <mo> rather than below it, so width_delta is about the width 280 // of the <mo>. 281 var width_delta = 282 munder[1].getBoundingClientRect().width - 283 munder[0].getBoundingClientRect().width; 284 this._has_movablelimits = this.has_munder() && width_delta > 20; 285 document.body.removeChild(math); 286 } 287 return this._has_movablelimits; 288 }, 289 290 "has_operator_spacing": function() { 291 // https://w3c.github.io/mathml-core/#dfn-lspace 292 // https://w3c.github.io/mathml-core/#layout-of-mrow 293 if (!this.hasOwnProperty("_has_operator_spacing")) { 294 document.body.insertAdjacentHTML("beforeend", "<math>\ 295 <mrow>\ 296 <mn>1</mn><mo lspace='0px' rspace='0px'>+</mo><mn>2</mn>\ 297 </mrow>\ 298 <mrow>\ 299 <mn>1</mn><mo lspace='20px' rspace='20px'>+</mo><mn>2</mn>\ 300 </mrow>\ 301 </math>"); 302 var math = document.body.lastElementChild; 303 var mrow = math.getElementsByTagName("mrow"); 304 // lspace/rspace will add 40px per MathML and none if not supported. 305 this._has_operator_spacing = 306 mrow[1].getBoundingClientRect().width - 307 mrow[0].getBoundingClientRect().width > 30; 308 document.body.removeChild(math); 309 } 310 return this._has_operator_spacing; 311 }, 312 313 ensure_for_match_reftest: function(has_function) { 314 if (!document.querySelector("link[rel='match']")) 315 throw "This function must only be used for match reftest"; 316 // Add a little red square at the top left corner if the feature is not supported in order to make match reftest fail. 317 if (!this[has_function]()) { 318 document.body.insertAdjacentHTML("beforeend", "\ 319 <div style='width: 10px !important; height: 10px !important;\ 320 position: absolute !important;\ 321 left: 0 !important; top: 0 !important;\ 322 background: red !important; z-index: 1000 !important;'></div>"); 323 } 324 } 325 };