Bug 1396600 - Make some efforts to lazy load properties-db. r=tromey
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 06 Sep 2017 18:54:07 +0200
changeset 428722 492ea790f0493e82e754f18eb2b8cde3ea8946f3
parent 428721 45084f5718b924ffcbd6a791cf3607546c47befb
child 428723 f9c03c26c8763e78a2c70f1afc6cfb0fc92ec493
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstromey
bugs1396600
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1396600 - Make some efforts to lazy load properties-db. r=tromey MozReview-Commit-ID: LGgVb5kxN7X
devtools/client/shared/css-angle.js
devtools/client/shared/output-parser.js
devtools/client/shared/test/browser_css_angle.js
devtools/server/actors/css-properties.js
devtools/shared/css/color.js
devtools/shared/css/parsing-utils.js
devtools/shared/fronts/css-properties.js
--- a/devtools/client/shared/css-angle.js
+++ b/devtools/client/shared/css-angle.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 {CSS_ANGLEUNIT} = require("devtools/shared/css/properties-db");
+loader.lazyRequireGetter(this, "CSS_ANGLEUNIT",
+  "devtools/shared/css/properties-db", true);
 
 const SPECIALVALUES = new Set([
   "initial",
   "inherit",
   "unset"
 ]);
 
 const {getCSSLexer} = require("devtools/shared/css/lexer");
@@ -36,19 +37,22 @@ function CssAngle(angleValue) {
   this.newAngle(angleValue);
 }
 
 module.exports.angleUtils = {
   CssAngle: CssAngle,
   classifyAngle: classifyAngle
 };
 
-CssAngle.ANGLEUNIT = CSS_ANGLEUNIT;
+CssAngle.prototype = {
+  // Still keep trying to lazy load properties-db by lazily getting ANGLEUNIT
+  get ANGLEUNIT() {
+    return CSS_ANGLEUNIT;
+  },
 
-CssAngle.prototype = {
   _angleUnit: null,
   _angleUnitUppercase: false,
 
   // The value as-authored.
   authored: null,
   // A lower-cased copy of |authored|.
   lowerCased: null,
 
@@ -64,157 +68,157 @@ CssAngle.prototype = {
   },
 
   get valid() {
     let token = getCSSLexer(this.authored).nextToken();
     if (!token) {
       return false;
     }
     return (token.tokenType === "dimension"
-      && token.text.toLowerCase() in CssAngle.ANGLEUNIT);
+      && token.text.toLowerCase() in this.ANGLEUNIT);
   },
 
   get specialValue() {
     return SPECIALVALUES.has(this.lowerCased) ? this.authored : null;
   },
 
   get deg() {
     let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
     if (invalidOrSpecialValue !== false) {
       return invalidOrSpecialValue;
     }
 
     let angleUnit = classifyAngle(this.authored);
-    if (angleUnit === CssAngle.ANGLEUNIT.deg) {
+    if (angleUnit === this.ANGLEUNIT.deg) {
       // The angle is valid and is in degree.
       return this.authored;
     }
 
     let degValue;
-    if (angleUnit === CssAngle.ANGLEUNIT.rad) {
+    if (angleUnit === this.ANGLEUNIT.rad) {
       // The angle is valid and is in radian.
       degValue = this.authoredAngleValue / (Math.PI / 180);
     }
 
-    if (angleUnit === CssAngle.ANGLEUNIT.grad) {
+    if (angleUnit === this.ANGLEUNIT.grad) {
       // The angle is valid and is in gradian.
       degValue = this.authoredAngleValue * 0.9;
     }
 
-    if (angleUnit === CssAngle.ANGLEUNIT.turn) {
+    if (angleUnit === this.ANGLEUNIT.turn) {
       // The angle is valid and is in turn.
       degValue = this.authoredAngleValue * 360;
     }
 
-    let unitStr = CssAngle.ANGLEUNIT.deg;
+    let unitStr = this.ANGLEUNIT.deg;
     if (this._angleUnitUppercase === true) {
       unitStr = unitStr.toUpperCase();
     }
     return `${Math.round(degValue * 100) / 100}${unitStr}`;
   },
 
   get rad() {
     let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
     if (invalidOrSpecialValue !== false) {
       return invalidOrSpecialValue;
     }
 
     let unit = classifyAngle(this.authored);
-    if (unit === CssAngle.ANGLEUNIT.rad) {
+    if (unit === this.ANGLEUNIT.rad) {
       // The angle is valid and is in radian.
       return this.authored;
     }
 
     let radValue;
-    if (unit === CssAngle.ANGLEUNIT.deg) {
+    if (unit === this.ANGLEUNIT.deg) {
       // The angle is valid and is in degree.
       radValue = this.authoredAngleValue * (Math.PI / 180);
     }
 
-    if (unit === CssAngle.ANGLEUNIT.grad) {
+    if (unit === this.ANGLEUNIT.grad) {
       // The angle is valid and is in gradian.
       radValue = this.authoredAngleValue * 0.9 * (Math.PI / 180);
     }
 
-    if (unit === CssAngle.ANGLEUNIT.turn) {
+    if (unit === this.ANGLEUNIT.turn) {
       // The angle is valid and is in turn.
       radValue = this.authoredAngleValue * 360 * (Math.PI / 180);
     }
 
-    let unitStr = CssAngle.ANGLEUNIT.rad;
+    let unitStr = this.ANGLEUNIT.rad;
     if (this._angleUnitUppercase === true) {
       unitStr = unitStr.toUpperCase();
     }
     return `${Math.round(radValue * 10000) / 10000}${unitStr}`;
   },
 
   get grad() {
     let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
     if (invalidOrSpecialValue !== false) {
       return invalidOrSpecialValue;
     }
 
     let unit = classifyAngle(this.authored);
-    if (unit === CssAngle.ANGLEUNIT.grad) {
+    if (unit === this.ANGLEUNIT.grad) {
       // The angle is valid and is in gradian
       return this.authored;
     }
 
     let gradValue;
-    if (unit === CssAngle.ANGLEUNIT.deg) {
+    if (unit === this.ANGLEUNIT.deg) {
       // The angle is valid and is in degree
       gradValue = this.authoredAngleValue / 0.9;
     }
 
-    if (unit === CssAngle.ANGLEUNIT.rad) {
+    if (unit === this.ANGLEUNIT.rad) {
       // The angle is valid and is in radian
       gradValue = this.authoredAngleValue / 0.9 / (Math.PI / 180);
     }
 
-    if (unit === CssAngle.ANGLEUNIT.turn) {
+    if (unit === this.ANGLEUNIT.turn) {
       // The angle is valid and is in turn
       gradValue = this.authoredAngleValue * 400;
     }
 
-    let unitStr = CssAngle.ANGLEUNIT.grad;
+    let unitStr = this.ANGLEUNIT.grad;
     if (this._angleUnitUppercase === true) {
       unitStr = unitStr.toUpperCase();
     }
     return `${Math.round(gradValue * 100) / 100}${unitStr}`;
   },
 
   get turn() {
     let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
     if (invalidOrSpecialValue !== false) {
       return invalidOrSpecialValue;
     }
 
     let unit = classifyAngle(this.authored);
-    if (unit === CssAngle.ANGLEUNIT.turn) {
+    if (unit === this.ANGLEUNIT.turn) {
       // The angle is valid and is in turn
       return this.authored;
     }
 
     let turnValue;
-    if (unit === CssAngle.ANGLEUNIT.deg) {
+    if (unit === this.ANGLEUNIT.deg) {
       // The angle is valid and is in degree
       turnValue = this.authoredAngleValue / 360;
     }
 
-    if (unit === CssAngle.ANGLEUNIT.rad) {
+    if (unit === this.ANGLEUNIT.rad) {
       // The angle is valid and is in radian
       turnValue = (this.authoredAngleValue / (Math.PI / 180)) / 360;
     }
 
-    if (unit === CssAngle.ANGLEUNIT.grad) {
+    if (unit === this.ANGLEUNIT.grad) {
       // The angle is valid and is in gradian
       turnValue = this.authoredAngleValue / 400;
     }
 
-    let unitStr = CssAngle.ANGLEUNIT.turn;
+    let unitStr = this.ANGLEUNIT.turn;
     if (this._angleUnitUppercase === true) {
       unitStr = unitStr.toUpperCase();
     }
     return `${Math.round(turnValue * 100) / 100}${unitStr}`;
   },
 
   /**
    * Check whether the angle value is in the special list e.g.
@@ -247,66 +251,66 @@ CssAngle.prototype = {
     // Store a lower-cased version of the angle to help with format
     // testing.  The original text is kept as well so it can be
     // returned when needed.
     this.lowerCased = angle.toLowerCase();
     this._angleUnitUppercase = (angle === angle.toUpperCase());
     this.authored = angle;
 
     let reg = new RegExp(
-      `(${Object.keys(CssAngle.ANGLEUNIT).join("|")})$`, "i");
+      `(${Object.keys(this.ANGLEUNIT).join("|")})$`, "i");
     let unitStartIdx = angle.search(reg);
     this.authoredAngleValue = angle.substring(0, unitStartIdx);
     this.authoredAngleUnit = angle.substring(unitStartIdx, angle.length);
 
     return this;
   },
 
   nextAngleUnit: function () {
     // Get a reordered array from the formats object
     // to have the current format at the front so we can cycle through.
-    let formats = Object.keys(CssAngle.ANGLEUNIT);
+    let formats = Object.keys(this.ANGLEUNIT);
     let putOnEnd = formats.splice(0, formats.indexOf(this.angleUnit));
     formats = formats.concat(putOnEnd);
     let currentDisplayedValue = this[formats[0]];
 
     for (let format of formats) {
       if (this[format].toLowerCase() !== currentDisplayedValue.toLowerCase()) {
-        this.angleUnit = CssAngle.ANGLEUNIT[format];
+        this.angleUnit = this.ANGLEUNIT[format];
         break;
       }
     }
     return this.toString();
   },
 
   /**
    * Return a string representing a angle
    */
   toString: function () {
     let angle;
 
     switch (this.angleUnit) {
-      case CssAngle.ANGLEUNIT.deg:
+      case this.ANGLEUNIT.deg:
         angle = this.deg;
         break;
-      case CssAngle.ANGLEUNIT.rad:
+      case this.ANGLEUNIT.rad:
         angle = this.rad;
         break;
-      case CssAngle.ANGLEUNIT.grad:
+      case this.ANGLEUNIT.grad:
         angle = this.grad;
         break;
-      case CssAngle.ANGLEUNIT.turn:
+      case this.ANGLEUNIT.turn:
         angle = this.turn;
         break;
       default:
         angle = this.deg;
     }
 
     if (this._angleUnitUppercase &&
-        this.angleUnit != CssAngle.ANGLEUNIT.authored) {
+        this.angleUnit != this.ANGLEUNIT.authored) {
       angle = angle.toUpperCase();
     }
     return angle;
   },
 
   /**
    * This method allows comparison of CssAngle objects using ===.
    */
@@ -322,24 +326,24 @@ CssAngle.prototype = {
  * @param  {String} value
  *         The angle, in any form accepted by CSS.
  * @return {String}
  *         The angle classification, one of "deg", "rad", "grad", or "turn".
  */
 function classifyAngle(value) {
   value = value.toLowerCase();
   if (value.endsWith("deg")) {
-    return CssAngle.ANGLEUNIT.deg;
+    return CSS_ANGLEUNIT.deg;
   }
 
   if (value.endsWith("grad")) {
-    return CssAngle.ANGLEUNIT.grad;
+    return CSS_ANGLEUNIT.grad;
   }
 
   if (value.endsWith("rad")) {
-    return CssAngle.ANGLEUNIT.rad;
+    return CSS_ANGLEUNIT.rad;
   }
   if (value.endsWith("turn")) {
-    return CssAngle.ANGLEUNIT.turn;
+    return CSS_ANGLEUNIT.turn;
   }
 
-  return CssAngle.ANGLEUNIT.deg;
+  return CSS_ANGLEUNIT.deg;
 }
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -1,25 +1,29 @@
 /* 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, "ANGLE_TAKING_FUNCTIONS",
+  "devtools/shared/css/properties-db", true);
+loader.lazyRequireGetter(this, "BASIC_SHAPE_FUNCTIONS",
+  "devtools/shared/css/properties-db", true);
+loader.lazyRequireGetter(this, "BEZIER_KEYWORDS",
+  "devtools/shared/css/properties-db", true);
+loader.lazyRequireGetter(this, "COLOR_TAKING_FUNCTIONS",
+  "devtools/shared/css/properties-db", true);
+loader.lazyRequireGetter(this, "CSS_TYPES",
+  "devtools/shared/css/properties-db", true);
+
 const {angleUtils} = require("devtools/client/shared/css-angle");
 const {colorUtils} = require("devtools/shared/css/color");
 const {getCSSLexer} = require("devtools/shared/css/lexer");
 const EventEmitter = require("devtools/shared/old-event-emitter");
-const {
-  ANGLE_TAKING_FUNCTIONS,
-  BASIC_SHAPE_FUNCTIONS,
-  BEZIER_KEYWORDS,
-  COLOR_TAKING_FUNCTIONS,
-  CSS_TYPES
-} = require("devtools/shared/css/properties-db");
 const {appendText} = require("devtools/client/inspector/shared/utils");
 const Services = require("Services");
 
 const STYLE_INSPECTOR_PROPERTIES = "devtools/shared/locales/styleinspector.properties";
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const STYLE_INSPECTOR_L10N = new LocalizationHelper(STYLE_INSPECTOR_PROPERTIES);
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
--- a/devtools/client/shared/test/browser_css_angle.js
+++ b/devtools/client/shared/test/browser_css_angle.js
@@ -43,26 +43,27 @@ function testAngleValidity() {
     let validString = testAngle.valid ? " a valid" : "an invalid";
 
     is(testAngle.valid, result,
        `Testing that "${angle}" is ${validString} angle`);
   }
 }
 
 function testToString(angle, deg, rad, grad, turn) {
-  angle.angleUnit = angleUtils.CssAngle.ANGLEUNIT.deg;
+  let { ANGLEUNIT } = angleUtils.CssAngle.prototype;
+  angle.angleUnit = ANGLEUNIT.deg;
   is(angle.toString(), deg, "toString() with deg type");
 
-  angle.angleUnit = angleUtils.CssAngle.ANGLEUNIT.rad;
+  angle.angleUnit = ANGLEUNIT.rad;
   is(angle.toString(), rad, "toString() with rad type");
 
-  angle.angleUnit = angleUtils.CssAngle.ANGLEUNIT.grad;
+  angle.angleUnit = ANGLEUNIT.grad;
   is(angle.toString(), grad, "toString() with grad type");
 
-  angle.angleUnit = angleUtils.CssAngle.ANGLEUNIT.turn;
+  angle.angleUnit = ANGLEUNIT.turn;
   is(angle.toString(), turn, "toString() with turn type");
 }
 
 function getAngleValidityData() {
   return [{
     angle: "0.2turn",
     result: true
   }, {
--- a/devtools/server/actors/css-properties.js
+++ b/devtools/server/actors/css-properties.js
@@ -1,24 +1,22 @@
 /* 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 { Cc, Ci } = require("chrome");
-
-loader.lazyGetter(this, "DOMUtils", () => {
-  return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
-});
+loader.lazyServiceGetter(this, "DOMUtils",
+  "@mozilla.org/inspector/dom-utils;1", "inIDOMUtils");
+loader.lazyRequireGetter(this, "CSS_TYPES",
+  "devtools/shared/css/properties-db", true);
 
 const protocol = require("devtools/shared/protocol");
 const { ActorClassWithSpec, Actor } = protocol;
 const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
-const { CSS_TYPES } = require("devtools/shared/css/properties-db");
 const { cssColors } = require("devtools/shared/css/color-db");
 
 exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
   typeName: "cssProperties",
 
   initialize(conn) {
     Actor.prototype.initialize.call(this, conn);
   },
--- a/devtools/shared/css/color.js
+++ b/devtools/shared/css/color.js
@@ -1,17 +1,19 @@
 /* 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 Services = require("Services");
 
-const {CSS_ANGLEUNIT} = require("devtools/shared/css/properties-db");
+loader.lazyRequireGetter(this, "CSS_ANGLEUNIT",
+  "devtools/shared/css/properties-db", true);
+
 const {getAngleValueInDegrees} = require("devtools/shared/css/parsing-utils");
 
 const {getCSSLexer} = require("devtools/shared/css/lexer");
 const {cssColors} = require("devtools/shared/css/color-db");
 
 const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
 
 const SPECIALVALUES = new Set([
--- a/devtools/shared/css/parsing-utils.js
+++ b/devtools/shared/css/parsing-utils.js
@@ -9,17 +9,18 @@
 // parseDeclarations - parse a CSS rule into declarations
 // RuleRewriter - rewrite CSS rule text
 // parsePseudoClassesAndAttributes - parse selector and extract
 //     pseudo-classes
 // parseSingleValue - parse a single CSS property value
 
 "use strict";
 
-const {CSS_ANGLEUNIT} = require("devtools/shared/css/properties-db");
+loader.lazyRequireGetter(this, "CSS_ANGLEUNIT",
+  "devtools/shared/css/properties-db", true);
 
 const promise = require("promise");
 const {getCSSLexer} = require("devtools/shared/css/lexer");
 const {Task} = require("devtools/shared/task");
 
 const SELECTOR_ATTRIBUTE = exports.SELECTOR_ATTRIBUTE = 1;
 const SELECTOR_ELEMENT = exports.SELECTOR_ELEMENT = 2;
 const SELECTOR_PSEUDO_CLASS = exports.SELECTOR_PSEUDO_CLASS = 3;
--- a/devtools/shared/fronts/css-properties.js
+++ b/devtools/shared/fronts/css-properties.js
@@ -1,17 +1,19 @@
 /* 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, "CSS_PROPERTIES_DB",
+  "devtools/shared/css/properties-db", true);
+
 const { FrontClassWithSpec, Front } = require("devtools/shared/protocol");
 const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
 const { Task } = require("devtools/shared/task");
-const { CSS_PROPERTIES_DB } = require("devtools/shared/css/properties-db");
 const { cssColors } = require("devtools/shared/css/color-db");
 
 /**
  * Build up a regular expression that matches a CSS variable token. This is an
  * ident token that starts with two dashes "--".
  *
  * https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
  */
@@ -275,49 +277,59 @@ function getClientCssProperties() {
 /**
  * Even if the target has the cssProperties actor, the returned data may not be in the
  * same shape or have all of the data we need. This normalizes the data and fills in
  * any missing information like color values.
  *
  * @return {Object} The normalized CSS database.
  */
 function normalizeCssData(db) {
-  if (db !== CSS_PROPERTIES_DB) {
+  // If there is a `from` attributes, it means that it comes from RDP
+  // and it is not the client CSS_PROPERTIES_DB object.
+  // (prevent comparing to CSS_PROPERTIES_DB to avoid loading client database)
+  if (typeof (db.from) == "string") {
     // Firefox 49's getCSSDatabase() just returned the properties object, but
     // now it returns an object with multiple types of CSS information.
     if (!db.properties) {
       db = { properties: db };
     }
 
     let missingSupports = !db.properties.color.supports;
     let missingValues = !db.properties.color.values;
     let missingSubproperties = !db.properties.background.subproperties;
+    let missingIsInherited = !db.properties.font.isInherited;
 
-    for (let name in db.properties) {
-      // Skip the current property if we can't find it in CSS_PROPERTIES_DB.
-      if (typeof CSS_PROPERTIES_DB.properties[name] !== "object") {
-        continue;
-      }
+    let missingSomething = missingSupports || missingValues || missingSubproperties ||
+      missingIsInherited;
+
+    if (missingSomething) {
+      for (let name in db.properties) {
+        // Skip the current property if we can't find it in CSS_PROPERTIES_DB.
+        if (typeof CSS_PROPERTIES_DB.properties[name] !== "object") {
+          continue;
+        }
 
-      // Add "supports" information to the css properties if it's missing.
-      if (missingSupports) {
-        db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
-      }
-      // Add "values" information to the css properties if it's missing.
-      if (missingValues) {
-        db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
-      }
-      // Add "subproperties" information to the css properties if it's missing.
-      if (missingSubproperties) {
-        db.properties[name].subproperties =
-          CSS_PROPERTIES_DB.properties[name].subproperties;
-      }
-      // Add "isInherited" information to the css properties if it's missing.
-      if (db.properties.font.isInherited) {
-        db.properties[name].isInherited = CSS_PROPERTIES_DB.properties[name].isInherited;
+        // Add "supports" information to the css properties if it's missing.
+        if (missingSupports) {
+          db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
+        }
+        // Add "values" information to the css properties if it's missing.
+        if (missingValues) {
+          db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
+        }
+        // Add "subproperties" information to the css properties if it's missing.
+        if (missingSubproperties) {
+          db.properties[name].subproperties =
+            CSS_PROPERTIES_DB.properties[name].subproperties;
+        }
+        // Add "isInherited" information to the css properties if it's missing.
+        if (missingIsInherited) {
+          db.properties[name].isInherited =
+            CSS_PROPERTIES_DB.properties[name].isInherited;
+        }
       }
     }
   }
 
   reattachCssColorValues(db);
 
   // If there is no supportedFeature in db, create an empty one.
   if (!db.supportedFeature) {