tor-browser

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

fonts.js (3616B)


      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 loader.lazyRequireGetter(
      8  this,
      9  "loadSheet",
     10  "resource://devtools/shared/layout/utils.js",
     11  true
     12 );
     13 loader.lazyRequireGetter(
     14  this,
     15  "removeSheet",
     16  "resource://devtools/shared/layout/utils.js",
     17  true
     18 );
     19 
     20 // How many text runs are we highlighting at a time. There may be many text runs, and we
     21 // want to prevent performance problems.
     22 const MAX_TEXT_RANGES = 100;
     23 
     24 // This stylesheet is inserted into the page to customize the color of the selected text
     25 // runs.
     26 // Note that this color is defined as --highlighter-content-color in the highlighters.css
     27 // file, and corresponds to the box-model content color. We want to give it an opacity of
     28 // 0.6 here.
     29 const STYLESHEET_URI =
     30  "data:text/css," +
     31  encodeURIComponent(
     32    "::selection{background-color:hsl(197,71%,73%,.6)!important;}"
     33  );
     34 
     35 /**
     36 * This highlighter highlights runs of text in the page that have been rendered given a
     37 * certain font. The highlighting is done with window selection ranges, so no extra
     38 * markup is being inserted into the content page.
     39 */
     40 class FontsHighlighter {
     41  constructor(highlighterEnv) {
     42    this.env = highlighterEnv;
     43  }
     44 
     45  destroy() {
     46    this.hide();
     47    this.env = this.currentNode = null;
     48  }
     49 
     50  get currentNodeDocument() {
     51    if (!this.currentNode) {
     52      return this.env.document;
     53    }
     54 
     55    if (this.currentNode.nodeType === this.currentNode.DOCUMENT_NODE) {
     56      return this.currentNode;
     57    }
     58 
     59    return this.currentNode.ownerDocument;
     60  }
     61 
     62  /**
     63   * Show the highlighter for a given node.
     64   *
     65   * @param {DOMNode} node The node in which we want to search for text runs.
     66   * @param {object} options A bunch of options that can be set:
     67   * - {String} name The actual font name to look for in the node.
     68   * - {String} CSSFamilyName The CSS font-family name given to this font.
     69   */
     70  show(node, options) {
     71    this.currentNode = node;
     72    const doc = this.currentNodeDocument;
     73 
     74    // Get all of the fonts used to render content inside the node.
     75    const searchRange = doc.createRange();
     76    searchRange.selectNodeContents(node);
     77 
     78    const fonts = InspectorUtils.getUsedFontFaces(searchRange, MAX_TEXT_RANGES);
     79 
     80    // Find the ones we want, based on the provided option.
     81    const matchingFonts = fonts.filter(
     82      f => f.CSSFamilyName === options.CSSFamilyName && f.name === options.name
     83    );
     84    if (!matchingFonts.length) {
     85      return;
     86    }
     87 
     88    // Load the stylesheet that will customize the color of the highlighter (using a
     89    // ::selection rule).
     90    loadSheet(this.env.window, STYLESHEET_URI);
     91 
     92    // Create a multi-selection in the page to highlight the text runs.
     93    const selection = doc.defaultView.getSelection();
     94    selection.removeAllRanges();
     95 
     96    for (const matchingFont of matchingFonts) {
     97      for (const range of matchingFont.ranges) {
     98        selection.addRange(range);
     99      }
    100    }
    101  }
    102 
    103  hide() {
    104    // No node was highlighted before, don't need to continue any further.
    105    if (!this.currentNode) {
    106      return;
    107    }
    108 
    109    try {
    110      removeSheet(this.env.window, STYLESHEET_URI);
    111    } catch (e) {
    112      // Silently fail here as we might not have inserted the stylesheet at all.
    113    }
    114 
    115    // Simply remove all current ranges in the seletion.
    116    const doc = this.currentNodeDocument;
    117    const selection = doc.defaultView.getSelection();
    118    selection.removeAllRanges();
    119  }
    120 }
    121 
    122 exports.FontsHighlighter = FontsHighlighter;