summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/Layout.sys.mjs
blob: 15b0060717a40be9210b99a18310f0115156fba1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { Assert } from "resource://testing-common/Assert.sys.mjs";

import { CommonUtils } from "chrome://mochitests/content/browser/accessible/tests/browser/Common.sys.mjs";

export const Layout = {
  /**
   * Zoom the given document.
   */
  zoomDocument(doc, zoom) {
    const bc = BrowsingContext.getFromWindow(doc.defaultView);
    // To mirror the behaviour of the UI, we set the zoom
    // value on the top level browsing context. This value automatically
    // propagates down to iframes.
    bc.top.fullZoom = zoom;
  },

  /**
   * Set the relative resolution of this document. This is what apz does.
   * On non-mobile platforms you won't see a visible change.
   */
  setResolution(doc, zoom) {
    const windowUtils = doc.defaultView.windowUtils;
    windowUtils.setResolutionAndScaleTo(zoom);
  },

  /**
   * Assert.is() function checking the expected value is within the range.
   */
  isWithin(expected, got, within, msg) {
    if (Math.abs(got - expected) <= within) {
      Assert.ok(true, `${msg} - Got ${got}`);
    } else {
      Assert.ok(
        false,
        `${msg} - Got ${got}, expected ${expected} with error of ${within}`
      );
    }
  },

  /**
   * Return the accessible coordinates relative to the screen in device pixels.
   */
  getPos(id) {
    const accessible = CommonUtils.getAccessible(id);
    const x = {};
    const y = {};
    accessible.getBounds(x, y, {}, {});

    return [x.value, y.value];
  },

  /**
   * Return the accessible coordinates and size relative to the screen in device
   * pixels. This methods also retrieves coordinates in CSS pixels and ensures that they
   * match Dev pixels with a given device pixel ratio.
   */
  getBounds(id, dpr) {
    const accessible = CommonUtils.getAccessible(id);
    const x = {};
    const y = {};
    const width = {};
    const height = {};
    const xInCSS = {};
    const yInCSS = {};
    const widthInCSS = {};
    const heightInCSS = {};
    accessible.getBounds(x, y, width, height);
    accessible.getBoundsInCSSPixels(xInCSS, yInCSS, widthInCSS, heightInCSS);

    this.isWithin(
      x.value / dpr,
      xInCSS.value,
      1,
      "X in CSS pixels is calculated correctly"
    );
    this.isWithin(
      y.value / dpr,
      yInCSS.value,
      1,
      "Y in CSS pixels is calculated correctly"
    );
    this.isWithin(
      width.value / dpr,
      widthInCSS.value,
      1,
      "Width in CSS pixels is calculated correctly"
    );
    this.isWithin(
      height.value / dpr,
      heightInCSS.value,
      1,
      "Height in CSS pixels is calculated correctly"
    );

    return [x.value, y.value, width.value, height.value];
  },

  getRangeExtents(id, startOffset, endOffset, coordOrigin) {
    const hyperText = CommonUtils.getAccessible(id, [Ci.nsIAccessibleText]);
    const x = {};
    const y = {};
    const width = {};
    const height = {};
    hyperText.getRangeExtents(
      startOffset,
      endOffset,
      x,
      y,
      width,
      height,
      coordOrigin
    );

    return [x.value, y.value, width.value, height.value];
  },

  CSSToDevicePixels(win, x, y, width, height) {
    const ratio = win.devicePixelRatio;

    // CSS pixels and ratio can be not integer. Device pixels are always integer.
    // Do our best and hope it works.
    return [
      Math.round(x * ratio),
      Math.round(y * ratio),
      Math.round(width * ratio),
      Math.round(height * ratio),
    ];
  },

  /**
   * Return DOM node coordinates relative the screen and its size in device
   * pixels.
   */
  getBoundsForDOMElm(id, doc) {
    let x = 0;
    let y = 0;
    let width = 0;
    let height = 0;

    const elm = CommonUtils.getNode(id, doc);
    const elmWindow = elm.ownerGlobal;
    if (elm.localName == "area") {
      const mapName = elm.parentNode.getAttribute("name");
      const selector = `[usemap="#${mapName}"]`;
      const img = elm.ownerDocument.querySelector(selector);

      const areaCoords = elm.coords.split(",");
      const areaX = parseInt(areaCoords[0], 10);
      const areaY = parseInt(areaCoords[1], 10);
      const areaWidth = parseInt(areaCoords[2], 10) - areaX;
      const areaHeight = parseInt(areaCoords[3], 10) - areaY;

      const rect = img.getBoundingClientRect();
      x = rect.left + areaX;
      y = rect.top + areaY;
      width = areaWidth;
      height = areaHeight;
    } else {
      const rect = elm.getBoundingClientRect();
      x = rect.left;
      y = rect.top;
      width = rect.width;
      height = rect.height;
    }

    return this.CSSToDevicePixels(
      elmWindow,
      x + elmWindow.mozInnerScreenX,
      y + elmWindow.mozInnerScreenY,
      width,
      height
    );
  },
};