no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / accessible / tests / mochitest / layout.js
blob1467d5fe7fa88032d262a88f2e5a9779aff9d075
1 /* import-globals-from common.js */
3 /**
4  * Tests if the given child and grand child accessibles at the given point are
5  * expected.
6  *
7  * @param aID            [in] accessible identifier
8  * @param aX             [in] x coordinate of the point relative accessible
9  * @param aY             [in] y coordinate of the point relative accessible
10  * @param aChildID       [in] expected child accessible
11  * @param aGrandChildID  [in] expected child accessible
12  */
13 function testChildAtPoint(aID, aX, aY, aChildID, aGrandChildID) {
14   var child = getChildAtPoint(aID, aX, aY, false);
15   var expectedChild = getAccessible(aChildID);
17   var msg =
18     "Wrong direct child accessible at the point (" +
19     aX +
20     ", " +
21     aY +
22     ") of " +
23     prettyName(aID);
24   isObject(child, expectedChild, msg);
26   var grandChild = getChildAtPoint(aID, aX, aY, true);
27   var expectedGrandChild = getAccessible(aGrandChildID);
29   msg =
30     "Wrong deepest child accessible at the point (" +
31     aX +
32     ", " +
33     aY +
34     ") of " +
35     prettyName(aID);
36   isObject(grandChild, expectedGrandChild, msg);
39 /**
40  * Test if getChildAtPoint returns the given child and grand child accessibles
41  * at coordinates of child accessible (direct and deep hit test).
42  */
43 function hitTest(aContainerID, aChildID, aGrandChildID) {
44   var container = getAccessible(aContainerID);
45   var child = getAccessible(aChildID);
46   var grandChild = getAccessible(aGrandChildID);
48   var [x, y] = getBoundsForDOMElm(child);
50   var actualChild = container.getChildAtPoint(x + 1, y + 1);
51   isObject(
52     actualChild,
53     child,
54     "Wrong direct child of " + prettyName(aContainerID)
55   );
57   var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1);
58   isObject(
59     actualGrandChild,
60     grandChild,
61     "Wrong deepest child of " + prettyName(aContainerID)
62   );
65 /**
66  * Test if getOffsetAtPoint returns the given text offset at given coordinates.
67  */
68 function testOffsetAtPoint(aHyperTextID, aX, aY, aCoordType, aExpectedOffset) {
69   var hyperText = getAccessible(aHyperTextID, [nsIAccessibleText]);
70   var offset = hyperText.getOffsetAtPoint(aX, aY, aCoordType);
71   is(
72     offset,
73     aExpectedOffset,
74     "Wrong offset at given point (" +
75       aX +
76       ", " +
77       aY +
78       ") for " +
79       prettyName(aHyperTextID)
80   );
83 /**
84  * Zoom the given document.
85  */
86 function zoomDocument(aDocument, aZoom) {
87   SpecialPowers.setFullZoom(aDocument.defaultView, aZoom);
90 /**
91  * Set the relative resolution of this document. This is what apz does.
92  * On non-mobile platforms you won't see a visible change.
93  */
94 function setResolution(aDocument, aZoom) {
95   var windowUtils = aDocument.defaultView.windowUtils;
97   windowUtils.setResolutionAndScaleTo(aZoom);
101  * Return child accessible at the given point.
103  * @param aIdentifier        [in] accessible identifier
104  * @param aX                 [in] x coordinate of the point relative accessible
105  * @param aY                 [in] y coordinate of the point relative accessible
106  * @param aFindDeepestChild  [in] points whether deepest or nearest child should
107  *                           be returned
108  * @return                   the child accessible at the given point
109  */
110 function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
111   var acc = getAccessible(aIdentifier);
112   if (!acc) {
113     return null;
114   }
116   var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode);
118   var x = screenX + aX;
119   var y = screenY + aY;
121   try {
122     if (aFindDeepestChild) {
123       return acc.getDeepestChildAtPoint(x, y);
124     }
125     return acc.getChildAtPoint(x, y);
126   } catch (e) {}
128   return null;
132  * Test the accessible position.
133  */
134 function testPos(aID, aPoint) {
135   var [expectedX, expectedY] =
136     aPoint != undefined ? aPoint : getBoundsForDOMElm(aID);
138   var [x, y] = getBounds(aID);
139   is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
140   is(y, expectedY, "Wrong y coordinate of " + prettyName(aID));
144  * Test the accessible boundaries.
145  */
146 function testBounds(aID, aRect) {
147   var [expectedX, expectedY, expectedWidth, expectedHeight] =
148     aRect != undefined ? aRect : getBoundsForDOMElm(aID);
150   var [x, y, width, height] = getBounds(aID);
151   is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
152   is(y, expectedY, "Wrong y coordinate of " + prettyName(aID));
153   is(width, expectedWidth, "Wrong width of " + prettyName(aID));
154   is(height, expectedHeight, "Wrong height of " + prettyName(aID));
158  * Test text position at the given offset.
159  */
160 function testTextPos(aID, aOffset, aPoint, aCoordOrigin) {
161   var [expectedX, expectedY] = aPoint;
163   var xObj = {},
164     yObj = {};
165   var hyperText = getAccessible(aID, [nsIAccessibleText]);
166   hyperText.getCharacterExtents(aOffset, xObj, yObj, {}, {}, aCoordOrigin);
167   is(
168     xObj.value,
169     expectedX,
170     "Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID)
171   );
172   ok(
173     yObj.value - expectedY <= 2 && expectedY - yObj.value <= 2,
174     "Wrong y coordinate at offset " +
175       aOffset +
176       " for " +
177       prettyName(aID) +
178       " - got " +
179       yObj.value +
180       ", expected " +
181       expectedY +
182       "The difference doesn't exceed 1."
183   );
187  * Test text bounds that is enclosed betwene the given offsets.
188  */
189 function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) {
190   var [expectedX, expectedY, expectedWidth, expectedHeight] = aRect;
192   var xObj = {},
193     yObj = {},
194     widthObj = {},
195     heightObj = {};
196   var hyperText = getAccessible(aID, [nsIAccessibleText]);
197   hyperText.getRangeExtents(
198     aStartOffset,
199     aEndOffset,
200     xObj,
201     yObj,
202     widthObj,
203     heightObj,
204     aCoordOrigin
205   );
207   // x
208   isWithin(
209     expectedX,
210     xObj.value,
211     1,
212     "Wrong x coordinate of text between offsets (" +
213       aStartOffset +
214       ", " +
215       aEndOffset +
216       ") for " +
217       prettyName(aID)
218   );
220   // y
221   isWithin(
222     expectedY,
223     yObj.value,
224     1,
225     `y coord of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
226       `for ${prettyName(aID)}`
227   );
229   // Width
230   var msg =
231     "Wrong width of text between offsets (" +
232     aStartOffset +
233     ", " +
234     aEndOffset +
235     ") for " +
236     prettyName(aID) +
237     " - Got " +
238     widthObj.value +
239     " Expected " +
240     expectedWidth;
241   if (!WIN) {
242     isWithin(expectedWidth, widthObj.value, 1, msg);
243   } else {
244     // fails on some windows machines
245     todo(false, msg);
246   }
248   // Height
249   isWithin(
250     expectedHeight,
251     heightObj.value,
252     1,
253     `height of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
254       `for ${prettyName(aID)}`
255   );
259  * Return the accessible coordinates relative to the screen in device pixels.
260  */
261 function getPos(aID) {
262   var accessible = getAccessible(aID);
263   var x = {},
264     y = {};
265   accessible.getBounds(x, y, {}, {});
266   return [x.value, y.value];
270  * Return the accessible coordinates and size relative to the screen in device
271  * pixels. This methods also retrieves coordinates in CSS pixels and ensures that they
272  * match Dev pixels with a given device pixel ratio.
273  */
274 function getBounds(aID, aDPR = window.devicePixelRatio) {
275   const accessible = getAccessible(aID);
276   let x = {},
277     y = {},
278     width = {},
279     height = {};
280   let xInCSS = {},
281     yInCSS = {},
282     widthInCSS = {},
283     heightInCSS = {};
284   accessible.getBounds(x, y, width, height);
285   accessible.getBoundsInCSSPixels(xInCSS, yInCSS, widthInCSS, heightInCSS);
287   info(`DPR is: ${aDPR}`);
288   isWithin(
289     xInCSS.value,
290     x.value / aDPR,
291     1,
292     "X in CSS pixels is calculated correctly"
293   );
294   isWithin(
295     yInCSS.value,
296     y.value / aDPR,
297     1,
298     "Y in CSS pixels is calculated correctly"
299   );
300   isWithin(
301     widthInCSS.value,
302     width.value / aDPR,
303     1,
304     "Width in CSS pixels is calculated correctly"
305   );
306   isWithin(
307     heightInCSS.value,
308     height.value / aDPR,
309     1,
310     "Height in CSS pixels is calculated correctly"
311   );
313   return [x.value, y.value, width.value, height.value];
316 function getRangeExtents(aID, aStartOffset, aEndOffset, aCoordOrigin) {
317   var hyperText = getAccessible(aID, [nsIAccessibleText]);
318   var x = {},
319     y = {},
320     width = {},
321     height = {};
322   hyperText.getRangeExtents(
323     aStartOffset,
324     aEndOffset,
325     x,
326     y,
327     width,
328     height,
329     aCoordOrigin
330   );
331   return [x.value, y.value, width.value, height.value];
335  * Return DOM node coordinates relative the screen and its size in device
336  * pixels.
337  */
338 function getBoundsForDOMElm(aID) {
339   var x = 0,
340     y = 0,
341     width = 0,
342     height = 0;
344   var elm = getNode(aID);
345   if (elm.localName == "area") {
346     var mapName = elm.parentNode.getAttribute("name");
347     var selector = "[usemap='#" + mapName + "']";
348     var img = elm.ownerDocument.querySelector(selector);
350     var areaCoords = elm.coords.split(",");
351     var areaX = parseInt(areaCoords[0]);
352     var areaY = parseInt(areaCoords[1]);
353     var areaWidth = parseInt(areaCoords[2]) - areaX;
354     var areaHeight = parseInt(areaCoords[3]) - areaY;
356     let rect = img.getBoundingClientRect();
357     x = rect.left + areaX;
358     y = rect.top + areaY;
359     width = areaWidth;
360     height = areaHeight;
361   } else {
362     let rect = elm.getBoundingClientRect();
363     x = rect.left;
364     y = rect.top;
365     width = rect.width;
366     height = rect.height;
367   }
369   var elmWindow = elm.ownerGlobal;
370   return CSSToDevicePixels(
371     elmWindow,
372     x + elmWindow.mozInnerScreenX,
373     y + elmWindow.mozInnerScreenY,
374     width,
375     height
376   );
379 function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) {
380   var ratio = aWindow.devicePixelRatio;
382   // CSS pixels and ratio can be not integer. Device pixels are always integer.
383   // Do our best and hope it works.
384   return [
385     Math.round(aX * ratio),
386     Math.round(aY * ratio),
387     Math.round(aWidth * ratio),
388     Math.round(aHeight * ratio),
389   ];