tor-browser

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

get-char-advances.js (2121B)


      1 'use strict';
      2 
      3 /**
      4 * Returns an array of advances for all characters in the descendants
      5 * of the specified element.
      6 *
      7 * Technically speaking, advances and glyph bounding boxes are different things,
      8 * and advances are not exposed. This function computes approximate values from
      9 * bounding boxes.
     10 */
     11 function getCharAdvances(element) {
     12  const style = getComputedStyle(element);
     13  const is_vertical = style.writingMode.startsWith('vertical');
     14  const range = document.createRange();
     15  const all_bounds = []
     16 
     17  function walk(element) {
     18    for (const node of element.childNodes) {
     19      const nodeType = node.nodeType;
     20      if (nodeType === Node.TEXT_NODE) {
     21        const text = node.nodeValue;
     22        for (let i = 0; i < text.length; ++i) {
     23          range.setStart(node, i);
     24          range.setEnd(node, i + 1);
     25          let bounds = range.getBoundingClientRect();
     26          // Transpose if it's in vertical flow. Guarantee that top < bottom
     27          // and left < right are always true.
     28          if (is_vertical) {
     29            bounds = {
     30              left: bounds.top,
     31              top: bounds.left,
     32              right: bounds.bottom,
     33              bottom: bounds.right
     34            };
     35          }
     36          all_bounds.push(bounds);
     37        }
     38      } else if (nodeType === Node.ELEMENT_NODE) {
     39        walk(node);
     40      }
     41    }
     42  }
     43  walk(element);
     44  all_bounds.sort(function(bound_a, bound_b) {
     45    if (bound_a.bottom <= bound_b.top) {
     46      return -1;
     47    }
     48    if (bound_b.bottom <= bound_a.top) {
     49      return 1;
     50    }
     51    return bound_a.left - bound_b.left;
     52  });
     53  let origin = undefined;
     54  let blockEnd = -1;
     55  const advances = [];
     56  for (let bounds of all_bounds) {
     57    // Check if this is on the same line.
     58    if (bounds.top >= blockEnd) {
     59      origin = undefined;
     60      blockEnd = bounds.bottom;
     61    }
     62    // For the first character, the left bound is closest to the origin.
     63    if (origin === undefined)
     64      origin = bounds.left;
     65    // The right bound is a good approximation of the next origin.
     66    advances.push(bounds.right - origin);
     67    origin = bounds.right;
     68  }
     69  return advances;
     70 }