browser_attributed_text.js (8838B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 // Test read-only attributed strings 8 addAccessibleTask( 9 `<h1>hello <a href="#" id="a1">world</a></h1> 10 <p>this <b style="color: red; background-color: yellow;" aria-invalid="spelling">is</b> <span style="text-decoration: underline dotted green;">a</span> <a href="#" id="a2">test</a></p>`, 11 async (browser, accDoc) => { 12 let macDoc = accDoc.nativeInterface.QueryInterface( 13 Ci.nsIAccessibleMacInterface 14 ); 15 16 let range = macDoc.getParameterizedAttributeValue( 17 "AXTextMarkerRangeForUnorderedTextMarkers", 18 [ 19 macDoc.getAttributeValue("AXStartTextMarker"), 20 macDoc.getAttributeValue("AXEndTextMarker"), 21 ] 22 ); 23 24 let attributedText = macDoc.getParameterizedAttributeValue( 25 "AXAttributedStringForTextMarkerRange", 26 range 27 ); 28 29 let attributesList = attributedText.map( 30 ({ 31 string, 32 AXForegroundColor, 33 AXBackgroundColor, 34 AXUnderline, 35 AXUnderlineColor, 36 AXHeadingLevel, 37 AXFont, 38 AXLink, 39 AXMarkedMisspelled, 40 }) => [ 41 string, 42 AXForegroundColor, 43 AXBackgroundColor, 44 AXUnderline, 45 AXUnderlineColor, 46 AXHeadingLevel, 47 AXFont.AXFontSize, 48 AXLink ? AXLink.getAttributeValue("AXDOMIdentifier") : null, 49 AXMarkedMisspelled, 50 ] 51 ); 52 53 Assert.deepEqual(attributesList, [ 54 // string, fg color, bg color, underline, underline color, heading level, font size, link id, misspelled 55 [ 56 "hello ", 57 "#000000", 58 "#ffffff", 59 undefined, 60 undefined, 61 1, 62 32, 63 null, 64 undefined, 65 ], 66 ["world", "#0000ee", "#ffffff", 1, "#0000ee", 1, 32, "a1", undefined], 67 [ 68 "this ", 69 "#000000", 70 "#ffffff", 71 undefined, 72 undefined, 73 undefined, 74 16, 75 null, 76 undefined, 77 ], 78 [ 79 "is", 80 "#ff0000", 81 "#ffff00", 82 undefined, 83 undefined, 84 undefined, 85 16, 86 null, 87 1, 88 ], 89 [ 90 " ", 91 "#000000", 92 "#ffffff", 93 undefined, 94 undefined, 95 undefined, 96 16, 97 null, 98 undefined, 99 ], 100 ["a", "#000000", "#ffffff", 1, "#008000", undefined, 16, null, undefined], 101 [ 102 " ", 103 "#000000", 104 "#ffffff", 105 undefined, 106 undefined, 107 undefined, 108 16, 109 null, 110 undefined, 111 ], 112 [ 113 "test", 114 "#0000ee", 115 "#ffffff", 116 1, 117 "#0000ee", 118 undefined, 119 16, 120 "a2", 121 undefined, 122 ], 123 ]); 124 125 // Test different NSRange parameters for AXAttributedStringForRange 126 let worldLeaf = findAccessibleChildByID(accDoc, "a1").firstChild; 127 let wordStaticText = worldLeaf.nativeInterface.QueryInterface( 128 Ci.nsIAccessibleMacInterface 129 ); 130 attributedText = wordStaticText.getParameterizedAttributeValue( 131 "AXAttributedStringForRange", 132 NSRange(4, 1) 133 ); 134 is(attributedText.length, 1, "Last character is in single attribute run"); 135 is(attributedText[0].string, "d", "Last character matches"); 136 137 attributedText = wordStaticText.getParameterizedAttributeValue( 138 "AXAttributedStringForRange", 139 NSRange(5, 1) 140 ); 141 is(attributedText.length, 0, "Range is past accessible bounds"); 142 } 143 ); 144 145 // Test misspelling in text area 146 addAccessibleTask( 147 `<textarea id="t">hello worlf, i love you</textarea>`, 148 async (browser, accDoc) => { 149 let textArea = getNativeInterface(accDoc, "t"); 150 let spellDone = waitForEvent(EVENT_TEXT_ATTRIBUTE_CHANGED, "t"); 151 textArea.setAttributeValue("AXFocused", true); 152 153 let attributedText = []; 154 155 // For some internal reason we get several text attribute change events 156 // before the attributed text returned provides the misspelling attributes. 157 while (true) { 158 await spellDone; 159 160 let range = textArea.getAttributeValue("AXVisibleCharacterRange"); 161 attributedText = textArea.getParameterizedAttributeValue( 162 "AXAttributedStringForRange", 163 NSRange(...range) 164 ); 165 166 if (attributedText.length != 3) { 167 spellDone = waitForEvent(EVENT_TEXT_ATTRIBUTE_CHANGED, "t"); 168 } else { 169 break; 170 } 171 } 172 173 ok(attributedText[1].AXMarkedMisspelled); 174 } 175 ); 176 177 // Test getting a span of attributed text that includes an empty input element. 178 addAccessibleTask( 179 `hello <input id="input"> world<button></button>`, 180 async (browser, accDoc) => { 181 let macDoc = accDoc.nativeInterface.QueryInterface( 182 Ci.nsIAccessibleMacInterface 183 ); 184 185 let range = macDoc.getParameterizedAttributeValue( 186 "AXTextMarkerRangeForUnorderedTextMarkers", 187 [ 188 macDoc.getAttributeValue("AXStartTextMarker"), 189 macDoc.getAttributeValue("AXEndTextMarker"), 190 ] 191 ); 192 193 let attributedText = macDoc.getParameterizedAttributeValue( 194 "AXAttributedStringForTextMarkerRange", 195 range 196 ); 197 198 let text = macDoc.getParameterizedAttributeValue( 199 "AXStringForTextMarkerRange", 200 range 201 ); 202 203 is( 204 attributedText.length, 205 4, 206 "Should be 4 attribute runs for 2 texts, input and button" 207 ); 208 is(attributedText[0].string, `hello `, "Attributed string is correct"); 209 ok( 210 !attributedText[0].AXAttachment, 211 "Regular string attributes run doesn't have attachment" 212 ); 213 is( 214 attributedText[1].AXAttachment.getAttributeValue("AXRole"), 215 "AXTextField", 216 "Entry text attribute run has correct attachment" 217 ); 218 is( 219 attributedText[3].AXAttachment.getAttributeValue("AXRole"), 220 "AXButton", 221 "Button text attribute run has correct attachment" 222 ); 223 is(text, `hello world${kEmbedChar}`, "Unattributed string is correct"); 224 } 225 ); 226 227 // Test text fragment. 228 addAccessibleTask( 229 `This is a test.`, 230 async (browser, accDoc) => { 231 const macDoc = accDoc.nativeInterface.QueryInterface( 232 Ci.nsIAccessibleMacInterface 233 ); 234 const range = macDoc.getParameterizedAttributeValue( 235 "AXTextMarkerRangeForUnorderedTextMarkers", 236 [ 237 macDoc.getAttributeValue("AXStartTextMarker"), 238 macDoc.getAttributeValue("AXEndTextMarker"), 239 ] 240 ); 241 const attributedText = macDoc.getParameterizedAttributeValue( 242 "AXAttributedStringForTextMarkerRange", 243 range 244 ); 245 is(attributedText.length, 3); 246 ok(!attributedText[0].AXHighlight); 247 ok(attributedText[1].AXHighlight); 248 is(attributedText[1].string, "test"); 249 ok(!attributedText[2].AXHighlight); 250 }, 251 { urlSuffix: "#:~:text=test" } 252 ); 253 254 // Test the <mark> element. 255 addAccessibleTask( 256 `This is a <mark>test</mark>.`, 257 async function testMark(browser, accDoc) { 258 const macDoc = accDoc.nativeInterface.QueryInterface( 259 Ci.nsIAccessibleMacInterface 260 ); 261 const range = macDoc.getParameterizedAttributeValue( 262 "AXTextMarkerRangeForUnorderedTextMarkers", 263 [ 264 macDoc.getAttributeValue("AXStartTextMarker"), 265 macDoc.getAttributeValue("AXEndTextMarker"), 266 ] 267 ); 268 const attributedText = macDoc.getParameterizedAttributeValue( 269 "AXAttributedStringForTextMarkerRange", 270 range 271 ); 272 is(attributedText.length, 3); 273 ok(!attributedText[0].AXHighlight); 274 ok(attributedText[1].AXHighlight); 275 is(attributedText[1].string, "test"); 276 ok(!attributedText[2].AXHighlight); 277 } 278 ); 279 280 // Test the <mark> element, in conjunction with content that will 281 // prevent the creation of a text attributes object. 282 addAccessibleTask( 283 `<mark>a<button></button>b</mark>`, 284 async function testMarkNoAttributes(browser, accDoc) { 285 const macDoc = accDoc.nativeInterface.QueryInterface( 286 Ci.nsIAccessibleMacInterface 287 ); 288 const range = macDoc.getParameterizedAttributeValue( 289 "AXTextMarkerRangeForUnorderedTextMarkers", 290 [ 291 macDoc.getAttributeValue("AXStartTextMarker"), 292 macDoc.getAttributeValue("AXEndTextMarker"), 293 ] 294 ); 295 const attributedText = macDoc.getParameterizedAttributeValue( 296 "AXAttributedStringForTextMarkerRange", 297 range 298 ); 299 ok(attributedText, "Document has attributed text"); 300 is(attributedText.length, 3, "3 pieces of attributed text exist"); 301 302 ok(attributedText[0].AXHighlight, "0th pos text has highlight"); 303 is(attributedText[0].string, "a", "0th pos text is string `a`"); 304 305 ok(!attributedText[1].AXHighlight, "1st pos text has no highlight"); 306 307 ok(attributedText[2].AXHighlight, "2nd pos text has highlight"); 308 is(attributedText[2].string, "b", "2nd pos text is string `b`"); 309 } 310 );