Bug 1441622 - Expose the OpenType Font Variations data to the fonts redux store. r=pbro draft
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 28 Feb 2018 22:55:01 -0500
changeset 761502 e3a1312d75bc4b159c8aedd0fba3f52a93494b3e
parent 761501 dd8af18e26d4c1483ac9de3975157e24e3836a1b
push id100961
push userbmo:gl@mozilla.com
push dateThu, 01 Mar 2018 04:03:23 +0000
reviewerspbro
bugs1441622
milestone60.0a1
Bug 1441622 - Expose the OpenType Font Variations data to the fonts redux store. r=pbro MozReview-Commit-ID: 5b0baqMuDCk
devtools/client/inspector/fonts/fonts.js
devtools/client/inspector/fonts/types.js
devtools/server/actors/styles.js
devtools/shared/fronts/styles.js
devtools/shared/specs/styles.js
--- a/devtools/client/inspector/fonts/fonts.js
+++ b/devtools/client/inspector/fonts/fonts.js
@@ -1,23 +1,21 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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 { gDevTools } = require("devtools/client/framework/devtools");
 const { getColor } = require("devtools/client/shared/theme");
-
 const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 
-const { gDevTools } = require("devtools/client/framework/devtools");
-
 const FontsApp = createFactory(require("./components/FontsApp"));
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const INSPECTOR_L10N =
   new LocalizationHelper("devtools/client/locales/inspector.properties");
 
 const { updateFonts } = require("./actions/fonts");
 const { updatePreviewText } = require("./actions/font-options");
@@ -188,16 +186,21 @@ class FontInspector {
     }
 
     let options = {
       includePreviews: true,
       previewText,
       previewFillStyle: getColor("body-color")
     };
 
+    // Add the includeVariations argument into the option to get font variation data.
+    if (this.pageStyle.supportsFontVariations) {
+      options.includeVariations = true;
+    }
+
     fonts = await this.getFontsForNode(node, options);
     otherFonts = await this.getFontsNotInNode(fonts, options);
 
     if (!fonts.length && !otherFonts.length) {
       // No fonts to display. Clear the previously shown fonts.
       if (this.store) {
         this.store.dispatch(updateFonts(fonts, otherFonts));
       }
--- a/devtools/client/inspector/fonts/types.js
+++ b/devtools/client/inspector/fonts/types.js
@@ -2,16 +2,55 @@
  * 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 PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 /**
+ * A font variation axis.
+ */
+const fontVariationAxis = exports.fontVariationAxis = {
+  // The OpenType tag name of the variation axis
+  tag: PropTypes.string,
+
+  // The axis name of the variation axis
+  name: PropTypes.string,
+
+  // The minimum value of the variation axis
+  minValue: PropTypes.number,
+
+  // The maximum value of the variation axis
+  maxValue: PropTypes.number,
+
+  // The default value of the variation axis
+  defaultValue: PropTypes.number,
+};
+
+const fontVariationInstanceValue = exports.fontVariationInstanceValue = {
+  // The axis name of the variation axis
+  axis: PropTypes.string,
+
+  // The value of the variation axis
+  value: PropTypes.number,
+};
+
+/**
+ * A font variation instance.
+ */
+const fontVariationInstance = exports.fontVariationInstance = {
+  // The variation instance name of the font
+  axis: PropTypes.string,
+
+  // The font variation values for the variation instance of the font
+  values: PropTypes.arrayOf(PropTypes.shape(fontVariationInstanceValue)),
+};
+
+/**
  * A single font.
  */
 const font = exports.font = {
   // The name of the font family
   CSSFamilyName: PropTypes.string,
 
   // The format of the font
   format: PropTypes.string,
@@ -25,25 +64,31 @@ const font = exports.font = {
   // Object containing the CSS rule for the font
   rule: PropTypes.object,
 
   // The text of the CSS rule
   ruleText: PropTypes.string,
 
   // The URI of the font file
   URI: PropTypes.string,
+
+  // The variation axes of the font
+  variationAxes: PropTypes.arrayOf(PropTypes.shape(fontVariationAxis)),
+
+  // The variation instances of the font
+  variationInstances: PropTypes.arrayOf(PropTypes.shape(fontVariationInstance))
 };
 
 exports.fontOptions = {
   // The current preview text
   previewText: PropTypes.string,
 };
 
 /**
- * Font data
+ * Font data.
  */
 exports.fontData = {
   // The fonts used in the current element.
   fonts: PropTypes.arrayOf(PropTypes.shape(font)),
 
   // Fonts used elsewhere.
   otherFonts: PropTypes.arrayOf(PropTypes.shape(font)),
 };
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -1,15 +1,16 @@
 /* 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 {Ci} = require("chrome");
+const Services = require("Services");
 const protocol = require("devtools/shared/protocol");
 const {LongStringActor} = require("devtools/server/actors/string");
 const InspectorUtils = require("InspectorUtils");
 
 // This will also add the "stylesheet" actor type for protocol.js to recognize
 
 const {pageStyleSpec, styleRuleSpec, ELEMENT_STYLE} = require("devtools/shared/specs/styles");
 
@@ -24,16 +25,19 @@ loader.lazyRequireGetter(this, "parseNam
 loader.lazyRequireGetter(this, "UPDATE_PRESERVING_RULES",
   "devtools/server/actors/stylesheets", true);
 loader.lazyRequireGetter(this, "UPDATE_GENERAL",
   "devtools/server/actors/stylesheets", true);
 
 loader.lazyGetter(this, "PSEUDO_ELEMENTS", () => {
   return InspectorUtils.getCSSPseudoElementNames();
 });
+loader.lazyGetter(this, "FONT_VARIATIONS_ENABLED", () => {
+  return Services.prefs.getBoolPref("layout.css.font-variations.enabled");
+});
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const FONT_PREVIEW_TEXT = "Abc";
 const FONT_PREVIEW_FONT_SIZE = 40;
 const FONT_PREVIEW_FILLSTYLE = "black";
 const NORMAL_FONT_WEIGHT = 400;
 const BOLD_FONT_WEIGHT = 700;
 // Offset (in px) to avoid cutting off text edges of italic fonts.
@@ -110,17 +114,20 @@ var PageStyleActor = protocol.ActorClass
       actor: this.actorID,
       traits: {
         // Whether the actor has had bug 1103993 fixed, which means that the
         // getApplied method calls cssLogic.highlight(node) to recreate the
         // style cache. Clients requesting getApplied from actors that have not
         // been fixed must make sure cssLogic.highlight(node) was called before.
         getAppliedCreatesStyleCache: true,
         // Whether addNewRule accepts the editAuthored argument.
-        authoredStyles: true
+        authoredStyles: true,
+        // Whether getAllUsedFontFaces/getUsedFontFaces accepts the includeVariations
+        // argument.
+        fontVariations: true,
       }
     };
   },
 
   /**
    * Called when a style sheet is updated.
    */
   _styleApplied: function (kind, styleSheet) {
@@ -315,16 +322,22 @@ var PageStyleActor = protocol.ActorClass
         };
         let { dataURL, size } = getFontPreviewData(font.CSSFamilyName,
                                                    contentDocument, opts);
         fontFace.preview = {
           data: LongStringActor(this.conn, dataURL),
           size: size
         };
       }
+
+      if (options.includeVariations && FONT_VARIATIONS_ENABLED) {
+        fontFace.variationAxes = font.getVariationAxes();
+        fontFace.variationInstances = font.getVariationInstances();
+      }
+
       fontsArray.push(fontFace);
     }
 
     // @font-face fonts at the top, then alphabetically, then by weight
     fontsArray.sort(function (a, b) {
       return a.weight > b.weight ? 1 : -1;
     });
     fontsArray.sort(function (a, b) {
--- a/devtools/shared/fronts/styles.js
+++ b/devtools/shared/fronts/styles.js
@@ -42,16 +42,20 @@ const PageStyleFront = FrontClassWithSpe
   get walker() {
     return this.inspector.walker;
   },
 
   get supportsAuthoredStyles() {
     return this._form.traits && this._form.traits.authoredStyles;
   },
 
+  get supportsFontVariations() {
+    return this._form.traits && this._form.traits.fontVariations;
+  },
+
   getMatchedSelectors: custom(function (node, property, options) {
     return this._getMatchedSelectors(node, property, options).then(ret => {
       return ret.matched;
     });
   }, {
     impl: "_getMatchedSelectors"
   }),
 
--- a/devtools/shared/specs/styles.js
+++ b/devtools/shared/specs/styles.js
@@ -53,26 +53,46 @@ types.addDictType("modifiedStylesReturn"
   ruleProps: RetVal("nullable:appliedStylesReturn")
 });
 
 types.addDictType("fontpreview", {
   data: "nullable:longstring",
   size: "json"
 });
 
+types.addDictType("fontvariationaxis", {
+  tag: "string",
+  name: "string",
+  minValue: "number",
+  maxValue: "number",
+  defaultValue: "number"
+});
+
+types.addDictType("fontvariationinstancevalue", {
+  axis: "string",
+  value: "number"
+});
+
+types.addDictType("fontvariationinstance", {
+  name: "string",
+  values: "array:fontvariationinstancevalue"
+});
+
 types.addDictType("fontface", {
   name: "string",
   CSSFamilyName: "string",
   rule: "nullable:domstylerule",
   srcIndex: "number",
   URI: "string",
   format: "string",
   preview: "nullable:fontpreview",
   localName: "string",
-  metadata: "string"
+  metadata: "string",
+  variationAxes: "array:fontvariationaxis",
+  variationInstances: "array:fontvariationinstance"
 });
 
 const pageStyleSpec = generateActorSpec({
   typeName: "pagestyle",
 
   events: {
     "stylesheet-updated": {
       type: "styleSheetUpdated",
@@ -90,28 +110,30 @@ const pageStyleSpec = generateActorSpec(
       },
       response: {
         computed: RetVal("json")
       }
     },
     getAllUsedFontFaces: {
       request: {
         includePreviews: Option(0, "boolean"),
+        includeVariations: Option(1, "boolean"),
         previewText: Option(0, "string"),
         previewFontSize: Option(0, "string"),
         previewFillStyle: Option(0, "string")
       },
       response: {
         fontFaces: RetVal("array:fontface")
       }
     },
     getUsedFontFaces: {
       request: {
         node: Arg(0, "domnode"),
         includePreviews: Option(1, "boolean"),
+        includeVariations: Option(1, "boolean"),
         previewText: Option(1, "string"),
         previewFontSize: Option(1, "string"),
         previewFillStyle: Option(1, "string")
       },
       response: {
         fontFaces: RetVal("array:fontface")
       }
     },