1cb93a386Sopenharmony_ci// Functions dealing with parsing/stringifying fonts go here.
2cb93a386Sopenharmony_civar fontStringRegex = new RegExp(
3cb93a386Sopenharmony_ci  '(italic|oblique|normal|)\\s*' +              // style
4cb93a386Sopenharmony_ci  '(small-caps|normal|)\\s*' +                  // variant
5cb93a386Sopenharmony_ci  '(bold|bolder|lighter|[1-9]00|normal|)\\s*' + // weight
6cb93a386Sopenharmony_ci  '([\\d\\.]+)' +                               // size
7cb93a386Sopenharmony_ci  '(px|pt|pc|in|cm|mm|%|em|ex|ch|rem|q)' +      // unit
8cb93a386Sopenharmony_ci  // line-height is ignored here, as per the spec
9cb93a386Sopenharmony_ci  '(.+)'                                        // family
10cb93a386Sopenharmony_ci  );
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_cifunction stripWhitespace(str) {
13cb93a386Sopenharmony_ci  return str.replace(/^\s+|\s+$/, '');
14cb93a386Sopenharmony_ci}
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_civar defaultHeight = 16;
17cb93a386Sopenharmony_ci// Based off of node-canvas's parseFont
18cb93a386Sopenharmony_ci// returns font size in px, which represents the em width.
19cb93a386Sopenharmony_cifunction parseFontString(fontStr) {
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci  var font = fontStringRegex.exec(fontStr);
22cb93a386Sopenharmony_ci  if (!font) {
23cb93a386Sopenharmony_ci    Debug('Invalid font string ' + fontStr);
24cb93a386Sopenharmony_ci    return null;
25cb93a386Sopenharmony_ci  }
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci  var size = parseFloat(font[4]);
28cb93a386Sopenharmony_ci  var sizePx = defaultHeight;
29cb93a386Sopenharmony_ci  var unit = font[5];
30cb93a386Sopenharmony_ci  switch (unit) {
31cb93a386Sopenharmony_ci    case 'em':
32cb93a386Sopenharmony_ci    case 'rem':
33cb93a386Sopenharmony_ci      sizePx = size * defaultHeight;
34cb93a386Sopenharmony_ci      break;
35cb93a386Sopenharmony_ci    case 'pt':
36cb93a386Sopenharmony_ci      sizePx = size * 4/3;
37cb93a386Sopenharmony_ci      break;
38cb93a386Sopenharmony_ci    case 'px':
39cb93a386Sopenharmony_ci      sizePx = size;
40cb93a386Sopenharmony_ci      break;
41cb93a386Sopenharmony_ci    case 'pc':
42cb93a386Sopenharmony_ci      sizePx = size * defaultHeight;
43cb93a386Sopenharmony_ci      break;
44cb93a386Sopenharmony_ci    case 'in':
45cb93a386Sopenharmony_ci      sizePx = size * 96;
46cb93a386Sopenharmony_ci      break;
47cb93a386Sopenharmony_ci    case 'cm':
48cb93a386Sopenharmony_ci      sizePx = size * 96.0 / 2.54;
49cb93a386Sopenharmony_ci      break;
50cb93a386Sopenharmony_ci    case 'mm':
51cb93a386Sopenharmony_ci      sizePx = size * (96.0 / 25.4);
52cb93a386Sopenharmony_ci      break;
53cb93a386Sopenharmony_ci    case 'q': // quarter millimeters
54cb93a386Sopenharmony_ci      sizePx = size * (96.0 / 25.4 / 4);
55cb93a386Sopenharmony_ci      break;
56cb93a386Sopenharmony_ci    case '%':
57cb93a386Sopenharmony_ci      sizePx = size * (defaultHeight / 75);
58cb93a386Sopenharmony_ci      break;
59cb93a386Sopenharmony_ci  }
60cb93a386Sopenharmony_ci  return {
61cb93a386Sopenharmony_ci    'style':   font[1],
62cb93a386Sopenharmony_ci    'variant': font[2],
63cb93a386Sopenharmony_ci    'weight':  font[3],
64cb93a386Sopenharmony_ci    'sizePx':  sizePx,
65cb93a386Sopenharmony_ci    'family':  font[6].trim()
66cb93a386Sopenharmony_ci  };
67cb93a386Sopenharmony_ci}
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_cifunction getTypeface(fontstr) {
70cb93a386Sopenharmony_ci  var descriptors = parseFontString(fontstr);
71cb93a386Sopenharmony_ci  var typeface = getFromFontCache(descriptors);
72cb93a386Sopenharmony_ci  descriptors['typeface'] = typeface;
73cb93a386Sopenharmony_ci  return descriptors;
74cb93a386Sopenharmony_ci}
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci// null means use the default typeface (which is currently NotoMono)
77cb93a386Sopenharmony_civar fontCache = {
78cb93a386Sopenharmony_ci  'Noto Mono': {
79cb93a386Sopenharmony_ci    '*': null, // is used if we have this font family, but not the right style/variant/weight
80cb93a386Sopenharmony_ci  },
81cb93a386Sopenharmony_ci  'monospace': {
82cb93a386Sopenharmony_ci    '*': null,
83cb93a386Sopenharmony_ci  }
84cb93a386Sopenharmony_ci};
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci// descriptors is like https://developer.mozilla.org/en-US/docs/Web/API/FontFace/FontFace
87cb93a386Sopenharmony_ci// The ones currently supported are family, style, variant, weight.
88cb93a386Sopenharmony_cifunction addToFontCache(typeface, descriptors) {
89cb93a386Sopenharmony_ci  var key = (descriptors['style']   || 'normal') + '|' +
90cb93a386Sopenharmony_ci            (descriptors['variant'] || 'normal') + '|' +
91cb93a386Sopenharmony_ci            (descriptors['weight']  || 'normal');
92cb93a386Sopenharmony_ci  var fam = descriptors['family'];
93cb93a386Sopenharmony_ci  if (!fontCache[fam]) {
94cb93a386Sopenharmony_ci    // preload with a fallback to this typeface
95cb93a386Sopenharmony_ci    fontCache[fam] = {
96cb93a386Sopenharmony_ci      '*': typeface,
97cb93a386Sopenharmony_ci    };
98cb93a386Sopenharmony_ci  }
99cb93a386Sopenharmony_ci  fontCache[fam][key] = typeface;
100cb93a386Sopenharmony_ci}
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_cifunction getFromFontCache(descriptors) {
103cb93a386Sopenharmony_ci  var key = (descriptors['style']   || 'normal') + '|' +
104cb93a386Sopenharmony_ci            (descriptors['variant'] || 'normal') + '|' +
105cb93a386Sopenharmony_ci            (descriptors['weight']  || 'normal');
106cb93a386Sopenharmony_ci  var fam = descriptors['family'];
107cb93a386Sopenharmony_ci  if (!fontCache[fam]) {
108cb93a386Sopenharmony_ci    return null;
109cb93a386Sopenharmony_ci  }
110cb93a386Sopenharmony_ci  return fontCache[fam][key] || fontCache[fam]['*'];
111cb93a386Sopenharmony_ci}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ciCanvasKit._testing['parseFontString'] = parseFontString;
114