diff options
Diffstat (limited to 'devtools/server/actors/highlighters/fonts.js')
-rw-r--r-- | devtools/server/actors/highlighters/fonts.js | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/devtools/server/actors/highlighters/fonts.js b/devtools/server/actors/highlighters/fonts.js new file mode 100644 index 0000000000..3106e1b1fa --- /dev/null +++ b/devtools/server/actors/highlighters/fonts.js @@ -0,0 +1,122 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const InspectorUtils = require("InspectorUtils"); +loader.lazyRequireGetter( + this, + "loadSheet", + "devtools/shared/layout/utils", + true +); +loader.lazyRequireGetter( + this, + "removeSheet", + "devtools/shared/layout/utils", + true +); + +// How many text runs are we highlighting at a time. There may be many text runs, and we +// want to prevent performance problems. +const MAX_TEXT_RANGES = 100; + +// This stylesheet is inserted into the page to customize the color of the selected text +// runs. +// Note that this color is defined as --highlighter-content-color in the highlighters.css +// file, and corresponds to the box-model content color. We want to give it an opacity of +// 0.6 here. +const STYLESHEET_URI = + "data:text/css," + + encodeURIComponent( + "::selection{background-color:hsl(197,71%,73%,.6)!important;}" + ); + +/** + * This highlighter highlights runs of text in the page that have been rendered given a + * certain font. The highlighting is done with window selection ranges, so no extra + * markup is being inserted into the content page. + */ +class FontsHighlighter { + constructor(highlighterEnv) { + this.env = highlighterEnv; + } + + destroy() { + this.hide(); + this.env = this.currentNode = null; + } + + get currentNodeDocument() { + if (!this.currentNode) { + return this.env.document; + } + + if (this.currentNode.nodeType === this.currentNode.DOCUMENT_NODE) { + return this.currentNode; + } + + return this.currentNode.ownerDocument; + } + + /** + * Show the highlighter for a given node. + * @param {DOMNode} node The node in which we want to search for text runs. + * @param {Object} options A bunch of options that can be set: + * - {String} name The actual font name to look for in the node. + * - {String} CSSFamilyName The CSS font-family name given to this font. + */ + show(node, options) { + this.currentNode = node; + const doc = this.currentNodeDocument; + + // Get all of the fonts used to render content inside the node. + const searchRange = doc.createRange(); + searchRange.selectNodeContents(node); + + const fonts = InspectorUtils.getUsedFontFaces(searchRange, MAX_TEXT_RANGES); + + // Find the ones we want, based on the provided option. + const matchingFonts = fonts.filter( + f => f.CSSFamilyName === options.CSSFamilyName && f.name === options.name + ); + if (!matchingFonts.length) { + return; + } + + // Load the stylesheet that will customize the color of the highlighter (using a + // ::selection rule). + loadSheet(this.env.window, STYLESHEET_URI); + + // Create a multi-selection in the page to highlight the text runs. + const selection = doc.defaultView.getSelection(); + selection.removeAllRanges(); + + for (const matchingFont of matchingFonts) { + for (const range of matchingFont.ranges) { + selection.addRange(range); + } + } + } + + hide() { + // No node was highlighted before, don't need to continue any further. + if (!this.currentNode) { + return; + } + + try { + removeSheet(this.env.window, STYLESHEET_URI); + } catch (e) { + // Silently fail here as we might not have inserted the stylesheet at all. + } + + // Simply remove all current ranges in the seletion. + const doc = this.currentNodeDocument; + const selection = doc.defaultView.getSelection(); + selection.removeAllRanges(); + } +} + +exports.FontsHighlighter = FontsHighlighter; |