|
1 //////////////////////////////////////////////////////////////////////////////// |
|
2 // Object attributes. |
|
3 |
|
4 /** |
|
5 * Test object attributes. |
|
6 * |
|
7 * @param aAccOrElmOrID [in] the accessible identifier |
|
8 * @param aAttrs [in] the map of expected object attributes |
|
9 * (name/value pairs) |
|
10 * @param aSkipUnexpectedAttrs [in] points this function doesn't fail if |
|
11 * unexpected attribute is encountered |
|
12 */ |
|
13 function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs) |
|
14 { |
|
15 testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs); |
|
16 } |
|
17 |
|
18 /** |
|
19 * Test object attributes that must not be present. |
|
20 * |
|
21 * @param aAccOrElmOrID [in] the accessible identifier |
|
22 * @param aAbsentAttrs [in] map of attributes that should not be |
|
23 * present (name/value pairs) |
|
24 */ |
|
25 function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs) |
|
26 { |
|
27 testAttrsInternal(aAccOrElmOrID, {}, true, aAbsentAttrs); |
|
28 } |
|
29 |
|
30 /** |
|
31 * Test CSS based object attributes. |
|
32 */ |
|
33 function testCSSAttrs(aID) |
|
34 { |
|
35 var node = document.getElementById(aID); |
|
36 var computedStyle = document.defaultView.getComputedStyle(node, ""); |
|
37 |
|
38 var attrs = { |
|
39 "display": computedStyle.display, |
|
40 "text-align": computedStyle.textAlign, |
|
41 "text-indent": computedStyle.textIndent, |
|
42 "margin-left": computedStyle.marginLeft, |
|
43 "margin-right": computedStyle.marginRight, |
|
44 "margin-top": computedStyle.marginTop, |
|
45 "margin-bottom": computedStyle.marginBottom |
|
46 }; |
|
47 testAttrs(aID, attrs, true); |
|
48 } |
|
49 |
|
50 /** |
|
51 * Test the accessible that it doesn't have CSS-based object attributes. |
|
52 */ |
|
53 function testAbsentCSSAttrs(aID) |
|
54 { |
|
55 var attrs = { |
|
56 "display": "", |
|
57 "text-align": "", |
|
58 "text-indent": "", |
|
59 "margin-left": "", |
|
60 "margin-right": "", |
|
61 "margin-top": "", |
|
62 "margin-bottom": "" |
|
63 }; |
|
64 testAbsentAttrs(aID, attrs); |
|
65 } |
|
66 |
|
67 /** |
|
68 * Test group object attributes (posinset, setsize and level) and |
|
69 * nsIAccessible::groupPosition() method. |
|
70 * |
|
71 * @param aAccOrElmOrID [in] the ID, DOM node or accessible |
|
72 * @param aPosInSet [in] the value of 'posinset' attribute |
|
73 * @param aSetSize [in] the value of 'setsize' attribute |
|
74 * @param aLevel [in, optional] the value of 'level' attribute |
|
75 */ |
|
76 function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel) |
|
77 { |
|
78 var acc = getAccessible(aAccOrElmOrID); |
|
79 var levelObj = {}, posInSetObj = {}, setSizeObj = {}; |
|
80 acc.groupPosition(levelObj, setSizeObj, posInSetObj); |
|
81 |
|
82 if (aPosInSet && aSetSize) { |
|
83 is(posInSetObj.value, aPosInSet, |
|
84 "Wrong group position (posinset) for " + prettyName(aAccOrElmOrID)); |
|
85 is(setSizeObj.value, aSetSize, |
|
86 "Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID)); |
|
87 |
|
88 var attrs = { |
|
89 "posinset": String(aPosInSet), |
|
90 "setsize": String(aSetSize) |
|
91 }; |
|
92 testAttrs(aAccOrElmOrID, attrs, true); |
|
93 } |
|
94 |
|
95 if (aLevel) { |
|
96 is(levelObj.value, aLevel, |
|
97 "Wrong group level for " + prettyName(aAccOrElmOrID)); |
|
98 |
|
99 var attrs = { "level" : String(aLevel) }; |
|
100 testAttrs(aAccOrElmOrID, attrs, true); |
|
101 } |
|
102 } |
|
103 |
|
104 //////////////////////////////////////////////////////////////////////////////// |
|
105 // Text attributes. |
|
106 |
|
107 /** |
|
108 * Test text attributes. |
|
109 * |
|
110 * @param aID [in] the ID of DOM element having text |
|
111 * accessible |
|
112 * @param aOffset [in] the offset inside text accessible to fetch |
|
113 * text attributes |
|
114 * @param aAttrs [in] the map of expected text attributes |
|
115 * (name/value pairs) exposed at the offset |
|
116 * @param aDefAttrs [in] the map of expected text attributes |
|
117 * (name/value pairs) exposed on hyper text |
|
118 * accessible |
|
119 * @param aStartOffset [in] expected start offset where text attributes |
|
120 * are applied |
|
121 * @param aEndOffset [in] expected end offset where text attribute |
|
122 * are applied |
|
123 * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if |
|
124 * unexpected attribute is encountered |
|
125 */ |
|
126 function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs, |
|
127 aStartOffset, aEndOffset, aSkipUnexpectedAttrs) |
|
128 { |
|
129 var accessible = getAccessible(aID, [nsIAccessibleText]); |
|
130 if (!accessible) |
|
131 return; |
|
132 |
|
133 var startOffset = { value: -1 }; |
|
134 var endOffset = { value: -1 }; |
|
135 |
|
136 // do not include attributes exposed on hyper text accessbile |
|
137 var attrs = getTextAttributes(aID, accessible, false, aOffset, |
|
138 startOffset, endOffset); |
|
139 |
|
140 if (!attrs) |
|
141 return; |
|
142 |
|
143 var errorMsg = " for " + aID + " at offset " + aOffset; |
|
144 |
|
145 is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg); |
|
146 is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg); |
|
147 |
|
148 compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs); |
|
149 |
|
150 // include attributes exposed on hyper text accessbile |
|
151 var expectedAttrs = {}; |
|
152 for (var name in aAttrs) |
|
153 expectedAttrs[name] = aAttrs[name]; |
|
154 |
|
155 for (var name in aDefAttrs) { |
|
156 if (!(name in expectedAttrs)) |
|
157 expectedAttrs[name] = aDefAttrs[name]; |
|
158 } |
|
159 |
|
160 attrs = getTextAttributes(aID, accessible, true, aOffset, |
|
161 startOffset, endOffset); |
|
162 |
|
163 if (!attrs) |
|
164 return; |
|
165 |
|
166 compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs); |
|
167 } |
|
168 |
|
169 /** |
|
170 * Test default text attributes. |
|
171 * |
|
172 * @param aID [in] the ID of DOM element having text |
|
173 * accessible |
|
174 * @param aDefAttrs [in] the map of expected text attributes |
|
175 * (name/value pairs) |
|
176 * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if |
|
177 * unexpected attribute is encountered |
|
178 */ |
|
179 function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs) |
|
180 { |
|
181 var accessible = getAccessible(aID, [nsIAccessibleText]); |
|
182 if (!accessible) |
|
183 return; |
|
184 |
|
185 var defAttrs = null; |
|
186 try{ |
|
187 defAttrs = accessible.defaultTextAttributes; |
|
188 } catch (e) { |
|
189 } |
|
190 |
|
191 if (!defAttrs) { |
|
192 ok(false, "Can't get default text attributes for " + aID); |
|
193 return; |
|
194 } |
|
195 |
|
196 var errorMsg = ". Getting default text attributes for " + aID; |
|
197 compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs); |
|
198 } |
|
199 |
|
200 /** |
|
201 * Test text attributes for wrong offset. |
|
202 */ |
|
203 function testTextAttrsWrongOffset(aID, aOffset) |
|
204 { |
|
205 var res = false; |
|
206 try { |
|
207 var s = {}, e = {}; |
|
208 var acc = getAccessible(ID, [nsIAccessibleText]); |
|
209 acc.getTextAttributes(false, 157, s, e); |
|
210 } catch (e) { |
|
211 res = true; |
|
212 } |
|
213 |
|
214 ok(res, |
|
215 "text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID)); |
|
216 } |
|
217 |
|
218 const kNormalFontWeight = |
|
219 function equalsToNormal(aWeight) { return aWeight <= 400 ; } |
|
220 |
|
221 const kBoldFontWeight = |
|
222 function equalsToBold(aWeight) { return aWeight > 400; } |
|
223 |
|
224 // The pt font size of the input element can vary by Linux distro. |
|
225 const kInputFontSize = WIN ? |
|
226 "10pt" : (MAC ? "8pt" : function() { return true; }); |
|
227 |
|
228 const kAbsentFontFamily = |
|
229 function(aFontFamily) { return aFontFamily != "sans-serif"; } |
|
230 const kInputFontFamily = |
|
231 function(aFontFamily) { return aFontFamily != "sans-serif"; } |
|
232 |
|
233 const kMonospaceFontFamily = |
|
234 function(aFontFamily) { return aFontFamily != "monospace"; } |
|
235 const kSansSerifFontFamily = |
|
236 function(aFontFamily) { return aFontFamily != "sans-serif"; } |
|
237 const kSerifFontFamily = |
|
238 function(aFontFamily) { return aFontFamily != "serif"; } |
|
239 |
|
240 const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS"; |
|
241 |
|
242 /** |
|
243 * Return used font from the given computed style. |
|
244 */ |
|
245 function fontFamily(aComputedStyle) |
|
246 { |
|
247 var name = aComputedStyle.fontFamily; |
|
248 switch (name) { |
|
249 case "monospace": |
|
250 return kMonospaceFontFamily; |
|
251 case "sans-serif": |
|
252 return kSansSerifFontFamily; |
|
253 case "serif": |
|
254 return kSerifFontFamily; |
|
255 default: |
|
256 return name; |
|
257 } |
|
258 } |
|
259 |
|
260 /** |
|
261 * Build an object of default text attributes expected for the given accessible. |
|
262 * |
|
263 * @param aID [in] identifier of accessible |
|
264 * @param aFontSize [in] font size |
|
265 * @param aFontWeight [in, optional] kBoldFontWeight or kNormalFontWeight, |
|
266 * default value is kNormalFontWeight |
|
267 */ |
|
268 function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily) |
|
269 { |
|
270 var elm = getNode(aID); |
|
271 var computedStyle = document.defaultView.getComputedStyle(elm, ""); |
|
272 var bgColor = computedStyle.backgroundColor == "transparent" ? |
|
273 "rgb(255, 255, 255)" : computedStyle.backgroundColor; |
|
274 |
|
275 var defAttrs = { |
|
276 "font-style": computedStyle.fontStyle, |
|
277 "font-size": aFontSize, |
|
278 "background-color": bgColor, |
|
279 "font-weight": aFontWeight ? aFontWeight : kNormalFontWeight, |
|
280 "color": computedStyle.color, |
|
281 "font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle), |
|
282 "text-position": computedStyle.verticalAlign |
|
283 }; |
|
284 |
|
285 return defAttrs; |
|
286 } |
|
287 |
|
288 //////////////////////////////////////////////////////////////////////////////// |
|
289 // Private. |
|
290 |
|
291 function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset, |
|
292 aStartOffset, aEndOffset) |
|
293 { |
|
294 // This function expects the passed in accessible to already be queried for |
|
295 // nsIAccessibleText. |
|
296 var attrs = null; |
|
297 try { |
|
298 attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset, |
|
299 aStartOffset, aEndOffset); |
|
300 } catch (e) { |
|
301 } |
|
302 |
|
303 if (attrs) |
|
304 return attrs; |
|
305 |
|
306 ok(false, "Can't get text attributes for " + aID); |
|
307 return null; |
|
308 } |
|
309 |
|
310 function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs, |
|
311 aAbsentAttrs) |
|
312 { |
|
313 var accessible = getAccessible(aAccOrElmOrID); |
|
314 if (!accessible) |
|
315 return; |
|
316 |
|
317 var attrs = null; |
|
318 try { |
|
319 attrs = accessible.attributes; |
|
320 } catch (e) { } |
|
321 |
|
322 if (!attrs) { |
|
323 ok(false, "Can't get object attributes for " + prettyName(aAccOrElmOrID)); |
|
324 return; |
|
325 } |
|
326 |
|
327 var errorMsg = " for " + prettyName(aAccOrElmOrID); |
|
328 compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs); |
|
329 } |
|
330 |
|
331 function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs, |
|
332 aAbsentAttrs) |
|
333 { |
|
334 // Check if all obtained attributes are expected and have expected value. |
|
335 var enumerate = aAttrs.enumerate(); |
|
336 while (enumerate.hasMoreElements()) { |
|
337 var prop = enumerate.getNext().QueryInterface(nsIPropertyElement); |
|
338 |
|
339 if (!(prop.key in aExpectedAttrs)) { |
|
340 if (!aSkipUnexpectedAttrs) |
|
341 ok(false, "Unexpected attribute '" + prop.key + "' having '" + |
|
342 prop.value + "'" + aErrorMsg); |
|
343 } else { |
|
344 var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg; |
|
345 var expectedValue = aExpectedAttrs[prop.key]; |
|
346 |
|
347 if (typeof expectedValue == "function") |
|
348 ok(expectedValue(prop.value), msg); |
|
349 else |
|
350 is(prop.value, expectedValue, msg); |
|
351 } |
|
352 } |
|
353 |
|
354 // Check if all expected attributes are presented. |
|
355 for (var name in aExpectedAttrs) { |
|
356 var value = ""; |
|
357 try { |
|
358 value = aAttrs.getStringProperty(name); |
|
359 } catch(e) { } |
|
360 |
|
361 if (!value) |
|
362 ok(false, |
|
363 "There is no expected attribute '" + name + "' " + aErrorMsg); |
|
364 } |
|
365 |
|
366 // Check if all unexpected attributes are absent. |
|
367 if (aAbsentAttrs) { |
|
368 for (var name in aAbsentAttrs) { |
|
369 var wasFound = false; |
|
370 |
|
371 var enumerate = aAttrs.enumerate(); |
|
372 while (enumerate.hasMoreElements()) { |
|
373 var prop = enumerate.getNext().QueryInterface(nsIPropertyElement); |
|
374 if (prop.key == name) |
|
375 wasFound = true; |
|
376 } |
|
377 } |
|
378 |
|
379 ok(!wasFound, |
|
380 "There is an unexpected attribute '" + name + "' " + aErrorMsg); |
|
381 } |
|
382 } |