//////////////////////////////////////////////////////////////////////////////// // Object attributes. /** * Test object attributes. * * @param aAccOrElmOrID [in] the accessible identifier * @param aAttrs [in] the map of expected object attributes * (name/value pairs) * @param aSkipUnexpectedAttrs [in] points this function doesn't fail if * unexpected attribute is encountered */ function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs) { testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs); } /** * Test object attributes that must not be present. * * @param aAccOrElmOrID [in] the accessible identifier * @param aAbsentAttrs [in] map of attributes that should not be * present (name/value pairs) */ function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs) { testAttrsInternal(aAccOrElmOrID, {}, true, aAbsentAttrs); } /** * Test CSS based object attributes. */ function testCSSAttrs(aID) { var node = document.getElementById(aID); var computedStyle = document.defaultView.getComputedStyle(node, ""); var attrs = { "display": computedStyle.display, "text-align": computedStyle.textAlign, "text-indent": computedStyle.textIndent, "margin-left": computedStyle.marginLeft, "margin-right": computedStyle.marginRight, "margin-top": computedStyle.marginTop, "margin-bottom": computedStyle.marginBottom }; testAttrs(aID, attrs, true); } /** * Test the accessible that it doesn't have CSS-based object attributes. */ function testAbsentCSSAttrs(aID) { var attrs = { "display": "", "text-align": "", "text-indent": "", "margin-left": "", "margin-right": "", "margin-top": "", "margin-bottom": "" }; testAbsentAttrs(aID, attrs); } /** * Test group object attributes (posinset, setsize and level) and * nsIAccessible::groupPosition() method. * * @param aAccOrElmOrID [in] the ID, DOM node or accessible * @param aPosInSet [in] the value of 'posinset' attribute * @param aSetSize [in] the value of 'setsize' attribute * @param aLevel [in, optional] the value of 'level' attribute */ function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel) { var acc = getAccessible(aAccOrElmOrID); var levelObj = {}, posInSetObj = {}, setSizeObj = {}; acc.groupPosition(levelObj, setSizeObj, posInSetObj); if (aPosInSet && aSetSize) { is(posInSetObj.value, aPosInSet, "Wrong group position (posinset) for " + prettyName(aAccOrElmOrID)); is(setSizeObj.value, aSetSize, "Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID)); var attrs = { "posinset": String(aPosInSet), "setsize": String(aSetSize) }; testAttrs(aAccOrElmOrID, attrs, true); } if (aLevel) { is(levelObj.value, aLevel, "Wrong group level for " + prettyName(aAccOrElmOrID)); var attrs = { "level" : String(aLevel) }; testAttrs(aAccOrElmOrID, attrs, true); } } //////////////////////////////////////////////////////////////////////////////// // Text attributes. /** * Test text attributes. * * @param aID [in] the ID of DOM element having text * accessible * @param aOffset [in] the offset inside text accessible to fetch * text attributes * @param aAttrs [in] the map of expected text attributes * (name/value pairs) exposed at the offset * @param aDefAttrs [in] the map of expected text attributes * (name/value pairs) exposed on hyper text * accessible * @param aStartOffset [in] expected start offset where text attributes * are applied * @param aEndOffset [in] expected end offset where text attribute * are applied * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if * unexpected attribute is encountered */ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs, aStartOffset, aEndOffset, aSkipUnexpectedAttrs) { var accessible = getAccessible(aID, [nsIAccessibleText]); if (!accessible) return; var startOffset = { value: -1 }; var endOffset = { value: -1 }; // do not include attributes exposed on hyper text accessbile var attrs = getTextAttributes(aID, accessible, false, aOffset, startOffset, endOffset); if (!attrs) return; var errorMsg = " for " + aID + " at offset " + aOffset; is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg); is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg); compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs); // include attributes exposed on hyper text accessbile var expectedAttrs = {}; for (var name in aAttrs) expectedAttrs[name] = aAttrs[name]; for (var name in aDefAttrs) { if (!(name in expectedAttrs)) expectedAttrs[name] = aDefAttrs[name]; } attrs = getTextAttributes(aID, accessible, true, aOffset, startOffset, endOffset); if (!attrs) return; compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs); } /** * Test default text attributes. * * @param aID [in] the ID of DOM element having text * accessible * @param aDefAttrs [in] the map of expected text attributes * (name/value pairs) * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if * unexpected attribute is encountered */ function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs) { var accessible = getAccessible(aID, [nsIAccessibleText]); if (!accessible) return; var defAttrs = null; try{ defAttrs = accessible.defaultTextAttributes; } catch (e) { } if (!defAttrs) { ok(false, "Can't get default text attributes for " + aID); return; } var errorMsg = ". Getting default text attributes for " + aID; compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs); } /** * Test text attributes for wrong offset. */ function testTextAttrsWrongOffset(aID, aOffset) { var res = false; try { var s = {}, e = {}; var acc = getAccessible(ID, [nsIAccessibleText]); acc.getTextAttributes(false, 157, s, e); } catch (e) { res = true; } ok(res, "text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID)); } const kNormalFontWeight = function equalsToNormal(aWeight) { return aWeight <= 400 ; } const kBoldFontWeight = function equalsToBold(aWeight) { return aWeight > 400; } // The pt font size of the input element can vary by Linux distro. const kInputFontSize = WIN ? "10pt" : (MAC ? "8pt" : function() { return true; }); const kAbsentFontFamily = function(aFontFamily) { return aFontFamily != "sans-serif"; } const kInputFontFamily = function(aFontFamily) { return aFontFamily != "sans-serif"; } const kMonospaceFontFamily = function(aFontFamily) { return aFontFamily != "monospace"; } const kSansSerifFontFamily = function(aFontFamily) { return aFontFamily != "sans-serif"; } const kSerifFontFamily = function(aFontFamily) { return aFontFamily != "serif"; } const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS"; /** * Return used font from the given computed style. */ function fontFamily(aComputedStyle) { var name = aComputedStyle.fontFamily; switch (name) { case "monospace": return kMonospaceFontFamily; case "sans-serif": return kSansSerifFontFamily; case "serif": return kSerifFontFamily; default: return name; } } /** * Build an object of default text attributes expected for the given accessible. * * @param aID [in] identifier of accessible * @param aFontSize [in] font size * @param aFontWeight [in, optional] kBoldFontWeight or kNormalFontWeight, * default value is kNormalFontWeight */ function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily) { var elm = getNode(aID); var computedStyle = document.defaultView.getComputedStyle(elm, ""); var bgColor = computedStyle.backgroundColor == "transparent" ? "rgb(255, 255, 255)" : computedStyle.backgroundColor; var defAttrs = { "font-style": computedStyle.fontStyle, "font-size": aFontSize, "background-color": bgColor, "font-weight": aFontWeight ? aFontWeight : kNormalFontWeight, "color": computedStyle.color, "font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle), "text-position": computedStyle.verticalAlign }; return defAttrs; } //////////////////////////////////////////////////////////////////////////////// // Private. function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset, aStartOffset, aEndOffset) { // This function expects the passed in accessible to already be queried for // nsIAccessibleText. var attrs = null; try { attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset, aStartOffset, aEndOffset); } catch (e) { } if (attrs) return attrs; ok(false, "Can't get text attributes for " + aID); return null; } function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs) { var accessible = getAccessible(aAccOrElmOrID); if (!accessible) return; var attrs = null; try { attrs = accessible.attributes; } catch (e) { } if (!attrs) { ok(false, "Can't get object attributes for " + prettyName(aAccOrElmOrID)); return; } var errorMsg = " for " + prettyName(aAccOrElmOrID); compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs); } function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs, aAbsentAttrs) { // Check if all obtained attributes are expected and have expected value. var enumerate = aAttrs.enumerate(); while (enumerate.hasMoreElements()) { var prop = enumerate.getNext().QueryInterface(nsIPropertyElement); if (!(prop.key in aExpectedAttrs)) { if (!aSkipUnexpectedAttrs) ok(false, "Unexpected attribute '" + prop.key + "' having '" + prop.value + "'" + aErrorMsg); } else { var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg; var expectedValue = aExpectedAttrs[prop.key]; if (typeof expectedValue == "function") ok(expectedValue(prop.value), msg); else is(prop.value, expectedValue, msg); } } // Check if all expected attributes are presented. for (var name in aExpectedAttrs) { var value = ""; try { value = aAttrs.getStringProperty(name); } catch(e) { } if (!value) ok(false, "There is no expected attribute '" + name + "' " + aErrorMsg); } // Check if all unexpected attributes are absent. if (aAbsentAttrs) { for (var name in aAbsentAttrs) { var wasFound = false; var enumerate = aAttrs.enumerate(); while (enumerate.hasMoreElements()) { var prop = enumerate.getNext().QueryInterface(nsIPropertyElement); if (prop.key == name) wasFound = true; } } ok(!wasFound, "There is an unexpected attribute '" + name + "' " + aErrorMsg); } }