michael@0: /** michael@0: * Tests if the given child and grand child accessibles at the given point are michael@0: * expected. michael@0: * michael@0: * @param aID [in] accessible identifier michael@0: * @param aX [in] x coordinate of the point relative accessible michael@0: * @param aY [in] y coordinate of the point relative accessible michael@0: * @param aChildID [in] expected child accessible michael@0: * @param aGrandChildID [in] expected child accessible michael@0: */ michael@0: function testChildAtPoint(aID, aX, aY, aChildID, aGrandChildID) michael@0: { michael@0: var child = getChildAtPoint(aID, aX, aY, false); michael@0: var expectedChild = getAccessible(aChildID); michael@0: michael@0: var msg = "Wrong direct child accessible at the point (" + aX + ", " + aY + michael@0: ") of " + prettyName(aID); michael@0: isObject(child, expectedChild, msg); michael@0: michael@0: var grandChild = getChildAtPoint(aID, aX, aY, true); michael@0: var expectedGrandChild = getAccessible(aGrandChildID); michael@0: michael@0: msg = "Wrong deepest child accessible at the point (" + aX + ", " + aY + michael@0: ") of " + prettyName(aID); michael@0: isObject(grandChild, expectedGrandChild, msg); michael@0: } michael@0: michael@0: /** michael@0: * Test if getChildAtPoint returns the given child and grand child accessibles michael@0: * at coordinates of child accessible (direct and deep hit test). michael@0: */ michael@0: function hitTest(aContainerID, aChildID, aGrandChildID) michael@0: { michael@0: var container = getAccessible(aContainerID); michael@0: var child = getAccessible(aChildID); michael@0: var grandChild = getAccessible(aGrandChildID); michael@0: michael@0: var [x, y] = getBoundsForDOMElm(child); michael@0: michael@0: var actualChild = container.getChildAtPoint(x + 1, y + 1); michael@0: isObject(actualChild, child, michael@0: "Wrong direct child of " + prettyName(aContainerID)); michael@0: michael@0: var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1); michael@0: isObject(actualGrandChild, grandChild, michael@0: "Wrong deepest child of " + prettyName(aContainerID)); michael@0: } michael@0: michael@0: /** michael@0: * Test if getOffsetAtPoint returns the given text offset at given coordinates. michael@0: */ michael@0: function testOffsetAtPoint(aHyperTextID, aX, aY, aCoordType, aExpectedOffset) michael@0: { michael@0: var hyperText = getAccessible(aHyperTextID, [nsIAccessibleText]); michael@0: var offset = hyperText.getOffsetAtPoint(aX, aY, aCoordType); michael@0: is(offset, aExpectedOffset, michael@0: "Wrong offset at given point (" + aX + ", " + aY + ") for " + michael@0: prettyName(aHyperTextID)); michael@0: } michael@0: michael@0: /** michael@0: * Zoom the given document. michael@0: */ michael@0: function zoomDocument(aDocument, aZoom) michael@0: { michael@0: var docShell = aDocument.defaultView. michael@0: QueryInterface(Components.interfaces.nsIInterfaceRequestor). michael@0: getInterface(Components.interfaces.nsIWebNavigation). michael@0: QueryInterface(Components.interfaces.nsIDocShell); michael@0: var docViewer = docShell.contentViewer. michael@0: QueryInterface(Components.interfaces.nsIMarkupDocumentViewer); michael@0: michael@0: docViewer.fullZoom = aZoom; michael@0: } michael@0: michael@0: /** michael@0: * Return child accessible at the given point. michael@0: * michael@0: * @param aIdentifier [in] accessible identifier michael@0: * @param aX [in] x coordinate of the point relative accessible michael@0: * @param aY [in] y coordinate of the point relative accessible michael@0: * @param aFindDeepestChild [in] points whether deepest or nearest child should michael@0: * be returned michael@0: * @return the child accessible at the given point michael@0: */ michael@0: function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) michael@0: { michael@0: var acc = getAccessible(aIdentifier); michael@0: if (!acc) michael@0: return; michael@0: michael@0: var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode); michael@0: michael@0: var x = screenX + aX; michael@0: var y = screenY + aY; michael@0: michael@0: try { michael@0: if (aFindDeepestChild) michael@0: return acc.getDeepestChildAtPoint(x, y); michael@0: return acc.getChildAtPoint(x, y); michael@0: } catch (e) { } michael@0: michael@0: return null; michael@0: } michael@0: michael@0: /** michael@0: * Test the accessible position. michael@0: */ michael@0: function testPos(aID, aPoint) michael@0: { michael@0: var [expectedX, expectedY] = michael@0: (aPoint != undefined) ? aPoint : getBoundsForDOMElm(aID); michael@0: michael@0: var [x, y] = getBounds(aID); michael@0: is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); michael@0: is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); michael@0: } michael@0: michael@0: /** michael@0: * Test the accessible boundaries. michael@0: */ michael@0: function testBounds(aID, aRect) michael@0: { michael@0: var [expectedX, expectedY, expectedWidth, expectedHeight] = michael@0: (aRect != undefined) ? aRect : getBoundsForDOMElm(aID); michael@0: michael@0: var [x, y, width, height] = getBounds(aID); michael@0: is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); michael@0: is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); michael@0: is(width, expectedWidth, "Wrong width of " + prettyName(aID)); michael@0: is(height, expectedHeight, "Wrong height of " + prettyName(aID)); michael@0: } michael@0: michael@0: /** michael@0: * Test text position at the given offset. michael@0: */ michael@0: function testTextPos(aID, aOffset, aPoint, aCoordOrigin) michael@0: { michael@0: var [expectedX, expectedY] = aPoint; michael@0: michael@0: var xObj = {}, yObj = {}; michael@0: var hyperText = getAccessible(aID, [nsIAccessibleText]); michael@0: hyperText.getCharacterExtents(aOffset, xObj, yObj, {}, {}, aCoordOrigin); michael@0: is(xObj.value, expectedX, michael@0: "Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID)); michael@0: ok(yObj.value - expectedY < 2 && expectedY - yObj.value < 2, michael@0: "Wrong y coordinate at offset " + aOffset + " for " + prettyName(aID) + michael@0: " - got " + yObj.value + ", expected " + expectedY + michael@0: "The difference doesn't exceed 1."); michael@0: } michael@0: michael@0: /** michael@0: * Test text bounds that is enclosed betwene the given offsets. michael@0: */ michael@0: function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) michael@0: { michael@0: var [expectedX, expectedY, expectedWidth, expectedHeight] = aRect; michael@0: michael@0: var xObj = {}, yObj = {}, widthObj = {}, heightObj = {}; michael@0: var hyperText = getAccessible(aID, [nsIAccessibleText]); michael@0: hyperText.getRangeExtents(aStartOffset, aEndOffset, michael@0: xObj, yObj, widthObj, heightObj, aCoordOrigin); michael@0: is(xObj.value, expectedX, michael@0: "Wrong x coordinate of text between offsets (" + aStartOffset + ", " + michael@0: aEndOffset + ") for " + prettyName(aID)); michael@0: is(yObj.value, expectedY, michael@0: "Wrong y coordinate of text between offsets (" + aStartOffset + ", " + michael@0: aEndOffset + ") for " + prettyName(aID)); michael@0: michael@0: var msg = "Wrong width of text between offsets (" + aStartOffset + ", " + michael@0: aEndOffset + ") for " + prettyName(aID); michael@0: if (widthObj.value == expectedWidth) michael@0: ok(true, msg); michael@0: else michael@0: todo(false, msg); // fails on some windows machines michael@0: michael@0: is(heightObj.value, expectedHeight, michael@0: "Wrong height of text between offsets (" + aStartOffset + ", " + michael@0: aEndOffset + ") for " + prettyName(aID)); michael@0: } michael@0: michael@0: /** michael@0: * Return the accessible coordinates relative to the screen in device pixels. michael@0: */ michael@0: function getPos(aID) michael@0: { michael@0: var accessible = getAccessible(aID); michael@0: var x = {}, y = {}; michael@0: accessible.getBounds(x, y, {}, {}); michael@0: return [x.value, y.value]; michael@0: } michael@0: michael@0: /** michael@0: * Return the accessible coordinates and size relative to the screen in device michael@0: * pixels. michael@0: */ michael@0: function getBounds(aID) michael@0: { michael@0: var accessible = getAccessible(aID); michael@0: var x = {}, y = {}, width = {}, height = {}; michael@0: accessible.getBounds(x, y, width, height); michael@0: return [x.value, y.value, width.value, height.value]; michael@0: } michael@0: michael@0: /** michael@0: * Return DOM node coordinates relative the screen and its size in device michael@0: * pixels. michael@0: */ michael@0: function getBoundsForDOMElm(aID) michael@0: { michael@0: var x = 0, y = 0, width = 0, height = 0; michael@0: michael@0: var elm = getNode(aID); michael@0: if (elm.localName == "area") { michael@0: var mapName = elm.parentNode.getAttribute("name"); michael@0: var selector = "[usemap='#" + mapName + "']"; michael@0: var img = elm.ownerDocument.querySelector(selector); michael@0: michael@0: var areaCoords = elm.coords.split(","); michael@0: var areaX = parseInt(areaCoords[0]); michael@0: var areaY = parseInt(areaCoords[1]); michael@0: var areaWidth = parseInt(areaCoords[2]) - areaX; michael@0: var areaHeight = parseInt(areaCoords[3]) - areaY; michael@0: michael@0: var rect = img.getBoundingClientRect(); michael@0: x = rect.left + areaX; michael@0: y = rect.top + areaY; michael@0: width = areaWidth; michael@0: height = areaHeight; michael@0: } michael@0: else { michael@0: var rect = elm.getBoundingClientRect(); michael@0: x = rect.left; michael@0: y = rect.top; michael@0: width = rect.width; michael@0: height = rect.height; michael@0: } michael@0: michael@0: var elmWindow = elm.ownerDocument.defaultView; michael@0: return CSSToDevicePixels(elmWindow, michael@0: x + elmWindow.mozInnerScreenX, michael@0: y + elmWindow.mozInnerScreenY, michael@0: width, michael@0: height); michael@0: } michael@0: michael@0: function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) michael@0: { michael@0: var winUtil = aWindow. michael@0: QueryInterface(Components.interfaces.nsIInterfaceRequestor). michael@0: getInterface(Components.interfaces.nsIDOMWindowUtils); michael@0: michael@0: var ratio = winUtil.screenPixelsPerCSSPixel; michael@0: michael@0: // CSS pixels and ratio can be not integer. Device pixels are always integer. michael@0: // Do our best and hope it works. michael@0: return [ Math.round(aX * ratio), Math.round(aY * ratio), michael@0: Math.round(aWidth * ratio), Math.round(aHeight * ratio) ]; michael@0: }