tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

layout.js (9788B)


      1 /* import-globals-from common.js */
      2 
      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);
     16 
     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);
     25 
     26  var grandChild = getChildAtPoint(aID, aX, aY, true);
     27  var expectedGrandChild = getAccessible(aGrandChildID);
     28 
     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);
     37 }
     38 
     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);
     47 
     48  var [x, y] = getBoundsForDOMElm(child);
     49 
     50  var actualChild = container.getChildAtPoint(x + 1, y + 1);
     51  isObject(
     52    actualChild,
     53    child,
     54    "Wrong direct child of " + prettyName(aContainerID)
     55  );
     56 
     57  var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1);
     58  isObject(
     59    actualGrandChild,
     60    grandChild,
     61    "Wrong deepest child of " + prettyName(aContainerID)
     62  );
     63 }
     64 
     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  );
     81 }
     82 
     83 /**
     84 * Zoom the given document.
     85 */
     86 function zoomDocument(aDocument, aZoom) {
     87  SpecialPowers.setFullZoom(aDocument.defaultView, aZoom);
     88 }
     89 
     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;
     96 
     97  windowUtils.setResolutionAndScaleTo(aZoom);
     98 }
     99 
    100 /**
    101 * Return child accessible at the given point.
    102 *
    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  }
    115 
    116  var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode);
    117 
    118  var x = screenX + aX;
    119  var y = screenY + aY;
    120 
    121  try {
    122    if (aFindDeepestChild) {
    123      return acc.getDeepestChildAtPoint(x, y);
    124    }
    125    return acc.getChildAtPoint(x, y);
    126  } catch (e) {}
    127 
    128  return null;
    129 }
    130 
    131 /**
    132 * Test the accessible position.
    133 */
    134 function testPos(aID, aPoint) {
    135  var [expectedX, expectedY] =
    136    aPoint != undefined ? aPoint : getBoundsForDOMElm(aID);
    137 
    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));
    141 }
    142 
    143 /**
    144 * Test the accessible boundaries.
    145 */
    146 function testBounds(aID, aRect) {
    147  var [expectedX, expectedY, expectedWidth, expectedHeight] =
    148    aRect != undefined ? aRect : getBoundsForDOMElm(aID);
    149 
    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));
    155 }
    156 
    157 /**
    158 * Test text position at the given offset.
    159 */
    160 function testTextPos(aID, aOffset, aPoint, aCoordOrigin) {
    161  var [expectedX, expectedY] = aPoint;
    162 
    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  );
    184 }
    185 
    186 /**
    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;
    191 
    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  );
    206 
    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  );
    219 
    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  );
    228 
    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  }
    247 
    248  // Height
    249  isWithin(
    250    expectedHeight,
    251    heightObj.value,
    252    1,
    253    `height of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
    254      `for ${prettyName(aID)}`
    255  );
    256 }
    257 
    258 /**
    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];
    267 }
    268 
    269 /**
    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);
    286 
    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  );
    312 
    313  return [x.value, y.value, width.value, height.value];
    314 }
    315 
    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];
    332 }
    333 
    334 /**
    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;
    343 
    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);
    349 
    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;
    355 
    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  }
    368 
    369  var elmWindow = elm.ownerGlobal;
    370  return CSSToDevicePixels(
    371    elmWindow,
    372    x + elmWindow.mozInnerScreenX,
    373    y + elmWindow.mozInnerScreenY,
    374    width,
    375    height
    376  );
    377 }
    378 
    379 function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) {
    380  var ratio = aWindow.devicePixelRatio;
    381 
    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  ];
    390 }