Source code

Revision control

Copy as Markdown

Other Tools

/* 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";
loader.lazyRequireGetter(
this,
"loadSheet",
true
);
loader.lazyRequireGetter(
this,
"removeSheet",
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;