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;