tor-browser

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

browser_webconsole_bidi_string_isolation.js (3499B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const TEST_URI = "data:text/html;charset=utf8,<!DOCTYPE html>Bidi strings";
      7 const rtlOverride = "\u202e";
      8 
      9 add_task(async function () {
     10  const hud = await openNewTabAndConsole(TEST_URI);
     11  const browser = gBrowser.selectedBrowser;
     12 
     13  /* eslint-disable-next-line no-shadow */
     14  await SpecialPowers.spawn(browser, [rtlOverride], rtlOverride => {
     15    const { console } = content.wrappedJSObject;
     16 
     17    console.log(Symbol(rtlOverride + "msg01"));
     18    console.log([rtlOverride + "msg02"]);
     19    console.log({ p: rtlOverride + "msg03" });
     20    console.log({ [rtlOverride + "msg04"]: null });
     21    console.log(new Set([rtlOverride + "msg05"]));
     22    console.log(new Map([[rtlOverride + "msg06", null]]));
     23    console.log(new Map([[null, rtlOverride + "msg07"]]));
     24 
     25    const parser = content.document.createElement("div");
     26    parser.innerHTML = `
     27      <div data-test="${rtlOverride}msg08"></div>
     28      <div data-${rtlOverride}="msg09"></div>
     29      <div-${rtlOverride} msg10></div-${rtlOverride}>
     30    `;
     31    for (const child of parser.children) {
     32      console.log(child);
     33    }
     34  });
     35 
     36  const texts = [
     37    `Symbol("${rtlOverride}msg01")`,
     38    `Array [ "${rtlOverride}msg02" ]`,
     39    `Object { p: "${rtlOverride}msg03" }`,
     40    `Object { "${rtlOverride}msg04": null }`,
     41    `Set [ "${rtlOverride}msg05" ]`,
     42    `Map { "${rtlOverride}msg06" → null }`,
     43    `Map { null → "${rtlOverride}msg07" }`,
     44    `<div data-test="${rtlOverride}msg08">`,
     45    `<div data-${rtlOverride}="msg09">`,
     46    `<div-${rtlOverride} msg10="">`,
     47  ];
     48  for (let i = 0; i < texts.length; ++i) {
     49    const msgId = "msg" + String(i + 1).padStart(2, "0");
     50    const message = await waitFor(() => findConsoleAPIMessage(hud, msgId));
     51    const objectBox = message.querySelector(".objectBox");
     52    is(objectBox.textContent, texts[i], "Should have all the relevant text");
     53    checkRects(objectBox);
     54  }
     55 });
     56 
     57 function getBoundingClientRect(node) {
     58  if (node.nodeType === Node.ELEMENT_NODE) {
     59    return node.getBoundingClientRect();
     60  }
     61  // There is no Node.getBoundingClientRect, use a Range instead.
     62  const range = document.createRange();
     63  range.selectNode(node);
     64  return range.getBoundingClientRect();
     65 }
     66 
     67 /**
     68 * The console prints data build from external strings. They can contain
     69 * characters that change the directionality of the text. For example, RTL
     70 * characters will flow right to left. However, this should be isolated to
     71 * prevent one string from mangling how another one is rendered.
     72 * This function uses getBoundingClientRect() to check that the nodes, as a
     73 * whole, flow LTR (even if the characters in the node flow RTL).
     74 * The bidi algorithm happens at layout time, so we need to check the rects,
     75 * DOM operations like textContent would be useless.
     76 */
     77 function checkRects(node, parentRect = getBoundingClientRect(node)) {
     78  let prevRect;
     79  for (const child of node.childNodes) {
     80    const rect = getBoundingClientRect(child);
     81    Assert.greaterOrEqual(
     82      rect.x,
     83      parentRect.x,
     84      "Rect should start inside parent"
     85    );
     86    Assert.lessOrEqual(
     87      rect.x + rect.width,
     88      parentRect.x + parentRect.width,
     89      "Rect should end inside parent"
     90    );
     91    if (prevRect) {
     92      Assert.greaterOrEqual(
     93        rect.x,
     94        prevRect.x + prevRect.width,
     95        "Rect should start after previous one"
     96      );
     97    }
     98    prevRect = rect;
     99    checkRects(child, rect);
    100  }
    101 }