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