browser/devtools/fontinspector/font-inspector.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 "use strict";
michael@0 8
michael@0 9 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
michael@0 10 const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
michael@0 11
michael@0 12 function FontInspector(inspector, window)
michael@0 13 {
michael@0 14 this.inspector = inspector;
michael@0 15 this.chromeDoc = window.document;
michael@0 16 this.init();
michael@0 17 }
michael@0 18
michael@0 19 FontInspector.prototype = {
michael@0 20 init: function FI_init() {
michael@0 21 this.update = this.update.bind(this);
michael@0 22 this.onNewNode = this.onNewNode.bind(this);
michael@0 23 this.inspector.selection.on("new-node", this.onNewNode);
michael@0 24 this.inspector.sidebar.on("fontinspector-selected", this.onNewNode);
michael@0 25 this.showAll = this.showAll.bind(this);
michael@0 26 this.showAllButton = this.chromeDoc.getElementById("showall");
michael@0 27 this.showAllButton.addEventListener("click", this.showAll);
michael@0 28 this.update();
michael@0 29 },
michael@0 30
michael@0 31 /**
michael@0 32 * Is the fontinspector visible in the sidebar?
michael@0 33 */
michael@0 34 isActive: function FI_isActive() {
michael@0 35 return this.inspector.sidebar &&
michael@0 36 this.inspector.sidebar.getCurrentTabID() == "fontinspector";
michael@0 37 },
michael@0 38
michael@0 39 /**
michael@0 40 * Remove listeners.
michael@0 41 */
michael@0 42 destroy: function FI_destroy() {
michael@0 43 this.chromeDoc = null;
michael@0 44 this.inspector.sidebar.off("layoutview-selected", this.onNewNode);
michael@0 45 this.inspector.selection.off("new-node", this.onNewNode);
michael@0 46 this.showAllButton.removeEventListener("click", this.showAll);
michael@0 47 },
michael@0 48
michael@0 49 /**
michael@0 50 * Selection 'new-node' event handler.
michael@0 51 */
michael@0 52 onNewNode: function FI_onNewNode() {
michael@0 53 if (this.isActive() &&
michael@0 54 this.inspector.selection.isLocal() &&
michael@0 55 this.inspector.selection.isConnected() &&
michael@0 56 this.inspector.selection.isElementNode()) {
michael@0 57 this.undim();
michael@0 58 this.update();
michael@0 59 } else {
michael@0 60 this.dim();
michael@0 61 }
michael@0 62 },
michael@0 63
michael@0 64 /**
michael@0 65 * Hide the font list. No node are selected.
michael@0 66 */
michael@0 67 dim: function FI_dim() {
michael@0 68 this.chromeDoc.body.classList.add("dim");
michael@0 69 this.chromeDoc.querySelector("#all-fonts").innerHTML = "";
michael@0 70 },
michael@0 71
michael@0 72 /**
michael@0 73 * Show the font list. A node is selected.
michael@0 74 */
michael@0 75 undim: function FI_undim() {
michael@0 76 this.chromeDoc.body.classList.remove("dim");
michael@0 77 },
michael@0 78
michael@0 79 /**
michael@0 80 * Retrieve all the font related info we have for the selected
michael@0 81 * node and display them.
michael@0 82 */
michael@0 83 update: function FI_update() {
michael@0 84 if (!this.isActive() ||
michael@0 85 !this.inspector.selection.isConnected() ||
michael@0 86 !this.inspector.selection.isElementNode() ||
michael@0 87 this.chromeDoc.body.classList.contains("dim")) {
michael@0 88 return;
michael@0 89 }
michael@0 90
michael@0 91 let node = this.inspector.selection.node;
michael@0 92 let contentDocument = node.ownerDocument;
michael@0 93
michael@0 94 // We don't get fonts for a node, but for a range
michael@0 95 let rng = contentDocument.createRange();
michael@0 96 rng.selectNode(node);
michael@0 97 let fonts = DOMUtils.getUsedFontFaces(rng);
michael@0 98 let fontsArray = [];
michael@0 99 for (let i = 0; i < fonts.length; i++) {
michael@0 100 fontsArray.push(fonts.item(i));
michael@0 101 }
michael@0 102 fontsArray = fontsArray.sort(function(a, b) {
michael@0 103 return a.srcIndex < b.srcIndex;
michael@0 104 });
michael@0 105 this.chromeDoc.querySelector("#all-fonts").innerHTML = "";
michael@0 106 for (let f of fontsArray) {
michael@0 107 this.render(f, contentDocument);
michael@0 108 }
michael@0 109 },
michael@0 110
michael@0 111 /**
michael@0 112 * Display the information of one font.
michael@0 113 */
michael@0 114 render: function FI_render(font, document) {
michael@0 115 let s = this.chromeDoc.querySelector("#template > section");
michael@0 116 s = s.cloneNode(true);
michael@0 117
michael@0 118 s.querySelector(".font-name").textContent = font.name;
michael@0 119 s.querySelector(".font-css-name").textContent = font.CSSFamilyName;
michael@0 120 s.querySelector(".font-format").textContent = font.format;
michael@0 121
michael@0 122 if (font.srcIndex == -1) {
michael@0 123 s.classList.add("is-local");
michael@0 124 } else {
michael@0 125 s.classList.add("is-remote");
michael@0 126 }
michael@0 127
michael@0 128 s.querySelector(".font-url").value = font.URI;
michael@0 129
michael@0 130 let iframe = s.querySelector(".font-preview");
michael@0 131 if (font.rule) {
michael@0 132 // This is the @font-face{…} code.
michael@0 133 let cssText = font.rule.style.parentRule.cssText;
michael@0 134
michael@0 135 s.classList.add("has-code");
michael@0 136 s.querySelector(".font-css-code").textContent = cssText;
michael@0 137
michael@0 138 // We guess the base URL of the stylesheet to make
michael@0 139 // sure the font will be accessible in the preview.
michael@0 140 // If the font-face is in an inline <style>, we get
michael@0 141 // the location of the page.
michael@0 142 let origin = font.rule.style.parentRule.parentStyleSheet.href;
michael@0 143 if (!origin) { // Inline stylesheet
michael@0 144 origin = document.location.href;
michael@0 145 }
michael@0 146 // We remove the last part of the URL to get a correct base.
michael@0 147 let base = origin.replace(/\/[^\/]*$/,"/")
michael@0 148
michael@0 149 // From all this information, we build a preview.
michael@0 150 this.buildPreview(iframe, font.CSSFamilyName, cssText, base);
michael@0 151 } else {
michael@0 152 this.buildPreview(iframe, font.CSSFamilyName, "", "");
michael@0 153 }
michael@0 154
michael@0 155 this.chromeDoc.querySelector("#all-fonts").appendChild(s);
michael@0 156 },
michael@0 157
michael@0 158 /**
michael@0 159 * Show a preview of the font in an iframe.
michael@0 160 */
michael@0 161 buildPreview: function FI_buildPreview(iframe, name, cssCode, base) {
michael@0 162 /* The HTML code of the preview is:
michael@0 163 * <!DOCTYPE HTML>
michael@0 164 * <head>
michael@0 165 * <base href="{base}"></base>
michael@0 166 * </head>
michael@0 167 * <style>
michael@0 168 * p {font-family: {name};}
michael@0 169 * * {font-size: 40px;line-height:60px;padding:0 10px;margin:0};
michael@0 170 * </style>
michael@0 171 * <p contenteditable spellcheck='false'>Abc</p>
michael@0 172 */
michael@0 173 let extraCSS = "* {padding:0;margin:0}";
michael@0 174 extraCSS += ".theme-dark {color: white}";
michael@0 175 extraCSS += "p {font-size: 40px;line-height:60px;padding:0 10px;margin:0;}";
michael@0 176 cssCode += extraCSS;
michael@0 177 let src = "data:text/html;charset=utf-8,<!DOCTYPE HTML><head><base></base></head><style></style><p contenteditable spellcheck='false'>Abc</p>";
michael@0 178 iframe.addEventListener("load", function onload() {
michael@0 179 iframe.removeEventListener("load", onload, true);
michael@0 180 let doc = iframe.contentWindow.document;
michael@0 181 // We could have done that earlier, but we want to avoid any URL-encoding
michael@0 182 // nightmare.
michael@0 183 doc.querySelector("base").href = base;
michael@0 184 doc.querySelector("style").textContent = cssCode;
michael@0 185 doc.querySelector("p").style.fontFamily = name;
michael@0 186 // Forward theme
michael@0 187 doc.documentElement.className = document.documentElement.className;
michael@0 188 }, true);
michael@0 189 iframe.src = src;
michael@0 190 },
michael@0 191
michael@0 192 /**
michael@0 193 * Select the <body> to show all the fonts included in the document.
michael@0 194 */
michael@0 195 showAll: function FI_showAll() {
michael@0 196 if (!this.isActive() ||
michael@0 197 !this.inspector.selection.isConnected() ||
michael@0 198 !this.inspector.selection.isElementNode()) {
michael@0 199 return;
michael@0 200 }
michael@0 201
michael@0 202 // Select the body node to show all fonts
michael@0 203 let walker = this.inspector.walker;
michael@0 204
michael@0 205 walker.getRootNode().then(root => walker.querySelector(root, "body")).then(body => {
michael@0 206 this.inspector.selection.setNodeFront(body, "fontinspector");
michael@0 207 });
michael@0 208 },
michael@0 209 }
michael@0 210
michael@0 211 window.setPanel = function(panel) {
michael@0 212 window.fontInspector = new FontInspector(panel, window);
michael@0 213 }
michael@0 214
michael@0 215 window.onunload = function() {
michael@0 216 if (window.fontInspector) {
michael@0 217 window.fontInspector.destroy();
michael@0 218 }
michael@0 219 }

mercurial