121 lines
3.5 KiB
JavaScript
121 lines
3.5 KiB
JavaScript
/* 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",
|
|
"resource://devtools/shared/layout/utils.js",
|
|
true
|
|
);
|
|
loader.lazyRequireGetter(
|
|
this,
|
|
"removeSheet",
|
|
"resource://devtools/shared/layout/utils.js",
|
|
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;
|