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.

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

mercurial