Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /** |
michael@0 | 2 | * Tests if the given child and grand child accessibles at the given point are |
michael@0 | 3 | * expected. |
michael@0 | 4 | * |
michael@0 | 5 | * @param aID [in] accessible identifier |
michael@0 | 6 | * @param aX [in] x coordinate of the point relative accessible |
michael@0 | 7 | * @param aY [in] y coordinate of the point relative accessible |
michael@0 | 8 | * @param aChildID [in] expected child accessible |
michael@0 | 9 | * @param aGrandChildID [in] expected child accessible |
michael@0 | 10 | */ |
michael@0 | 11 | function testChildAtPoint(aID, aX, aY, aChildID, aGrandChildID) |
michael@0 | 12 | { |
michael@0 | 13 | var child = getChildAtPoint(aID, aX, aY, false); |
michael@0 | 14 | var expectedChild = getAccessible(aChildID); |
michael@0 | 15 | |
michael@0 | 16 | var msg = "Wrong direct child accessible at the point (" + aX + ", " + aY + |
michael@0 | 17 | ") of " + prettyName(aID); |
michael@0 | 18 | isObject(child, expectedChild, msg); |
michael@0 | 19 | |
michael@0 | 20 | var grandChild = getChildAtPoint(aID, aX, aY, true); |
michael@0 | 21 | var expectedGrandChild = getAccessible(aGrandChildID); |
michael@0 | 22 | |
michael@0 | 23 | msg = "Wrong deepest child accessible at the point (" + aX + ", " + aY + |
michael@0 | 24 | ") of " + prettyName(aID); |
michael@0 | 25 | isObject(grandChild, expectedGrandChild, msg); |
michael@0 | 26 | } |
michael@0 | 27 | |
michael@0 | 28 | /** |
michael@0 | 29 | * Test if getChildAtPoint returns the given child and grand child accessibles |
michael@0 | 30 | * at coordinates of child accessible (direct and deep hit test). |
michael@0 | 31 | */ |
michael@0 | 32 | function hitTest(aContainerID, aChildID, aGrandChildID) |
michael@0 | 33 | { |
michael@0 | 34 | var container = getAccessible(aContainerID); |
michael@0 | 35 | var child = getAccessible(aChildID); |
michael@0 | 36 | var grandChild = getAccessible(aGrandChildID); |
michael@0 | 37 | |
michael@0 | 38 | var [x, y] = getBoundsForDOMElm(child); |
michael@0 | 39 | |
michael@0 | 40 | var actualChild = container.getChildAtPoint(x + 1, y + 1); |
michael@0 | 41 | isObject(actualChild, child, |
michael@0 | 42 | "Wrong direct child of " + prettyName(aContainerID)); |
michael@0 | 43 | |
michael@0 | 44 | var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1); |
michael@0 | 45 | isObject(actualGrandChild, grandChild, |
michael@0 | 46 | "Wrong deepest child of " + prettyName(aContainerID)); |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | /** |
michael@0 | 50 | * Test if getOffsetAtPoint returns the given text offset at given coordinates. |
michael@0 | 51 | */ |
michael@0 | 52 | function testOffsetAtPoint(aHyperTextID, aX, aY, aCoordType, aExpectedOffset) |
michael@0 | 53 | { |
michael@0 | 54 | var hyperText = getAccessible(aHyperTextID, [nsIAccessibleText]); |
michael@0 | 55 | var offset = hyperText.getOffsetAtPoint(aX, aY, aCoordType); |
michael@0 | 56 | is(offset, aExpectedOffset, |
michael@0 | 57 | "Wrong offset at given point (" + aX + ", " + aY + ") for " + |
michael@0 | 58 | prettyName(aHyperTextID)); |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | /** |
michael@0 | 62 | * Zoom the given document. |
michael@0 | 63 | */ |
michael@0 | 64 | function zoomDocument(aDocument, aZoom) |
michael@0 | 65 | { |
michael@0 | 66 | var docShell = aDocument.defaultView. |
michael@0 | 67 | QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
michael@0 | 68 | getInterface(Components.interfaces.nsIWebNavigation). |
michael@0 | 69 | QueryInterface(Components.interfaces.nsIDocShell); |
michael@0 | 70 | var docViewer = docShell.contentViewer. |
michael@0 | 71 | QueryInterface(Components.interfaces.nsIMarkupDocumentViewer); |
michael@0 | 72 | |
michael@0 | 73 | docViewer.fullZoom = aZoom; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | /** |
michael@0 | 77 | * Return child accessible at the given point. |
michael@0 | 78 | * |
michael@0 | 79 | * @param aIdentifier [in] accessible identifier |
michael@0 | 80 | * @param aX [in] x coordinate of the point relative accessible |
michael@0 | 81 | * @param aY [in] y coordinate of the point relative accessible |
michael@0 | 82 | * @param aFindDeepestChild [in] points whether deepest or nearest child should |
michael@0 | 83 | * be returned |
michael@0 | 84 | * @return the child accessible at the given point |
michael@0 | 85 | */ |
michael@0 | 86 | function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) |
michael@0 | 87 | { |
michael@0 | 88 | var acc = getAccessible(aIdentifier); |
michael@0 | 89 | if (!acc) |
michael@0 | 90 | return; |
michael@0 | 91 | |
michael@0 | 92 | var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode); |
michael@0 | 93 | |
michael@0 | 94 | var x = screenX + aX; |
michael@0 | 95 | var y = screenY + aY; |
michael@0 | 96 | |
michael@0 | 97 | try { |
michael@0 | 98 | if (aFindDeepestChild) |
michael@0 | 99 | return acc.getDeepestChildAtPoint(x, y); |
michael@0 | 100 | return acc.getChildAtPoint(x, y); |
michael@0 | 101 | } catch (e) { } |
michael@0 | 102 | |
michael@0 | 103 | return null; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | /** |
michael@0 | 107 | * Test the accessible position. |
michael@0 | 108 | */ |
michael@0 | 109 | function testPos(aID, aPoint) |
michael@0 | 110 | { |
michael@0 | 111 | var [expectedX, expectedY] = |
michael@0 | 112 | (aPoint != undefined) ? aPoint : getBoundsForDOMElm(aID); |
michael@0 | 113 | |
michael@0 | 114 | var [x, y] = getBounds(aID); |
michael@0 | 115 | is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); |
michael@0 | 116 | is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | /** |
michael@0 | 120 | * Test the accessible boundaries. |
michael@0 | 121 | */ |
michael@0 | 122 | function testBounds(aID, aRect) |
michael@0 | 123 | { |
michael@0 | 124 | var [expectedX, expectedY, expectedWidth, expectedHeight] = |
michael@0 | 125 | (aRect != undefined) ? aRect : getBoundsForDOMElm(aID); |
michael@0 | 126 | |
michael@0 | 127 | var [x, y, width, height] = getBounds(aID); |
michael@0 | 128 | is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); |
michael@0 | 129 | is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); |
michael@0 | 130 | is(width, expectedWidth, "Wrong width of " + prettyName(aID)); |
michael@0 | 131 | is(height, expectedHeight, "Wrong height of " + prettyName(aID)); |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | /** |
michael@0 | 135 | * Test text position at the given offset. |
michael@0 | 136 | */ |
michael@0 | 137 | function testTextPos(aID, aOffset, aPoint, aCoordOrigin) |
michael@0 | 138 | { |
michael@0 | 139 | var [expectedX, expectedY] = aPoint; |
michael@0 | 140 | |
michael@0 | 141 | var xObj = {}, yObj = {}; |
michael@0 | 142 | var hyperText = getAccessible(aID, [nsIAccessibleText]); |
michael@0 | 143 | hyperText.getCharacterExtents(aOffset, xObj, yObj, {}, {}, aCoordOrigin); |
michael@0 | 144 | is(xObj.value, expectedX, |
michael@0 | 145 | "Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID)); |
michael@0 | 146 | ok(yObj.value - expectedY < 2 && expectedY - yObj.value < 2, |
michael@0 | 147 | "Wrong y coordinate at offset " + aOffset + " for " + prettyName(aID) + |
michael@0 | 148 | " - got " + yObj.value + ", expected " + expectedY + |
michael@0 | 149 | "The difference doesn't exceed 1."); |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | /** |
michael@0 | 153 | * Test text bounds that is enclosed betwene the given offsets. |
michael@0 | 154 | */ |
michael@0 | 155 | function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) |
michael@0 | 156 | { |
michael@0 | 157 | var [expectedX, expectedY, expectedWidth, expectedHeight] = aRect; |
michael@0 | 158 | |
michael@0 | 159 | var xObj = {}, yObj = {}, widthObj = {}, heightObj = {}; |
michael@0 | 160 | var hyperText = getAccessible(aID, [nsIAccessibleText]); |
michael@0 | 161 | hyperText.getRangeExtents(aStartOffset, aEndOffset, |
michael@0 | 162 | xObj, yObj, widthObj, heightObj, aCoordOrigin); |
michael@0 | 163 | is(xObj.value, expectedX, |
michael@0 | 164 | "Wrong x coordinate of text between offsets (" + aStartOffset + ", " + |
michael@0 | 165 | aEndOffset + ") for " + prettyName(aID)); |
michael@0 | 166 | is(yObj.value, expectedY, |
michael@0 | 167 | "Wrong y coordinate of text between offsets (" + aStartOffset + ", " + |
michael@0 | 168 | aEndOffset + ") for " + prettyName(aID)); |
michael@0 | 169 | |
michael@0 | 170 | var msg = "Wrong width of text between offsets (" + aStartOffset + ", " + |
michael@0 | 171 | aEndOffset + ") for " + prettyName(aID); |
michael@0 | 172 | if (widthObj.value == expectedWidth) |
michael@0 | 173 | ok(true, msg); |
michael@0 | 174 | else |
michael@0 | 175 | todo(false, msg); // fails on some windows machines |
michael@0 | 176 | |
michael@0 | 177 | is(heightObj.value, expectedHeight, |
michael@0 | 178 | "Wrong height of text between offsets (" + aStartOffset + ", " + |
michael@0 | 179 | aEndOffset + ") for " + prettyName(aID)); |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | /** |
michael@0 | 183 | * Return the accessible coordinates relative to the screen in device pixels. |
michael@0 | 184 | */ |
michael@0 | 185 | function getPos(aID) |
michael@0 | 186 | { |
michael@0 | 187 | var accessible = getAccessible(aID); |
michael@0 | 188 | var x = {}, y = {}; |
michael@0 | 189 | accessible.getBounds(x, y, {}, {}); |
michael@0 | 190 | return [x.value, y.value]; |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | /** |
michael@0 | 194 | * Return the accessible coordinates and size relative to the screen in device |
michael@0 | 195 | * pixels. |
michael@0 | 196 | */ |
michael@0 | 197 | function getBounds(aID) |
michael@0 | 198 | { |
michael@0 | 199 | var accessible = getAccessible(aID); |
michael@0 | 200 | var x = {}, y = {}, width = {}, height = {}; |
michael@0 | 201 | accessible.getBounds(x, y, width, height); |
michael@0 | 202 | return [x.value, y.value, width.value, height.value]; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | /** |
michael@0 | 206 | * Return DOM node coordinates relative the screen and its size in device |
michael@0 | 207 | * pixels. |
michael@0 | 208 | */ |
michael@0 | 209 | function getBoundsForDOMElm(aID) |
michael@0 | 210 | { |
michael@0 | 211 | var x = 0, y = 0, width = 0, height = 0; |
michael@0 | 212 | |
michael@0 | 213 | var elm = getNode(aID); |
michael@0 | 214 | if (elm.localName == "area") { |
michael@0 | 215 | var mapName = elm.parentNode.getAttribute("name"); |
michael@0 | 216 | var selector = "[usemap='#" + mapName + "']"; |
michael@0 | 217 | var img = elm.ownerDocument.querySelector(selector); |
michael@0 | 218 | |
michael@0 | 219 | var areaCoords = elm.coords.split(","); |
michael@0 | 220 | var areaX = parseInt(areaCoords[0]); |
michael@0 | 221 | var areaY = parseInt(areaCoords[1]); |
michael@0 | 222 | var areaWidth = parseInt(areaCoords[2]) - areaX; |
michael@0 | 223 | var areaHeight = parseInt(areaCoords[3]) - areaY; |
michael@0 | 224 | |
michael@0 | 225 | var rect = img.getBoundingClientRect(); |
michael@0 | 226 | x = rect.left + areaX; |
michael@0 | 227 | y = rect.top + areaY; |
michael@0 | 228 | width = areaWidth; |
michael@0 | 229 | height = areaHeight; |
michael@0 | 230 | } |
michael@0 | 231 | else { |
michael@0 | 232 | var rect = elm.getBoundingClientRect(); |
michael@0 | 233 | x = rect.left; |
michael@0 | 234 | y = rect.top; |
michael@0 | 235 | width = rect.width; |
michael@0 | 236 | height = rect.height; |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | var elmWindow = elm.ownerDocument.defaultView; |
michael@0 | 240 | return CSSToDevicePixels(elmWindow, |
michael@0 | 241 | x + elmWindow.mozInnerScreenX, |
michael@0 | 242 | y + elmWindow.mozInnerScreenY, |
michael@0 | 243 | width, |
michael@0 | 244 | height); |
michael@0 | 245 | } |
michael@0 | 246 | |
michael@0 | 247 | function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) |
michael@0 | 248 | { |
michael@0 | 249 | var winUtil = aWindow. |
michael@0 | 250 | QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
michael@0 | 251 | getInterface(Components.interfaces.nsIDOMWindowUtils); |
michael@0 | 252 | |
michael@0 | 253 | var ratio = winUtil.screenPixelsPerCSSPixel; |
michael@0 | 254 | |
michael@0 | 255 | // CSS pixels and ratio can be not integer. Device pixels are always integer. |
michael@0 | 256 | // Do our best and hope it works. |
michael@0 | 257 | return [ Math.round(aX * ratio), Math.round(aY * ratio), |
michael@0 | 258 | Math.round(aWidth * ratio), Math.round(aHeight * ratio) ]; |
michael@0 | 259 | } |