summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/fonts/utils/font-utils.js
blob: 9a86acad49a50c4514cfad9adc306242a52e2e56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* 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";

module.exports = {
  /**
   * Given a CSS unit type, get the amount by which to increment a numeric value.
   * Used as the step attribute in inputs of type "range" or "number".
   *
   * @param {String} unit
   *        CSS unit type (px, %, em, rem, vh, vw, ...)
   * @return {Number}
   *         Amount by which to increment.
   */
  getStepForUnit(unit) {
    let step;
    switch (unit) {
      case "":
      case "em":
      case "rem":
      case "vw":
      case "vh":
      case "vmin":
      case "vmax":
        step = 0.1;
        break;
      default:
        step = 1;
    }

    return step;
  },

  /**
   * Get the unit type from the end of a CSS value string.
   * Returns null for non-string input or unitless values.
   *
   * @param {String} value
   *        CSS value string.
   * @return {String|null}
   *         CSS unit type, like "px", "em", "rem", etc or null.
   */
  getUnitFromValue(value) {
    if (typeof value !== "string" || isNaN(parseFloat(value))) {
      return null;
    }

    const match = value.match(/\D+?$/);
    return match?.length ? match[0] : null;
  },

  /**
   * Parse the string value of CSS font-variation-settings into an object with
   * axis tag names and corresponding values. If the string is a keyword or does not
   * contain axes, return an empty object.
   *
   * @param {String} string
   *        Value of font-variation-settings property coming from node's computed style.
   *        Its contents are expected to be stable having been already parsed by the
   *        browser.
   * @return {Object}
   */
  parseFontVariationAxes(string) {
    let axes = {};
    const keywords = ["initial", "normal", "inherit", "unset"];

    if (!string || keywords.includes(string.trim())) {
      return axes;
    }

    // Parse font-variation-settings CSS declaration into an object
    // with axis tags as keys and axis values as values.
    axes = string.split(",").reduce((acc, pair) => {
      // Tags are always in quotes. Split by quote and filter excessive whitespace.
      pair = pair.split(/["']/).filter(part => part.trim() !== "");
      // Guard against malformed input that may have slipped through.
      if (pair.length === 0) {
        return acc;
      }

      const tag = pair[0];
      const value = pair[1].trim();
      // Axis tags shorter or longer than 4 characters are invalid. Whitespace is valid.
      if (tag.length === 4) {
        acc[tag] = parseFloat(value);
      }
      return acc;
    }, {});

    return axes;
  },

  /**
   * Limit the decimal count of a number. Used instead of Number.toFixed() which pads
   * integers with zeroes. If the input is not a number, it is returned as is.
   *
   * @param {Number} number
   * @param {Number} decimals
   *        Decimal count in the output number. Default to one decimal.
   * @return {Number}
   */
  toFixed(number, decimals = 1) {
    if (typeof number !== "number") {
      return number;
    }

    return Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
  },
};