]> granicus.if.org Git - graphviz/commitdiff
lib/common: add character width lookup tables for more fonts and variants
authorBen Hansell <ben@cocotec.io>
Mon, 18 Oct 2021 17:02:46 +0000 (17:02 +0000)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 30 Oct 2021 15:16:52 +0000 (08:16 -0700)
This allows Graphviz to estimate the widths of text spans more accurately when built without a textlayout plugin. The textlayout plugins are platform-specific and can be difficult to build for obscure platforms (e.g. Graphviz Online), resulting in node labels not fitting within their nodes nicely.

lib/common: add new source file and header

lib/common: don't install new header

lib/common: redesign hard-coded font metrics

lib/common: remove unused variables

lib/common: format new source file with clang-format

lib/common: add more fonts

lib/common: add warning spam guards

lib/common: improve code style and comments

lib/common: improve code style and comments

lib/common: fix const compiler error

lib/common: reuse existing isalpha_no_locale function

lib/common: fix another const compilation error

lib/common: fix yet another const compilation error

update changelog

update changelog

CHANGELOG.md
lib/common/CMakeLists.txt
lib/common/Makefile.am
lib/common/textspan.c
lib/common/textspan_lut.c [new file with mode: 0644]
lib/common/textspan_lut.h [new file with mode: 0644]
lib/gvc.vcxproj
lib/gvc.vcxproj.filters

index 1b1aba02947213118e131bdc145f042971becf51..02e6b55d3350f5561881e04bfb971c9d5761d771 100644 (file)
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased (2.49.4)]
 
+### Added
+
+- hard-coded lookup tables for fallback font metrics for more fonts and font
+  variants
+
 ## [2.49.3] – 2021-10-22
 
 ### Fixed
index d153c7fb492bec38ceb94102be3fe0a56d907ca5..b858ededab959c865814dd85962192ead6f0d0b9 100644 (file)
@@ -58,6 +58,7 @@ add_library(common_obj OBJECT
     ps_font_equiv.h
     render.h
     textspan.h
+    textspan_lut.h
     types.h
     usershape.h
     utils.h
@@ -86,6 +87,7 @@ add_library(common_obj OBJECT
     splines.c
     taper.c
     textspan.c
+    textspan_lut.c
     timing.c
     utils.c
     xml.c
index 34b9b1ab03b8d0fec3b9c849d1a81903dda937fa..16d81e876c312f3031ff74254d2d55cd579e4987 100644 (file)
@@ -21,10 +21,10 @@ pkginclude_HEADERS = arith.h geom.h color.h types.h textspan.h usershape.h
 noinst_HEADERS = render.h utils.h memory.h \
        geomprocs.h colorprocs.h colortbl.h entities.h globals.h \
        logic.h const.h macros.h htmllex.h htmltable.h pointset.h intset.h \
-       timing.h ps_font_equiv.h
+       textspan_lut.h timing.h ps_font_equiv.h
 noinst_LTLIBRARIES = libcommon_C.la
 
-libcommon_C_la_SOURCES = arrows.c colxlate.c ellipse.c textspan.c \
+libcommon_C_la_SOURCES = arrows.c colxlate.c ellipse.c textspan.c textspan_lut.c \
        args.c memory.c globals.c htmllex.c htmlparse.y htmltable.c input.c \
        pointset.c intset.c postproc.c routespl.c splines.c psusershape.c \
        timing.c labels.c ns.c shapes.c utils.c geom.c taper.c \
index 2cc1c6b9e7bee8cc3ab385eb9dee8a5bf9a332ae..46c77252f39cb9014d65d0d2109917fb58bbbe19 100644 (file)
 #include <string.h>
 #include <cdt/cdt.h>
 #include <common/render.h>
+#include <common/textspan_lut.h>
 #include <cgraph/strcasecmp.h>
 
-static double timesFontWidth[] = {
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.3329, 0.4079, 0.5000, 0.5000, 0.8329, 0.7779, 0.3329,    /*  !"#$%&' */
-    0.3329, 0.3329, 0.5000, 0.5639, 0.2500, 0.3329, 0.2500, 0.2779,    /* ()*+,-./ */
-    0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000,    /* 01234567 */
-    0.5000, 0.5000, 0.2779, 0.2779, 0.5639, 0.5639, 0.5639, 0.4439,    /* 89:;<=>? */
-    0.9209, 0.7219, 0.6669, 0.6669, 0.7219, 0.6109, 0.5559, 0.7219,    /* @ABCDEFG */
-    0.7219, 0.3329, 0.3889, 0.7219, 0.6109, 0.8889, 0.7219, 0.7219,    /* HIJKLMNO */
-    0.5559, 0.7219, 0.6669, 0.5559, 0.6109, 0.7219, 0.7219, 0.9439,    /* PQRSTUVW */
-    0.7219, 0.7219, 0.6109, 0.3329, 0.2779, 0.3329, 0.4689, 0.5000,    /* XYZ[\]^_ */
-    0.3329, 0.4439, 0.5000, 0.4439, 0.5000, 0.4439, 0.3329, 0.5000,    /* `abcdefg */
-    0.5000, 0.2779, 0.2779, 0.5000, 0.2779, 0.7779, 0.5000, 0.5000,    /* hijklmno */
-    0.5000, 0.5000, 0.3329, 0.3889, 0.2779, 0.5000, 0.5000, 0.7219,    /* pqrstuvw */
-    0.5000, 0.5000, 0.4439, 0.4799, 0.1999, 0.4799, 0.5409, 0.2500,    /* xyz{|}~  */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.3329, 0.5000, 0.5000, 0.1669, 0.5000, 0.5000, 0.5000,    /*  ¡¢£¤¥¦§ */
-    0.5000, 0.1799, 0.4439, 0.5000, 0.3329, 0.3329, 0.5559, 0.5559,    /* ¨©ª«¬­®¯ */
-    0.2500, 0.5000, 0.5000, 0.5000, 0.2500, 0.2500, 0.4529, 0.3499,    /*  ±²³´ ¶· */
-    0.3329, 0.4439, 0.4439, 0.5000, 1.0000, 1.0000, 0.2500, 0.4439,    /* ¸¹º»¼½ ¿ */
-    0.2500, 0.3329, 0.3329, 0.3329, 0.3329, 0.3329, 0.3329, 0.3329,    /*  ÁÂÃÄÅÆÇ */
-    0.3329, 0.2500, 0.3329, 0.3329, 0.2500, 0.3329, 0.3329, 0.3329,    /* È ÊË ÍÎÏ */
-    1.0000, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /* Ð        */
-    0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500, 0.2500,    /*          */
-    0.2500, 0.8889, 0.2500, 0.2759, 0.2500, 0.2500, 0.2500, 0.2500,    /*  á ã     */
-    0.6109, 0.7219, 0.8889, 0.3099, 0.2500, 0.2500, 0.2500, 0.2500,    /* èéêë     */
-    0.2500, 0.6669, 0.2500, 0.2500, 0.2500, 0.2779, 0.2500, 0.2500,    /*  ñ   õ   */
-    0.2779, 0.5000, 0.7219, 0.5000, 0.2500, 0.2500, 0.2500, 0.2500,    /* øùúû     */
-};
-static double arialFontWidth[] = {
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.3549, 0.5559, 0.5559, 0.8889, 0.6669, 0.2209,    /*  !"#$%&' */
-    0.3329, 0.3329, 0.3889, 0.5839, 0.2779, 0.3329, 0.2779, 0.2779,    /* ()*+,-./ */
-    0.5559, 0.5559, 0.5559, 0.5559, 0.5559, 0.5559, 0.5559, 0.5559,    /* 01234567 */
-    0.5559, 0.5559, 0.2779, 0.2779, 0.5839, 0.5839, 0.5839, 0.5559,    /* 89:;<=>? */
-    1.0149, 0.6669, 0.6669, 0.7219, 0.7219, 0.6669, 0.6109, 0.7779,    /* @ABCDEFG */
-    0.7219, 0.2779, 0.5000, 0.6669, 0.5559, 0.8329, 0.7219, 0.7779,    /* HIJKLMNO */
-    0.6669, 0.7779, 0.7219, 0.6669, 0.6109, 0.7219, 0.6669, 0.9439,    /* PQRSTUVW */
-    0.6669, 0.6669, 0.6109, 0.2779, 0.2779, 0.2779, 0.4689, 0.5559,    /* XYZ[\]^_ */
-    0.2219, 0.5559, 0.5559, 0.5000, 0.5559, 0.5559, 0.2779, 0.5559,    /* `abcdefg */
-    0.5559, 0.2219, 0.2219, 0.5000, 0.2219, 0.8329, 0.5559, 0.5559,    /* hijklmno */
-    0.5559, 0.5559, 0.3329, 0.5000, 0.2779, 0.5559, 0.5000, 0.7219,    /* pqrstuvw */
-    0.5000, 0.5000, 0.5000, 0.3339, 0.2599, 0.3339, 0.5839, 0.2779,    /* xyz{|}~  */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 0.3329, 0.5559, 0.5559, 0.1669, 0.5559, 0.5559, 0.5559,    /*  ¡¢£¤¥¦§ */
-    0.5559, 0.1909, 0.3329, 0.5559, 0.3329, 0.3329, 0.5000, 0.5000,    /* ¨©ª«¬­®¯ */
-    0.2779, 0.5559, 0.5559, 0.5559, 0.2779, 0.2779, 0.5369, 0.3499,    /*  ±²³´ ¶· */
-    0.2219, 0.3329, 0.3329, 0.5559, 1.0000, 1.0000, 0.2779, 0.6109,    /* ¸¹º»¼½ ¿ */
-    0.2779, 0.3329, 0.3329, 0.3329, 0.3329, 0.3329, 0.3329, 0.3329,    /*  ÁÂÃÄÅÆÇ */
-    0.3329, 0.2779, 0.3329, 0.3329, 0.2779, 0.3329, 0.3329, 0.3329,    /* È ÊË ÍÎÏ */
-    1.0000, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /* Ð        */
-    0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*          */
-    0.2779, 1.0000, 0.2779, 0.3699, 0.2779, 0.2779, 0.2779, 0.2779,    /*  á ã     */
-    0.5559, 0.7779, 1.0000, 0.3649, 0.2779, 0.2779, 0.2779, 0.2779,    /* èéêë     */
-    0.2779, 0.8889, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779, 0.2779,    /*  ñ   õ   */
-    0.2219, 0.6109, 0.9439, 0.6109, 0.2779, 0.2779, 0.2779, 0.2779,    /* øùúû     */
-};
-static double courFontWidth[] = {
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*  !"#$%&' */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* ()*+,-./ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* 01234567 */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* 89:;<=>? */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* @ABCDEFG */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* HIJKLMNO */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* PQRSTUVW */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* XYZ[\]^_ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* `abcdefg */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* hijklmno */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* pqrstuvw */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* xyz{|}~  */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*  ¡¢£¤¥¦§ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* ¨©ª«¬­®¯ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*  ±²³´ ¶· */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* ¸¹º»¼½ ¿ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*  ÁÂÃÄÅÆÇ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* È ÊË ÍÎÏ */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* Ð        */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*          */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*  á ã     */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* èéêë     */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /*  ñ   õ   */
-    0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999, 0.5999,    /* øùúû     */
-};
-
 /* estimate_textspan_size:
  * Estimate size of textspan, for given face and size, in points.
  */
 static void
 estimate_textspan_size(textspan_t * span, char **fontpath)
 {
-    double *Fontwidth, fontsize;
-    char c, *p, *fpp, *fontname;
+    double fontsize;
+
+    int flags = span->font->flags;
+    bool bold = (flags & HTML_BF) != 0;
+    bool italic = (flags & HTML_IF) != 0;
 
-    fontname = span->font->name;
     fontsize = span->font->size;
 
     span->size.x = 0.0;
@@ -136,28 +36,10 @@ estimate_textspan_size(textspan_t * span, char **fontpath)
     span->yoffset_centerline = 0.1 * fontsize;
     span->layout = NULL;
     span->free_layout = NULL;
+    span->size.x = fontsize * estimate_text_width_1pt(span->font->name, span->str, bold, italic);
 
-    if (!strncasecmp(fontname, "cour", 4)) {
-       fpp = "[internal courier]";
-       Fontwidth = courFontWidth;
-    } else if (!strncasecmp(fontname, "arial", 5)
-              || !strncasecmp(fontname, "helvetica", 9)) {
-       fpp = "[internal arial]";
-       Fontwidth = arialFontWidth;
-    } else {
-       fpp = "[internal times]";
-       Fontwidth = timesFontWidth;
-    }
     if (fontpath)
-       *fontpath = fpp;
-    if ((p = span->str)) {
-       while ((c = *p++))
-           span->size.x += Fontwidth[(unsigned char) c];
-       /* NOTE: Tables are based on a font of size 1. Need to multiply by
-        * fontsize to get appropriate value.
-        */
-       span->size.x *= fontsize;
-    }
+        *fontpath = "[internal hard-coded]";
 }
 
 /*
diff --git a/lib/common/textspan_lut.c b/lib/common/textspan_lut.c
new file mode 100644 (file)
index 0000000..dea7690
--- /dev/null
@@ -0,0 +1,833 @@
+#include <assert.h>
+#include <ctype.h>
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <common/textspan_lut.h>
+#include <common/types.h>
+#include <common/utils.h>
+
+// Currently we just store the width of every ASCII character, which seems to
+// produce good enough results. We could also store kerning metrics and line
+// heights for each font if we want to be more thorough.
+struct FontFamilyMetrics {
+  // A pipe-separated, case-insensitive list of font family names which these
+  // metrics correspond to. If multiple font families are listed, they should be
+  // metrically equivalent.
+  const char *font_name;
+  // Widths are stored in (units_per_em * 1) pt. (that is how TrueType works
+  // internally). A value of -1 indicates that the width for that character is
+  // unknown.
+  double units_per_em;
+  short widths_regular[128];
+  short widths_bold[128];
+  short widths_italic[128];
+  short widths_bold_italic[128];
+};
+
+static const struct FontFamilyMetrics all_font_metrics[] = {
+    // Times_New_Roman.ttf (+ variants) from ttf-mscorefonts-installer.
+    {
+        "times|timesroman|timesnewroman|freeserif|liberationserif|nimbusroman|"
+        "texgyretermes|tinos|thorndale",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   512,
+            682,  836,  1024, 1024, 1706, 1593, 369,  682,  682,  1024, 1155,
+            512,  682,  512,  569,  1024, 1024, 1024, 1024, 1024, 1024, 1024,
+            1024, 1024, 1024, 569,  569,  1155, 1155, 1155, 909,  1886, 1479,
+            1366, 1366, 1479, 1251, 1139, 1479, 1479, 682,  797,  1479, 1251,
+            1821, 1479, 1479, 1139, 1479, 1366, 1139, 1251, 1479, 1479, 1933,
+            1479, 1479, 1251, 682,  569,  682,  961,  1024, 682,  909,  1024,
+            909,  1024, 909,  682,  1024, 1024, 569,  569,  1024, 569,  1593,
+            1024, 1024, 1024, 1024, 682,  797,  569,  1024, 1024, 1479, 1024,
+            1024, 909,  983,  410,  983,  1108, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   512,
+            682,  1137, 1024, 1024, 2048, 1706, 569,  682,  682,  1024, 1167,
+            512,  682,  512,  569,  1024, 1024, 1024, 1024, 1024, 1024, 1024,
+            1024, 1024, 1024, 682,  682,  1167, 1167, 1167, 1024, 1905, 1479,
+            1366, 1479, 1479, 1366, 1251, 1593, 1593, 797,  1024, 1593, 1366,
+            1933, 1479, 1593, 1251, 1593, 1479, 1139, 1366, 1479, 1479, 2048,
+            1479, 1479, 1366, 682,  569,  682,  1190, 1024, 682,  1024, 1139,
+            909,  1139, 909,  682,  1024, 1139, 569,  682,  1139, 569,  1706,
+            1139, 1024, 1139, 1139, 909,  797,  682,  1139, 1024, 1479, 1024,
+            1024, 909,  807,  451,  807,  1065, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   512,
+            682,  860,  1024, 1024, 1706, 1593, 438,  682,  682,  1024, 1382,
+            512,  682,  512,  569,  1024, 1024, 1024, 1024, 1024, 1024, 1024,
+            1024, 1024, 1024, 682,  682,  1382, 1382, 1382, 1024, 1884, 1251,
+            1251, 1366, 1479, 1251, 1251, 1479, 1479, 682,  909,  1366, 1139,
+            1706, 1366, 1479, 1251, 1479, 1251, 1024, 1139, 1479, 1251, 1706,
+            1251, 1139, 1139, 797,  569,  797,  864,  1024, 682,  1024, 1024,
+            909,  1024, 909,  569,  1024, 1024, 569,  569,  909,  569,  1479,
+            1024, 1024, 1024, 1024, 797,  797,  569,  1024, 909,  1366, 909,
+            909,  797,  819,  563,  819,  1108, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   512,
+            797,  1137, 1024, 1024, 1706, 1593, 569,  682,  682,  1024, 1167,
+            512,  682,  512,  569,  1024, 1024, 1024, 1024, 1024, 1024, 1024,
+            1024, 1024, 1024, 682,  682,  1167, 1167, 1167, 1024, 1704, 1366,
+            1366, 1366, 1479, 1366, 1366, 1479, 1593, 797,  1024, 1366, 1251,
+            1821, 1479, 1479, 1251, 1479, 1366, 1139, 1251, 1479, 1366, 1821,
+            1366, 1251, 1251, 682,  569,  682,  1167, 1024, 682,  1024, 1024,
+            909,  1024, 909,  682,  1024, 1139, 569,  569,  1024, 569,  1593,
+            1139, 1024, 1024, 1024, 797,  797,  569,  1139, 909,  1366, 1024,
+            909,  797,  713,  451,  713,  1167, -1,
+        },
+    },
+    // Arial.ttf (+ variants) from ttf-mscorefonts-installer.
+    {
+        "helvetica|arial|arialmt|freesans|liberationsans|arimo|albany|"
+        "nimbussans|nimbussansa|texgyreheros|albany|arimo",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   569,
+            569,  727,  1139, 1139, 1821, 1366, 391,  682,  682,  797,  1196,
+            569,  682,  569,  569,  1139, 1139, 1139, 1139, 1139, 1139, 1139,
+            1139, 1139, 1139, 569,  569,  1196, 1196, 1196, 1139, 2079, 1366,
+            1366, 1479, 1479, 1366, 1251, 1593, 1479, 569,  1024, 1366, 1139,
+            1706, 1479, 1593, 1366, 1593, 1479, 1366, 1251, 1479, 1366, 1933,
+            1366, 1366, 1251, 569,  569,  569,  961,  1139, 682,  1139, 1139,
+            1024, 1139, 1139, 569,  1139, 1139, 455,  455,  1024, 455,  1706,
+            1139, 1139, 1139, 1139, 682,  1024, 569,  1139, 1024, 1479, 1024,
+            1024, 1024, 684,  532,  684,  1196, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   569,
+            682,  971,  1139, 1139, 1821, 1479, 487,  682,  682,  797,  1196,
+            569,  682,  569,  569,  1139, 1139, 1139, 1139, 1139, 1139, 1139,
+            1139, 1139, 1139, 682,  682,  1196, 1196, 1196, 1251, 1997, 1479,
+            1479, 1479, 1479, 1366, 1251, 1593, 1479, 569,  1139, 1479, 1251,
+            1706, 1479, 1593, 1366, 1593, 1479, 1366, 1251, 1479, 1366, 1933,
+            1366, 1366, 1251, 682,  569,  682,  1196, 1139, 682,  1139, 1251,
+            1139, 1251, 1139, 682,  1251, 1251, 569,  569,  1139, 569,  1821,
+            1251, 1251, 1251, 1251, 797,  1139, 682,  1251, 1139, 1593, 1139,
+            1139, 1024, 797,  573,  797,  1196, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   569,
+            569,  727,  1139, 1139, 1821, 1366, 391,  682,  682,  797,  1196,
+            569,  682,  569,  569,  1139, 1139, 1139, 1139, 1139, 1139, 1139,
+            1139, 1139, 1139, 569,  569,  1196, 1196, 1196, 1139, 2079, 1366,
+            1366, 1479, 1479, 1366, 1251, 1593, 1479, 569,  1024, 1366, 1139,
+            1706, 1479, 1593, 1366, 1593, 1479, 1366, 1251, 1479, 1366, 1933,
+            1366, 1366, 1251, 569,  569,  569,  961,  1139, 682,  1139, 1139,
+            1024, 1139, 1139, 569,  1139, 1139, 455,  455,  1024, 455,  1706,
+            1139, 1139, 1139, 1139, 682,  1024, 569,  1139, 1024, 1479, 1024,
+            1024, 1024, 684,  532,  684,  1196, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   569,
+            682,  971,  1139, 1139, 1821, 1479, 487,  682,  682,  797,  1196,
+            569,  682,  569,  569,  1139, 1139, 1139, 1139, 1139, 1139, 1139,
+            1139, 1139, 1139, 682,  682,  1196, 1196, 1196, 1251, 1997, 1479,
+            1479, 1479, 1479, 1366, 1251, 1593, 1479, 569,  1139, 1479, 1251,
+            1706, 1479, 1593, 1366, 1593, 1479, 1366, 1251, 1479, 1366, 1933,
+            1366, 1366, 1251, 682,  569,  682,  1196, 1139, 682,  1139, 1251,
+            1139, 1251, 1139, 682,  1251, 1251, 569,  569,  1139, 569,  1821,
+            1251, 1251, 1251, 1251, 797,  1139, 682,  1251, 1139, 1593, 1139,
+            1139, 1024, 797,  573,  797,  1196, -1,
+        },
+    },
+    // Courier_New.ttf (+ variants) from ttf-mscorefonts-installer.
+    {
+        "cour|courier|couriernew|nimbusmono|texgyrecursor|freemono|"
+        "liberationmono|cousine|cumberland",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229,
+            1229, 1229, 1229, 1229, 1229, 1229, -1,
+        },
+    },
+    // https://fonts.google.com/specimen/Nunito
+    {
+        "Nunito",
+        1000,
+        {
+            0,   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            258, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            -1,  -1,  -1,  -1,  -1,  -1,  258, 228, 392, 600,  600, 930, 693,
+            221, 317, 317, 450, 600, 228, 424, 228, 283, 600,  600, 600, 600,
+            600, 600, 600, 600, 600, 600, 228, 228, 600, 600,  600, 443, 946,
+            729, 676, 673, 742, 583, 548, 726, 761, 257, 324,  625, 543, 855,
+            740, 767, 633, 767, 669, 615, 602, 728, 689, 1101, 650, 596, 589,
+            315, 283, 315, 600, 500, 500, 530, 583, 463, 583,  532, 333, 586,
+            568, 232, 236, 500, 296, 856, 568, 556, 583, 583,  358, 481, 350,
+            561, 515, 841, 525, 514, 463, 352, 265, 352, 600,  -1,
+        },
+        {
+            0,   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            271, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            -1,  -1,  -1,  -1,  -1,  -1,  271, 248, 448, 600,  600, 945, 726,
+            243, 358, 358, 453, 600, 248, 434, 248, 313, 600,  600, 600, 600,
+            600, 600, 600, 600, 600, 600, 248, 248, 600, 600,  600, 459, 950,
+            744, 688, 680, 762, 597, 562, 736, 773, 282, 354,  665, 562, 868,
+            748, 785, 652, 785, 686, 631, 621, 738, 713, 1113, 672, 618, 605,
+            354, 313, 354, 600, 500, 500, 547, 600, 472, 600,  542, 364, 604,
+            585, 255, 259, 536, 319, 877, 585, 576, 600, 600,  392, 488, 384,
+            579, 527, 853, 546, 526, 474, 391, 288, 391, 600,  -1,
+        },
+        {
+            0,   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            258, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            -1,  -1,  -1,  -1,  -1,  -1,  258, 228, 392, 600,  600, 930, 693,
+            221, 317, 317, 450, 600, 228, 424, 228, 283, 600,  600, 600, 600,
+            600, 600, 600, 600, 600, 600, 228, 228, 600, 600,  600, 443, 946,
+            729, 676, 673, 742, 583, 548, 726, 761, 257, 324,  625, 543, 856,
+            739, 767, 633, 767, 669, 615, 602, 728, 688, 1101, 650, 596, 589,
+            315, 283, 315, 600, 500, 500, 530, 583, 463, 583,  532, 333, 586,
+            568, 232, 236, 500, 296, 856, 568, 556, 583, 583,  358, 481, 350,
+            561, 515, 841, 525, 514, 463, 352, 265, 352, 600,  -1,
+        },
+        {
+            0,   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            271, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   -1,  -1,  -1,
+            -1,  -1,  -1,  -1,  -1,  -1,  271, 248, 448, 600,  600, 945, 726,
+            243, 358, 358, 453, 600, 248, 434, 248, 313, 600,  600, 600, 600,
+            600, 600, 600, 600, 600, 600, 248, 248, 600, 600,  600, 459, 950,
+            744, 688, 680, 762, 597, 562, 736, 773, 282, 354,  664, 562, 869,
+            747, 785, 652, 785, 686, 631, 621, 738, 713, 1113, 672, 618, 605,
+            354, 313, 354, 600, 500, 500, 547, 600, 472, 600,  542, 364, 604,
+            585, 255, 259, 536, 319, 877, 585, 576, 600, 600,  392, 488, 384,
+            579, 527, 853, 546, 526, 474, 391, 288, 391, 600,  -1,
+        },
+    },
+    // Based on DejaVuSans, DejaVuSans-Bold, DejaVuSans-Oblique and
+    // DejaVuSans-BoldOblique (as opposed to italic)
+    {
+        "dejavusans",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   651,
+            821,  942,  1716, 1303, 1946, 1597, 563,  799,  799,  1024, 1716,
+            651,  739,  651,  690,  1303, 1303, 1303, 1303, 1303, 1303, 1303,
+            1303, 1303, 1303, 690,  690,  1716, 1716, 1716, 1087, 2048, 1401,
+            1405, 1430, 1577, 1294, 1178, 1587, 1540, 604,  604,  1343, 1141,
+            1767, 1532, 1612, 1235, 1612, 1423, 1300, 1251, 1499, 1401, 2025,
+            1403, 1251, 1403, 799,  690,  799,  1716, 1024, 1024, 1255, 1300,
+            1126, 1300, 1260, 721,  1300, 1298, 569,  569,  1186, 569,  1995,
+            1298, 1253, 1300, 1300, 842,  1067, 803,  1298, 1212, 1675, 1212,
+            1212, 1075, 1303, 690,  1303, 1716, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   713,
+            934,  1067, 1716, 1425, 2052, 1786, 627,  936,  936,  1071, 1716,
+            778,  850,  778,  748,  1425, 1425, 1425, 1425, 1425, 1425, 1425,
+            1425, 1425, 1425, 819,  819,  1716, 1716, 1716, 1188, 2048, 1585,
+            1561, 1503, 1700, 1399, 1399, 1681, 1714, 762,  762,  1587, 1305,
+            2038, 1714, 1741, 1501, 1741, 1577, 1475, 1397, 1663, 1585, 2259,
+            1579, 1483, 1485, 936,  748,  936,  1716, 1024, 1024, 1382, 1466,
+            1214, 1466, 1389, 891,  1466, 1458, 702,  702,  1362, 702,  2134,
+            1458, 1407, 1466, 1466, 1010, 1219, 979,  1458, 1335, 1892, 1321,
+            1335, 1192, 1458, 748,  1458, 1716, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   651,
+            821,  942,  1716, 1303, 1946, 1597, 563,  799,  799,  1024, 1716,
+            651,  739,  651,  690,  1303, 1303, 1303, 1303, 1303, 1303, 1303,
+            1303, 1303, 1303, 690,  690,  1716, 1716, 1716, 1087, 2048, 1401,
+            1405, 1430, 1577, 1294, 1178, 1587, 1540, 604,  604,  1343, 1141,
+            1767, 1532, 1612, 1235, 1612, 1423, 1300, 1251, 1499, 1401, 2025,
+            1403, 1251, 1403, 799,  690,  799,  1716, 1024, 1024, 1255, 1300,
+            1126, 1300, 1260, 721,  1300, 1298, 569,  569,  1186, 569,  1995,
+            1298, 1253, 1300, 1300, 842,  1067, 803,  1298, 1212, 1675, 1212,
+            1212, 1075, 1303, 690,  1303, 1716, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   713,
+            934,  1067, 1425, 1425, 2052, 1786, 627,  936,  936,  1071, 1716,
+            778,  850,  778,  748,  1425, 1425, 1425, 1425, 1425, 1425, 1425,
+            1425, 1425, 1425, 819,  819,  1716, 1716, 1716, 1188, 2048, 1585,
+            1561, 1503, 1700, 1399, 1399, 1681, 1714, 762,  762,  1587, 1305,
+            2038, 1714, 1741, 1501, 1741, 1577, 1475, 1397, 1663, 1585, 2259,
+            1579, 1483, 1485, 936,  748,  936,  1716, 1024, 1024, 1382, 1466,
+            1214, 1466, 1389, 891,  1466, 1458, 702,  702,  1362, 702,  2134,
+            1458, 1407, 1466, 1466, 1010, 1219, 979,  1458, 1335, 1892, 1321,
+            1335, 1192, 1458, 748,  1458, 1716, -1,
+        },
+    },
+    {
+        "consola|consolas",
+        2048,
+        {
+            1126, -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   0,    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, -1,
+        },
+        {
+            1126, -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   0,    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, -1,
+        },
+        {
+            1126, -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   0,    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+            1126, 1126, 1126, 1126, 1126, 1126, -1,
+        },
+    },
+    {
+        "Trebuchet MS|Trebuchet",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   617,
+            752,  665,  1074, 1074, 1229, 1446, 327,  752,  752,  752,  1074,
+            752,  752,  752,  1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074,
+            1074, 1074, 1074, 752,  752,  1074, 1074, 1074, 752,  1578, 1208,
+            1159, 1225, 1256, 1097, 1075, 1385, 1340, 570,  976,  1179, 1037,
+            1453, 1307, 1380, 1142, 1384, 1192, 985,  1189, 1328, 1203, 1745,
+            1140, 1168, 1127, 752,  728,  752,  1074, 1074, 1074, 1076, 1141,
+            1014, 1141, 1117, 757,  1028, 1119, 584,  751,  1033, 604,  1700,
+            1119, 1099, 1141, 1141, 796,  829,  812,  1119, 1003, 1524, 1026,
+            1010, 972,  752,  1074, 752,  1074, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   617,
+            752,  751,  1200, 1200, 1401, 1446, 470,  752,  752,  885,  1200,
+            752,  752,  752,  799,  1200, 1200, 1200, 1200, 1200, 1200, 1200,
+            1200, 1200, 1200, 752,  752,  1200, 1200, 1200, 897,  1578, 1297,
+            1219, 1253, 1316, 1165, 1195, 1375, 1400, 570,  1091, 1264, 1132,
+            1526, 1367, 1440, 1202, 1452, 1251, 1047, 1253, 1388, 1273, 1810,
+            1230, 1256, 1147, 823,  728,  823,  1200, 1200, 1200, 1091, 1191,
+            1048, 1189, 1177, 757,  1028, 1214, 611,  751,  1122, 604,  1760,
+            1209, 1159, 1193, 1196, 875,  882,  812,  1210, 1080, 1605, 1131,
+            1093, 1082, 888,  1200, 888,  1200, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   617,
+            752,  665,  1074, 985,  1229, 1446, 327,  752,  752,  752,  1074,
+            752,  752,  752,  1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074,
+            1074, 1074, 1074, 752,  752,  1074, 1074, 1074, 752,  1578, 1251,
+            1159, 1225, 1256, 1097, 1075, 1385, 1340, 570,  976,  1179, 1037,
+            1559, 1307, 1380, 1113, 1380, 1192, 985,  1189, 1328, 1203, 1745,
+            1140, 1168, 1127, 752,  728,  752,  1074, 1074, 1074, 1076, 1141,
+            942,  1141, 1100, 822,  1028, 1141, 628,  751,  1033, 656,  1700,
+            1119, 1099, 1141, 1141, 853,  829,  860,  1140, 1003, 1524, 1026,
+            1010, 972,  752,  1074, 752,  1074, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   617,
+            752,  800,  1200, 1200, 1500, 1446, 617,  752,  752,  885,  1200,
+            752,  752,  752,  813,  1200, 1200, 1200, 1200, 1200, 1200, 1200,
+            1200, 1200, 1200, 752,  752,  1200, 1200, 1200, 813,  1578, 1257,
+            1208, 1255, 1295, 1215, 1199, 1385, 1389, 570,  1021, 1331, 1082,
+            1610, 1352, 1438, 1195, 1576, 1277, 1027, 1403, 1355, 1399, 1897,
+            1345, 1400, 1252, 994,  978,  994,  1200, 1200, 1200, 1214, 1215,
+            1009, 1215, 1130, 840,  1096, 1151, 669,  794,  1105, 655,  1700,
+            1151, 1167, 1226, 1226, 915,  940,  897,  1141, 1131, 1584, 1179,
+            1155, 1091, 994,  1200, 994,  1200, -1,
+        },
+    },
+    {
+        "Verdana",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   720,
+            806,  940,  1676, 1302, 2204, 1488, 550,  930,  930,  1302, 1676,
+            745,  930,  745,  930,  1302, 1302, 1302, 1302, 1302, 1302, 1302,
+            1302, 1302, 1302, 930,  930,  1676, 1676, 1676, 1117, 2048, 1400,
+            1404, 1430, 1578, 1295, 1177, 1588, 1539, 862,  931,  1419, 1140,
+            1726, 1532, 1612, 1235, 1612, 1424, 1400, 1262, 1499, 1400, 2025,
+            1403, 1260, 1403, 930,  930,  930,  1676, 1302, 1302, 1230, 1276,
+            1067, 1276, 1220, 720,  1276, 1296, 562,  705,  1212, 562,  1992,
+            1296, 1243, 1276, 1276, 874,  1067, 807,  1296, 1212, 1676, 1212,
+            1212, 1076, 1300, 930,  1300, 1676, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   700,
+            824,  1203, 1776, 1456, 2605, 1766, 680,  1113, 1113, 1456, 1776,
+            740,  983,  740,  1412, 1456, 1456, 1456, 1456, 1456, 1456, 1456,
+            1456, 1456, 1456, 824,  824,  1776, 1776, 1776, 1263, 1974, 1590,
+            1560, 1482, 1700, 1399, 1332, 1661, 1715, 1118, 1137, 1579, 1305,
+            1941, 1734, 1741, 1501, 1741, 1602, 1455, 1396, 1663, 1564, 2311,
+            1564, 1509, 1417, 1113, 1412, 1113, 1776, 1456, 1456, 1368, 1432,
+            1205, 1432, 1360, 865,  1432, 1459, 700,  825,  1374, 700,  2167,
+            1459, 1406, 1432, 1432, 1018, 1215, 933,  1459, 1331, 2006, 1370,
+            1333, 1222, 1456, 1113, 1456, 1776, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   720,
+            806,  940,  1676, 1302, 2204, 1488, 550,  930,  930,  1302, 1676,
+            745,  930,  745,  930,  1302, 1302, 1302, 1302, 1302, 1302, 1302,
+            1302, 1302, 1302, 930,  930,  1676, 1676, 1676, 1117, 2048, 1398,
+            1404, 1430, 1568, 1295, 1177, 1588, 1539, 862,  931,  1419, 1140,
+            1726, 1532, 1612, 1235, 1612, 1424, 1400, 1262, 1499, 1398, 2028,
+            1403, 1260, 1403, 930,  930,  930,  1676, 1302, 1302, 1230, 1276,
+            1067, 1276, 1220, 720,  1273, 1296, 562,  705,  1202, 562,  1993,
+            1296, 1243, 1276, 1276, 874,  1067, 807,  1296, 1210, 1676, 1212,
+            1210, 1076, 1300, 930,  1300, 1676, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   700,
+            824,  1203, 1776, 1456, 2605, 1766, 680,  1113, 1113, 1456, 1776,
+            740,  983,  740,  1412, 1456, 1456, 1456, 1456, 1456, 1456, 1456,
+            1456, 1456, 1456, 824,  824,  1776, 1776, 1776, 1263, 1974, 1590,
+            1560, 1482, 1700, 1399, 1332, 1661, 1715, 1118, 1137, 1579, 1305,
+            1941, 1734, 1741, 1501, 1741, 1602, 1455, 1396, 1663, 1564, 2311,
+            1564, 1509, 1417, 1113, 1412, 1113, 1776, 1456, 1456, 1368, 1432,
+            1205, 1432, 1360, 865,  1432, 1459, 700,  825,  1374, 700,  2167,
+            1459, 1404, 1432, 1432, 1018, 1215, 933,  1459, 1329, 2006, 1370,
+            1333, 1222, 1456, 1113, 1456, 1776, -1,
+        },
+    },
+    {
+        "OpenSans",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   532,
+            547,  821,  1323, 1171, 1686, 1495, 453,  606,  606,  1130, 1171,
+            502,  659,  545,  752,  1171, 1171, 1171, 1171, 1171, 1171, 1171,
+            1171, 1171, 1171, 545,  545,  1171, 1171, 1171, 879,  1841, 1296,
+            1327, 1292, 1493, 1139, 1057, 1491, 1511, 571,  547,  1257, 1063,
+            1849, 1544, 1595, 1233, 1595, 1266, 1124, 1133, 1491, 1219, 1896,
+            1182, 1147, 1169, 674,  752,  674,  1110, 918,  1182, 1139, 1255,
+            975,  1255, 1149, 694,  1122, 1257, 518,  518,  1075, 518,  1905,
+            1257, 1237, 1255, 1255, 836,  977,  723,  1257, 1026, 1593, 1073,
+            1032, 958,  776,  1128, 776,  1171, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   532,
+            586,  967,  1323, 1169, 1845, 1536, 545,  694,  694,  1116, 1169,
+            594,  659,  584,  846,  1169, 1169, 1169, 1169, 1169, 1169, 1169,
+            1169, 1169, 1169, 584,  594,  1169, 1169, 1169, 977,  1837, 1413,
+            1376, 1305, 1516, 1147, 1124, 1483, 1567, 678,  678,  1360, 1157,
+            1931, 1665, 1630, 1286, 1630, 1352, 1128, 1186, 1548, 1331, 1980,
+            1366, 1278, 1186, 678,  846,  678,  1090, 842,  1243, 1237, 1296,
+            1053, 1296, 1210, 793,  1157, 1346, 625,  625,  1270, 625,  2011,
+            1346, 1268, 1296, 1296, 930,  1018, 889,  1346, 1165, 1753, 1184,
+            1165, 999,  807,  1128, 807,  1169, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   532,
+            530,  791,  1323, 1128, 1624, 1372, 444,  584,  584,  1130, 1128,
+            492,  639,  518,  717,  1128, 1128, 1128, 1128, 1128, 1128, 1128,
+            1128, 1128, 1128, 518,  518,  1128, 1128, 1128, 874,  1735, 1137,
+            1225, 1198, 1364, 1047, 967,  1386, 1389, 559,  547,  1141, 971,
+            1714, 1438, 1475, 1159, 1475, 1165, 1028, 1020, 1384, 1122, 1745,
+            1063, 1030, 1087, 586,  717,  586,  1059, 807,  1135, 1157, 1182,
+            922,  1182, 1010, 641,  1026, 1182, 520,  520,  999,  520,  1786,
+            1182, 1149, 1182, 1182, 811,  877,  664,  1182, 946,  1468, 979,
+            946,  909,  715,  1128, 715,  1128, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   532,
+            586,  928,  1323, 1128, 1753, 1450, 522,  694,  694,  1116, 1128,
+            569,  659,  584,  862,  1128, 1128, 1128, 1128, 1128, 1128, 1128,
+            1128, 1128, 1128, 584,  584,  1128, 1128, 1128, 940,  1753, 1286,
+            1270, 1253, 1386, 1110, 1087, 1413, 1434, 659,  678,  1255, 1061,
+            1802, 1546, 1495, 1188, 1495, 1247, 1085, 1087, 1415, 1208, 1831,
+            1241, 1155, 1098, 678,  862,  678,  1081, 819,  1135, 1217, 1219,
+            989,  1217, 1141, 764,  1108, 1237, 608,  608,  1163, 608,  1853,
+            1237, 1198, 1219, 1217, 862,  969,  840,  1237, 1049, 1614, 1087,
+            1063, 932,  727,  1128, 727,  1128, -1,
+        },
+    },
+    {
+        "Georgia",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   494,
+            678,  843,  1317, 1249, 1674, 1455, 441,  768,  768,  967,  1317,
+            552,  766,  552,  960,  1257, 880,  1144, 1130, 1157, 1082, 1159,
+            1029, 1221, 1159, 640,  640,  1317, 1317, 1317, 980,  1902, 1374,
+            1339, 1315, 1534, 1338, 1227, 1485, 1669, 798,  1060, 1422, 1236,
+            1899, 1571, 1524, 1249, 1524, 1437, 1149, 1267, 1549, 1365, 1998,
+            1455, 1260, 1232, 768,  960,  768,  1317, 1317, 1024, 1032, 1147,
+            930,  1176, 990,  666,  1043, 1192, 600,  598,  1097, 586,  1804,
+            1210, 1104, 1170, 1146, 839,  885,  707,  1178, 1017, 1510, 1034,
+            1008, 909,  881,  768,  881,  1317, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   520,
+            771,  1044, 1440, 1312, 1801, 1637, 551,  915,  915,  987,  1440,
+            672,  776,  672,  966,  1436, 1003, 1283, 1279, 1330, 1227, 1327,
+            1135, 1385, 1327, 752,  752,  1440, 1440, 1440, 1123, 1980, 1553,
+            1551, 1465, 1708, 1477, 1375, 1653, 1870, 913,  1219, 1673, 1404,
+            2096, 1719, 1679, 1436, 1679, 1633, 1329, 1401, 1707, 1561, 2307,
+            1656, 1499, 1412, 915,  966,  915,  1440, 1440, 1024, 1220, 1322,
+            1088, 1358, 1171, 805,  1181, 1392, 724,  709,  1294, 705,  2080,
+            1413, 1302, 1347, 1328, 1065, 1050, 814,  1386, 1161, 1768, 1204,
+            1151, 1076, 1024, 794,  1024, 1440, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   494,
+            678,  843,  1317, 1249, 1674, 1455, 441,  768,  768,  967,  1317,
+            552,  766,  552,  960,  1257, 880,  1144, 1130, 1157, 1082, 1159,
+            1017, 1221, 1159, 786,  786,  1317, 1317, 1317, 980,  1902, 1374,
+            1339, 1315, 1534, 1338, 1227, 1485, 1669, 798,  1060, 1422, 1236,
+            1899, 1571, 1496, 1249, 1496, 1437, 1149, 1267, 1549, 1365, 1998,
+            1455, 1260, 1232, 768,  960,  768,  1317, 1317, 1024, 1173, 1134,
+            929,  1178, 966,  673,  1173, 1152, 609,  596,  1081, 584,  1801,
+            1208, 1100, 1184, 1137, 945,  883,  711,  1178, 1102, 1684, 1026,
+            1146, 909,  881,  768,  881,  1317, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   520,
+            771,  1044, 1440, 1312, 1801, 1637, 551,  915,  915,  987,  1440,
+            672,  776,  672,  966,  1436, 1003, 1283, 1279, 1330, 1227, 1327,
+            1160, 1385, 1327, 752,  752,  1440, 1440, 1440, 1123, 1980, 1553,
+            1555, 1465, 1708, 1477, 1375, 1653, 1870, 923,  1219, 1673, 1404,
+            2116, 1699, 1679, 1446, 1679, 1633, 1337, 1401, 1707, 1561, 2307,
+            1643, 1499, 1412, 915,  966,  915,  1440, 1440, 1024, 1352, 1329,
+            1097, 1357, 1141, 780,  1330, 1383, 749,  747,  1313, 726,  2052,
+            1413, 1302, 1357, 1331, 1093, 1059, 854,  1403, 1254, 1912, 1195,
+            1371, 1059, 1024, 794,  1024, 1440, -1,
+        },
+    },
+    {
+        "Calibri",
+        2048,
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   463,
+            667,  821,  1020, 1038, 1464, 1397, 452,  621,  621,  1020, 1020,
+            511,  627,  517,  791,  1038, 1038, 1038, 1038, 1038, 1038, 1038,
+            1038, 1038, 1038, 548,  548,  1020, 1020, 1020, 949,  1831, 1185,
+            1114, 1092, 1260, 1000, 941,  1292, 1276, 516,  653,  1064, 861,
+            1751, 1322, 1356, 1058, 1378, 1112, 941,  998,  1314, 1162, 1822,
+            1063, 998,  959,  628,  791,  628,  1020, 1020, 596,  981,  1076,
+            866,  1076, 1019, 625,  964,  1076, 470,  490,  931,  470,  1636,
+            1076, 1080, 1076, 1076, 714,  801,  686,  1076, 925,  1464, 887,
+            927,  809,  644,  943,  644,  1020, -1,
+        },
+        {
+            0,    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   0,    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   463,
+            667,  898,  1020, 1038, 1493, 1443, 478,  638,  638,  1020, 1020,
+            528,  627,  547,  880,  1038, 1038, 1038, 1038, 1038, 1038, 1038,
+            1038, 1038, 1038, 565,  565,  1020, 1020, 1020, 949,  1840, 1241,
+            1148, 1084, 1291, 999,  940,  1305, 1292, 546,  678,  1120, 866,
+            1790, 1349, 1385, 1090, 1405, 1153, 968,  1014, 1337, 1211, 1856,
+            1128, 1064, 979,  665,  880,  665,  1020, 1020, 615,  1011, 1099,
+            857,  1099, 1031, 648,  971,  1099, 503,  523,  983,  503,  1666,
+            1099, 1101, 1099, 1099, 728,  817,  710,  1099, 969,  1526, 941,
+            970,  814,  704,  973,  704,  1020, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   463,
+            667,  821,  1020, 1038, 1464, 1397, 452,  621,  621,  1020, 1020,
+            511,  627,  517,  794,  1038, 1038, 1038, 1038, 1038, 1038, 1038,
+            1038, 1038, 1038, 548,  548,  1020, 1020, 1020, 949,  1831, 1185,
+            1114, 1070, 1260, 1000, 941,  1292, 1276, 516,  653,  1064, 861,
+            1751, 1320, 1340, 1058, 1360, 1112, 926,  998,  1314, 1162, 1823,
+            1063, 998,  959,  628,  787,  628,  1020, 1020, 596,  1053, 1053,
+            852,  1053, 978,  625,  1053, 1053, 470,  490,  931,  470,  1620,
+            1053, 1051, 1053, 1053, 702,  797,  686,  1053, 913,  1464, 887,
+            916,  809,  644,  943,  644,  1020, -1,
+        },
+        {
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   463,
+            667,  898,  1020, 1038, 1493, 1443, 478,  638,  638,  1020, 1020,
+            528,  627,  547,  889,  1038, 1038, 1038, 1038, 1038, 1038, 1038,
+            1038, 1038, 1038, 565,  565,  1020, 1020, 1020, 949,  1840, 1241,
+            1148, 1062, 1291, 999,  940,  1305, 1292, 546,  678,  1120, 866,
+            1790, 1344, 1369, 1090, 1387, 1153, 953,  1014, 1337, 1211, 1857,
+            1128, 1064, 979,  665,  870,  665,  1020, 1020, 615,  1081, 1081,
+            843,  1081, 1006, 648,  1081, 1080, 503,  523,  983,  503,  1646,
+            1080, 1080, 1081, 1081, 721,  807,  710,  1080, 961,  1526, 941,
+            963,  814,  704,  973,  704,  1020, -1,
+        },
+    },
+};
+
+const static size_t all_font_metrics_len =
+    sizeof(all_font_metrics) / sizeof(all_font_metrics[0]);
+
+/// Compares two font names for equality, ignoring case and special characters.
+///
+/// E.g. "timesroman", "Times-Roman", "times ROMAN", "times_roman" and
+/// "tim8esroman" are all considered equal to eachother, but not equal to "Times
+/// New Roman".
+static bool font_name_equal_permissive(const char *a, const char *b,
+                                       const size_t b_length) {
+  assert(strlen(b) >= b_length);
+  size_t a_length = strlen(a);
+  size_t a_pos = 0;
+  size_t b_pos = 0;
+  while (a_pos != a_length && b_pos != b_length) {
+    if (!isalpha_no_locale(a[a_pos])) {
+      ++a_pos;
+      continue;
+    }
+    if (!isalpha_no_locale(b[b_pos])) {
+      ++b_pos;
+      continue;
+    }
+    if (tolower(a[a_pos]) != tolower(b[b_pos])) {
+      return false;
+    }
+    ++a_pos;
+    ++b_pos;
+  }
+  while (a_pos != a_length) {
+    if (isalpha_no_locale(a[a_pos])) {
+      return false;
+    }
+    ++a_pos;
+  }
+  while (b_pos != b_length) {
+    if (isalpha_no_locale(b[b_pos])) {
+      return false;
+    }
+    ++b_pos;
+  }
+  return true;
+}
+
+/// Checks whether a font name is in a pipe-separated list of font names,
+/// ignoring case and special characters.
+///
+/// E.g. "Times-Roman" and "TimesNewRoman" are both in
+/// "times|timesroman|timesnewroman", but "Arial" is not.
+static bool font_in_list_permissive(const char *value, const char *list) {
+  assert(value && strlen(value));
+  assert(list && strlen(list));
+
+  do {
+    const char *next_pipe = strchr(list, '|');
+    size_t next_pipe_or_end_pos = next_pipe ? next_pipe - list : strlen(list);
+    if (font_name_equal_permissive(value, list, next_pipe_or_end_pos)) {
+      return true;
+    }
+    list = next_pipe ? next_pipe + 1 : NULL;
+  } while (list);
+
+  return false;
+}
+
+static const struct FontFamilyMetrics *
+get_metrics_for_font_family(const char *font_name) {
+  for (size_t i = 0; i < all_font_metrics_len; i++) {
+    if (font_in_list_permissive(font_name, all_font_metrics[i].font_name)) {
+      return &all_font_metrics[i];
+    }
+  }
+  fprintf(stderr,
+          "Warning: no hard-coded metrics for '%s'.  Falling back to 'Times' "
+          "metrics\n",
+          font_name);
+  return get_metrics_for_font_family("Times");
+}
+
+static const short *
+get_metrics_for_font_variant(const struct FontFamilyMetrics *family_metrics,
+                             bool bold, bool italic) {
+  if (bold && italic) {
+    return family_metrics->widths_bold_italic;
+  }
+  if (bold) {
+    return family_metrics->widths_bold;
+  }
+  if (italic) {
+    return family_metrics->widths_italic;
+  }
+  return family_metrics->widths_regular;
+}
+
+/// @returns the width of the character in (units_per_em * 1) points.
+static unsigned short
+estimate_character_width_canonical(const short variant_metrics[128],
+                                   unsigned character) {
+  if (character >= 128) {
+    static bool warning_already_reported = false;
+    if (!warning_already_reported) { // stderr spam prevention
+      warning_already_reported = true;
+      fprintf(stderr,
+              "Warning: no value for width of non-ASCII character %u. Falling "
+              "back to width of space character\n",
+              character);
+    }
+    character = ' ';
+  }
+  short width = variant_metrics[character];
+  if (width == -1) {
+    static bool warning_already_reported = false;
+    if (!warning_already_reported) { // stderr spam prevention
+      warning_already_reported = true;
+      fprintf(stderr,
+              "Warning: no value for width of ASCII character %u. Falling back "
+              "to 0\n",
+              character);
+    }
+    width = 0;
+  }
+  assert(width >= 0);
+  return width;
+}
+
+double estimate_text_width_1pt(const char *font_name, const char *text,
+                               bool bold, bool italic) {
+  assert(font_name);
+  assert(text);
+
+  const struct FontFamilyMetrics *family_metrics =
+      get_metrics_for_font_family(font_name);
+  const short *variant_metrics =
+      get_metrics_for_font_variant(family_metrics, bold, italic);
+  unsigned text_width_canonical = 0;
+  for (const char *c = text; *c != '\0'; c++) {
+    text_width_canonical +=
+        estimate_character_width_canonical(variant_metrics, (unsigned char)*c);
+  }
+  return (double)text_width_canonical / family_metrics->units_per_em;
+}
diff --git a/lib/common/textspan_lut.h b/lib/common/textspan_lut.h
new file mode 100644 (file)
index 0000000..38ab1bd
--- /dev/null
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <stdbool.h>
+
+// LUT is short for lookup table.
+
+/// @param text a single line of ASCII text which should contain no control characters.
+/// @returns the estimated width of `text` in 1 point. A value is always returned, falling back to Times-Roman metrics 
+/// if there is no hard-coded lookup table for the given `font_name`.
+double estimate_text_width_1pt(const char* font_name, const char* text, bool bold, bool italic);
index 7c4436fdc34348adddf2b5612676b408a0fe7e96..6385a6f3ae7e8a41c7ead7918124985d6c25fc63 100644 (file)
@@ -134,6 +134,7 @@ awk -f $(SolutionDir)awk\colortbl.awk color_lib &gt; common\colortbl.h</Command>
     <ClInclude Include="common\ps_font_equiv.h" />
     <ClInclude Include="common\render.h" />
     <ClInclude Include="common\textspan.h" />
+    <ClInclude Include="common\textspan_lut.h" />
     <ClInclude Include="common\types.h" />
     <ClInclude Include="common\usershape.h" />
     <ClInclude Include="common\utils.h" />
@@ -177,6 +178,7 @@ awk -f $(SolutionDir)awk\colortbl.awk color_lib &gt; common\colortbl.h</Command>
     <ClCompile Include="common\splines.c" />
     <ClCompile Include="common\taper.c" />
     <ClCompile Include="common\textspan.c" />
+    <ClCompile Include="common\textspan_lut.c" />
     <ClCompile Include="common\timing.c" />
     <ClCompile Include="common\utils.c" />
     <ClCompile Include="common\xml.c" />
index 600aa1ba2b7bc648696f29b98076763cd29ff5da..3a23b79c51a3cf6e03481ca5fb248211cdc645aa 100644 (file)
@@ -75,6 +75,9 @@
     <ClInclude Include="common\textspan.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="common\textspan_lut.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="common\types.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="common\textspan.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="common\textspan_lut.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="common\geom.c">
       <Filter>Source Files</Filter>
     </ClCompile>