tor-browser

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

browser_text_basics.js (12004B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 function testRangeAtMarker(macDoc, marker, attribute, expected, msg) {
      8  let range = macDoc.getParameterizedAttributeValue(attribute, marker);
      9  is(stringForRange(macDoc, range), expected, msg);
     10 }
     11 
     12 function testUIElement(
     13  macDoc,
     14  marker,
     15  msg,
     16  expectedRole,
     17  expectedValue,
     18  expectedRange
     19 ) {
     20  let elem = macDoc.getParameterizedAttributeValue(
     21    "AXUIElementForTextMarker",
     22    marker
     23  );
     24  is(
     25    elem.getAttributeValue("AXRole"),
     26    expectedRole,
     27    `${msg}: element role matches`
     28  );
     29  is(elem.getAttributeValue("AXValue"), expectedValue, `${msg}: element value`);
     30  let elemRange = macDoc.getParameterizedAttributeValue(
     31    "AXTextMarkerRangeForUIElement",
     32    elem
     33  );
     34  is(
     35    stringForRange(macDoc, elemRange),
     36    expectedRange,
     37    `${msg}: element range matches element value`
     38  );
     39 }
     40 
     41 function testStyleRun(macDoc, marker, msg, expectedStyleRun) {
     42  testRangeAtMarker(
     43    macDoc,
     44    marker,
     45    "AXStyleTextMarkerRangeForTextMarker",
     46    expectedStyleRun,
     47    `${msg}: style run matches`
     48  );
     49 }
     50 
     51 function testParagraph(macDoc, marker, msg, expectedParagraph) {
     52  testRangeAtMarker(
     53    macDoc,
     54    marker,
     55    "AXParagraphTextMarkerRangeForTextMarker",
     56    expectedParagraph,
     57    `${msg}: paragraph matches`
     58  );
     59 }
     60 
     61 function testWords(macDoc, marker, msg, expectedLeft, expectedRight) {
     62  testRangeAtMarker(
     63    macDoc,
     64    marker,
     65    "AXLeftWordTextMarkerRangeForTextMarker",
     66    expectedLeft,
     67    `${msg}: left word matches`
     68  );
     69 
     70  testRangeAtMarker(
     71    macDoc,
     72    marker,
     73    "AXRightWordTextMarkerRangeForTextMarker",
     74    expectedRight,
     75    `${msg}: right word matches`
     76  );
     77 }
     78 
     79 function testLines(
     80  macDoc,
     81  marker,
     82  msg,
     83  expectedLine,
     84  expectedLeft,
     85  expectedRight
     86 ) {
     87  testRangeAtMarker(
     88    macDoc,
     89    marker,
     90    "AXLineTextMarkerRangeForTextMarker",
     91    expectedLine,
     92    `${msg}: line matches`
     93  );
     94 
     95  testRangeAtMarker(
     96    macDoc,
     97    marker,
     98    "AXLeftLineTextMarkerRangeForTextMarker",
     99    expectedLeft,
    100    `${msg}: left line matches`
    101  );
    102 
    103  testRangeAtMarker(
    104    macDoc,
    105    marker,
    106    "AXRightLineTextMarkerRangeForTextMarker",
    107    expectedRight,
    108    `${msg}: right line matches`
    109  );
    110 }
    111 
    112 function* markerIterator(macDoc, reverse = false) {
    113  let m = macDoc.getAttributeValue(
    114    reverse ? "AXEndTextMarker" : "AXStartTextMarker"
    115  );
    116  let c = 0;
    117  while (m) {
    118    yield [m, c++];
    119    m = macDoc.getParameterizedAttributeValue(
    120      reverse
    121        ? "AXPreviousTextMarkerForTextMarker"
    122        : "AXNextTextMarkerForTextMarker",
    123      m
    124    );
    125  }
    126 }
    127 
    128 // Tests consistency in text markers between:
    129 // 1. "Linked list" forward navagation
    130 // 2. Getting markers by index
    131 // 3. "Linked list" reverse navagation
    132 // For each iteration method check that the returned index is consistent
    133 function testMarkerIntegrity(accDoc, expectedMarkerValues) {
    134  let macDoc = accDoc.nativeInterface.QueryInterface(
    135    Ci.nsIAccessibleMacInterface
    136  );
    137 
    138  // Iterate forward with "AXNextTextMarkerForTextMarker"
    139  let prevMarker;
    140  let count = 0;
    141  for (let [marker, index] of markerIterator(macDoc)) {
    142    count++;
    143    let markerIndex = macDoc.getParameterizedAttributeValue(
    144      "AXIndexForTextMarker",
    145      marker
    146    );
    147    is(
    148      markerIndex,
    149      index,
    150      `Correct index in "AXNextTextMarkerForTextMarker": ${index}`
    151    );
    152    if (prevMarker) {
    153      let range = macDoc.getParameterizedAttributeValue(
    154        "AXTextMarkerRangeForUnorderedTextMarkers",
    155        [prevMarker, marker]
    156      );
    157      is(
    158        macDoc.getParameterizedAttributeValue(
    159          "AXLengthForTextMarkerRange",
    160          range
    161        ),
    162        1,
    163        `[${index}] marker moved one character`
    164      );
    165    }
    166    prevMarker = marker;
    167 
    168    testWords(
    169      macDoc,
    170      marker,
    171      `At index ${index}`,
    172      ...expectedMarkerValues[index].words
    173    );
    174    testLines(
    175      macDoc,
    176      marker,
    177      `At index ${index}`,
    178      ...expectedMarkerValues[index].lines
    179    );
    180    testUIElement(
    181      macDoc,
    182      marker,
    183      `At index ${index}`,
    184      ...expectedMarkerValues[index].element
    185    );
    186    testParagraph(
    187      macDoc,
    188      marker,
    189      `At index ${index}`,
    190      expectedMarkerValues[index].paragraph
    191    );
    192    testStyleRun(
    193      macDoc,
    194      marker,
    195      `At index ${index}`,
    196      expectedMarkerValues[index].style
    197    );
    198  }
    199 
    200  is(expectedMarkerValues.length, count, `Correct marker count: ${count}`);
    201 
    202  // Use "AXTextMarkerForIndex" to retrieve all text markers
    203  for (let i = 0; i < count; i++) {
    204    let marker = macDoc.getParameterizedAttributeValue(
    205      "AXTextMarkerForIndex",
    206      i
    207    );
    208    let index = macDoc.getParameterizedAttributeValue(
    209      "AXIndexForTextMarker",
    210      marker
    211    );
    212    is(index, i, `Correct index in "AXTextMarkerForIndex": ${i}`);
    213 
    214    if (i == count - 1) {
    215      ok(
    216        !macDoc.getParameterizedAttributeValue(
    217          "AXNextTextMarkerForTextMarker",
    218          marker
    219        ),
    220        "Iterated through all markers"
    221      );
    222    }
    223  }
    224 
    225  count = expectedMarkerValues.length;
    226 
    227  // Iterate backward with "AXPreviousTextMarkerForTextMarker"
    228  for (let [marker] of markerIterator(macDoc, true)) {
    229    if (count <= 0) {
    230      ok(false, "Exceeding marker count");
    231      break;
    232    }
    233    count--;
    234    let index = macDoc.getParameterizedAttributeValue(
    235      "AXIndexForTextMarker",
    236      marker
    237    );
    238    is(
    239      index,
    240      count,
    241      `Correct index in "AXPreviousTextMarkerForTextMarker": ${count}`
    242    );
    243  }
    244 
    245  is(count, 0, "Iterated backward through all text markers");
    246 }
    247 
    248 // Run tests with old word segmenter
    249 addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => {
    250  await SpecialPowers.pushPrefEnv({
    251    set: [
    252      ["intl.icu4x.segmenter.enabled", false],
    253      ["layout.word_select.stop_at_punctuation", true], // This is default
    254    ],
    255  });
    256 
    257  const expectedValues = await SpecialPowers.spawn(browser, [], async () => {
    258    return content.wrappedJSObject.getExpected(false, true);
    259  });
    260 
    261  testMarkerIntegrity(accDoc, expectedValues);
    262 
    263  await SpecialPowers.popPrefEnv();
    264 });
    265 
    266 // new UAX#14 segmenter without stop_at_punctuation.
    267 addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => {
    268  await SpecialPowers.pushPrefEnv({
    269    set: [
    270      ["intl.icu4x.segmenter.enabled", true],
    271      ["layout.word_select.stop_at_punctuation", false],
    272    ],
    273  });
    274 
    275  const expectedValues = await SpecialPowers.spawn(browser, [], async () => {
    276    return content.wrappedJSObject.getExpected(true, false);
    277  });
    278 
    279  testMarkerIntegrity(accDoc, expectedValues);
    280 
    281  await SpecialPowers.popPrefEnv();
    282 });
    283 
    284 // new UAX#14 segmenter with stop_at_punctuation
    285 addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => {
    286  await SpecialPowers.pushPrefEnv({
    287    set: [
    288      ["intl.icu4x.segmenter.enabled", true],
    289      ["layout.word_select.stop_at_punctuation", true], // this is default
    290    ],
    291  });
    292 
    293  const expectedValues = await SpecialPowers.spawn(browser, [], async () => {
    294    return content.wrappedJSObject.getExpected(true, true);
    295  });
    296 
    297  testMarkerIntegrity(accDoc, expectedValues);
    298 
    299  await SpecialPowers.popPrefEnv();
    300 });
    301 
    302 // Test text marker lesser-than operator
    303 addAccessibleTask(
    304  `<p id="p">hello <a id="a" href="#">goodbye</a> world</p>`,
    305  async (browser, accDoc) => {
    306    let macDoc = accDoc.nativeInterface.QueryInterface(
    307      Ci.nsIAccessibleMacInterface
    308    );
    309 
    310    let start = macDoc.getParameterizedAttributeValue(
    311      "AXTextMarkerForIndex",
    312      1
    313    );
    314    let end = macDoc.getParameterizedAttributeValue("AXTextMarkerForIndex", 10);
    315 
    316    let range = macDoc.getParameterizedAttributeValue(
    317      "AXTextMarkerRangeForUnorderedTextMarkers",
    318      [end, start]
    319    );
    320    is(stringForRange(macDoc, range), "ello good");
    321  }
    322 );
    323 
    324 addAccessibleTask(
    325  `<input id="input" value=""><a href="#">goodbye</a>`,
    326  async (browser, accDoc) => {
    327    let macDoc = accDoc.nativeInterface.QueryInterface(
    328      Ci.nsIAccessibleMacInterface
    329    );
    330 
    331    let input = getNativeInterface(accDoc, "input");
    332 
    333    let range = macDoc.getParameterizedAttributeValue(
    334      "AXTextMarkerRangeForUIElement",
    335      input
    336    );
    337 
    338    is(stringForRange(macDoc, range), "", "string value is correct");
    339  }
    340 );
    341 
    342 addAccessibleTask(
    343  `<div role="listbox" id="box">
    344    <input type="radio" name="test" role="option" title="First item"/>
    345    <input type="radio" name="test" role="option" title="Second item"/>
    346  </div>`,
    347  async (browser, accDoc) => {
    348    let box = getNativeInterface(accDoc, "box");
    349    const children = box.getAttributeValue("AXChildren");
    350    is(children.length, 2, "Listbox contains two items");
    351    is(children[0].getAttributeValue("AXValue"), "First item");
    352    is(children[1].getAttributeValue("AXValue"), "Second item");
    353  }
    354 );
    355 
    356 addAccessibleTask(
    357  `<div id="t">
    358    A link <b>should</b> explain <u>clearly</u> what information the <i>reader</i> will get by clicking on that link.
    359  </div>`,
    360  async (browser, accDoc) => {
    361    let t = getNativeInterface(accDoc, "t");
    362    const children = t.getAttributeValue("AXChildren");
    363    const expectedTitles = [
    364      "A link ",
    365      "should",
    366      " explain ",
    367      "clearly",
    368      " what information the ",
    369      "reader",
    370      " will get by clicking on that link. ",
    371    ];
    372    is(children.length, 7, "container has seven children");
    373    children.forEach((child, index) => {
    374      is(child.getAttributeValue("AXValue"), expectedTitles[index]);
    375    });
    376  }
    377 );
    378 
    379 addAccessibleTask(
    380  `<a href="#">link</a> <input id="input" value="hello">`,
    381  async (browser, accDoc) => {
    382    let macDoc = accDoc.nativeInterface.QueryInterface(
    383      Ci.nsIAccessibleMacInterface
    384    );
    385 
    386    let input = getNativeInterface(accDoc, "input");
    387    let range = macDoc.getParameterizedAttributeValue(
    388      "AXTextMarkerRangeForUIElement",
    389      input
    390    );
    391 
    392    let firstMarkerInInput = macDoc.getParameterizedAttributeValue(
    393      "AXStartTextMarkerForTextMarkerRange",
    394      range
    395    );
    396 
    397    let leftWordRange = macDoc.getParameterizedAttributeValue(
    398      "AXLeftWordTextMarkerRangeForTextMarker",
    399      firstMarkerInInput
    400    );
    401    let str = macDoc.getParameterizedAttributeValue(
    402      "AXStringForTextMarkerRange",
    403      leftWordRange
    404    );
    405    is(str, "hello", "Left word at start of input should be right word");
    406  }
    407 );
    408 
    409 addAccessibleTask(`<p id="p">hello world</p>`, async (browser, accDoc) => {
    410  let macDoc = accDoc.nativeInterface.QueryInterface(
    411    Ci.nsIAccessibleMacInterface
    412  );
    413 
    414  let p = getNativeInterface(accDoc, "p");
    415  let range = macDoc.getParameterizedAttributeValue(
    416    "AXTextMarkerRangeForUIElement",
    417    p
    418  );
    419 
    420  let bounds = macDoc.getParameterizedAttributeValue(
    421    "AXBoundsForTextMarkerRange",
    422    range
    423  );
    424 
    425  ok(bounds.origin && bounds.size, "Returned valid bounds");
    426 
    427  // Test bounds of collapsed range.
    428 
    429  let marker = macDoc.getParameterizedAttributeValue(
    430    "AXStartTextMarkerForTextMarkerRange",
    431    range
    432  );
    433 
    434  let collapsedRange = macDoc.getParameterizedAttributeValue(
    435    "AXTextMarkerRangeForUnorderedTextMarkers",
    436    [marker, marker]
    437  );
    438 
    439  let collapsedBounds = macDoc.getParameterizedAttributeValue(
    440    "AXBoundsForTextMarkerRange",
    441    collapsedRange
    442  );
    443 
    444  ok(
    445    collapsedBounds.origin && collapsedBounds.size,
    446    "Returned valid collapsed bounds"
    447  );
    448 
    449  let nextMarker = macDoc.getParameterizedAttributeValue(
    450    "AXNextTextMarkerForTextMarker",
    451    marker
    452  );
    453 
    454  range = macDoc.getParameterizedAttributeValue(
    455    "AXTextMarkerRangeForUnorderedTextMarkers",
    456    [marker, nextMarker]
    457  );
    458 
    459  is(stringForRange(macDoc, range), "h", "range is first letter");
    460 
    461  bounds = macDoc.getParameterizedAttributeValue(
    462    "AXBoundsForTextMarkerRange",
    463    range
    464  );
    465 
    466  Assert.less(
    467    collapsedBounds.size[0],
    468    bounds.size[0],
    469    "Collapsed range is smaller than character range"
    470  );
    471 });