www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

fontMetrics.js (7301B)


      1 /* eslint no-unused-vars:0 */
      2 
      3 const Style = require("./Style");
      4 const cjkRegex = require("./unicodeRegexes").cjkRegex;
      5 
      6 /**
      7  * This file contains metrics regarding fonts and individual symbols. The sigma
      8  * and xi variables, as well as the metricMap map contain data extracted from
      9  * TeX, TeX font metrics, and the TTF files. These data are then exposed via the
     10  * `metrics` variable and the getCharacterMetrics function.
     11  */
     12 
     13 // In TeX, there are actually three sets of dimensions, one for each of
     14 // textstyle, scriptstyle, and scriptscriptstyle.  These are provided in the
     15 // the arrays below, in that order.
     16 //
     17 // The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively.
     18 // This was determined by running the folllowing script:
     19 //
     20 //     latex -interaction=nonstopmode \
     21 //     '\documentclass{article}\usepackage{amsmath}\begin{document}' \
     22 //     '$a$ \expandafter\show\the\textfont2' \
     23 //     '\expandafter\show\the\scriptfont2' \
     24 //     '\expandafter\show\the\scriptscriptfont2' \
     25 //     '\stop'
     26 //
     27 // The metrics themselves were retreived using the following commands:
     28 //
     29 //     tftopl cmsy10
     30 //     tftopl cmsy7
     31 //     tftopl cmsy5
     32 //
     33 // The output of each of these commands is quite lengthy.  The only part we
     34 // care about is the FONTDIMEN section. Each value is measured in EMs.
     35 const sigmas = {
     36     slant: [0.250, 0.250, 0.250],       // sigma1
     37     space: [0.000, 0.000, 0.000],       // sigma2
     38     stretch: [0.000, 0.000, 0.000],     // sigma3
     39     shrink: [0.000, 0.000, 0.000],      // sigma4
     40     xHeight: [0.431, 0.431, 0.431],     // sigma5
     41     quad: [1.000, 1.171, 1.472],        // sigma6
     42     extraSpace: [0.000, 0.000, 0.000],  // sigma7
     43     num1: [0.677, 0.732, 0.925],        // sigma8
     44     num2: [0.394, 0.384, 0.387],        // sigma9
     45     num3: [0.444, 0.471, 0.504],        // sigma10
     46     denom1: [0.686, 0.752, 1.025],      // sigma11
     47     denom2: [0.345, 0.344, 0.532],      // sigma12
     48     sup1: [0.413, 0.503, 0.504],        // sigma13
     49     sup2: [0.363, 0.431, 0.404],        // sigma14
     50     sup3: [0.289, 0.286, 0.294],        // sigma15
     51     sub1: [0.150, 0.143, 0.200],        // sigma16
     52     sub2: [0.247, 0.286, 0.400],        // sigma17
     53     supDrop: [0.386, 0.353, 0.494],     // sigma18
     54     subDrop: [0.050, 0.071, 0.100],     // sigma19
     55     delim1: [2.390, 1.700, 1.980],      // sigma20
     56     delim2: [1.010, 1.157, 1.420],      // sigma21
     57     axisHeight: [0.250, 0.250, 0.250],  // sigma22
     58 };
     59 
     60 // These font metrics are extracted from TeX by using
     61 // \font\a=cmex10
     62 // \showthe\fontdimenX\a
     63 // where X is the corresponding variable number. These correspond to the font
     64 // parameters of the extension fonts (family 3). See the TeXbook, page 441.
     65 const xi1 = 0;
     66 const xi2 = 0;
     67 const xi3 = 0;
     68 const xi4 = 0;
     69 const xi5 = 0.431;
     70 const xi6 = 1;
     71 const xi7 = 0;
     72 const xi8 = 0.04;
     73 const xi9 = 0.111;
     74 const xi10 = 0.166;
     75 const xi11 = 0.2;
     76 const xi12 = 0.6;
     77 const xi13 = 0.1;
     78 
     79 // This value determines how large a pt is, for metrics which are defined in
     80 // terms of pts.
     81 // This value is also used in katex.less; if you change it make sure the values
     82 // match.
     83 const ptPerEm = 10.0;
     84 
     85 // The space between adjacent `|` columns in an array definition. From
     86 // `\showthe\doublerulesep` in LaTeX.
     87 const doubleRuleSep = 2.0 / ptPerEm;
     88 
     89 /**
     90  * This is just a mapping from common names to real metrics
     91  */
     92 const metrics = {
     93     defaultRuleThickness: xi8,
     94     bigOpSpacing1: xi9,
     95     bigOpSpacing2: xi10,
     96     bigOpSpacing3: xi11,
     97     bigOpSpacing4: xi12,
     98     bigOpSpacing5: xi13,
     99     ptPerEm: ptPerEm,
    100     doubleRuleSep: doubleRuleSep,
    101 };
    102 
    103 // This map contains a mapping from font name and character code to character
    104 // metrics, including height, depth, italic correction, and skew (kern from the
    105 // character to the corresponding \skewchar)
    106 // This map is generated via `make metrics`. It should not be changed manually.
    107 const metricMap = require("./fontMetricsData");
    108 
    109 // These are very rough approximations.  We default to Times New Roman which
    110 // should have Latin-1 and Cyrillic characters, but may not depending on the
    111 // operating system.  The metrics do not account for extra height from the
    112 // accents.  In the case of Cyrillic characters which have both ascenders and
    113 // descenders we prefer approximations with ascenders, primarily to prevent
    114 // the fraction bar or root line from intersecting the glyph.
    115 // TODO(kevinb) allow union of multiple glyph metrics for better accuracy.
    116 const extraCharacterMap = {
    117     // Latin-1
    118     'À': 'A',
    119     'Á': 'A',
    120     'Â': 'A',
    121     'Ã': 'A',
    122     'Ä': 'A',
    123     'Å': 'A',
    124     'Æ': 'A',
    125     'Ç': 'C',
    126     'È': 'E',
    127     'É': 'E',
    128     'Ê': 'E',
    129     'Ë': 'E',
    130     'Ì': 'I',
    131     'Í': 'I',
    132     'Î': 'I',
    133     'Ï': 'I',
    134     'Ð': 'D',
    135     'Ñ': 'N',
    136     'Ò': 'O',
    137     'Ó': 'O',
    138     'Ô': 'O',
    139     'Õ': 'O',
    140     'Ö': 'O',
    141     'Ø': 'O',
    142     'Ù': 'U',
    143     'Ú': 'U',
    144     'Û': 'U',
    145     'Ü': 'U',
    146     'Ý': 'Y',
    147     'Þ': 'o',
    148     'ß': 'B',
    149     'à': 'a',
    150     'á': 'a',
    151     'â': 'a',
    152     'ã': 'a',
    153     'ä': 'a',
    154     'å': 'a',
    155     'æ': 'a',
    156     'ç': 'c',
    157     'è': 'e',
    158     'é': 'e',
    159     'ê': 'e',
    160     'ë': 'e',
    161     'ì': 'i',
    162     'í': 'i',
    163     'î': 'i',
    164     'ï': 'i',
    165     'ð': 'd',
    166     'ñ': 'n',
    167     'ò': 'o',
    168     'ó': 'o',
    169     'ô': 'o',
    170     'õ': 'o',
    171     'ö': 'o',
    172     'ø': 'o',
    173     'ù': 'u',
    174     'ú': 'u',
    175     'û': 'u',
    176     'ü': 'u',
    177     'ý': 'y',
    178     'þ': 'o',
    179     'ÿ': 'y',
    180 
    181     // Cyrillic
    182     'А': 'A',
    183     'Б': 'B',
    184     'В': 'B',
    185     'Г': 'F',
    186     'Д': 'A',
    187     'Е': 'E',
    188     'Ж': 'K',
    189     'З': '3',
    190     'И': 'N',
    191     'Й': 'N',
    192     'К': 'K',
    193     'Л': 'N',
    194     'М': 'M',
    195     'Н': 'H',
    196     'О': 'O',
    197     'П': 'N',
    198     'Р': 'P',
    199     'С': 'C',
    200     'Т': 'T',
    201     'У': 'y',
    202     'Ф': 'O',
    203     'Х': 'X',
    204     'Ц': 'U',
    205     'Ч': 'h',
    206     'Ш': 'W',
    207     'Щ': 'W',
    208     'Ъ': 'B',
    209     'Ы': 'X',
    210     'Ь': 'B',
    211     'Э': '3',
    212     'Ю': 'X',
    213     'Я': 'R',
    214     'а': 'a',
    215     'б': 'b',
    216     'в': 'a',
    217     'г': 'r',
    218     'д': 'y',
    219     'е': 'e',
    220     'ж': 'm',
    221     'з': 'e',
    222     'и': 'n',
    223     'й': 'n',
    224     'к': 'n',
    225     'л': 'n',
    226     'м': 'm',
    227     'н': 'n',
    228     'о': 'o',
    229     'п': 'n',
    230     'р': 'p',
    231     'с': 'c',
    232     'т': 'o',
    233     'у': 'y',
    234     'ф': 'b',
    235     'х': 'x',
    236     'ц': 'n',
    237     'ч': 'n',
    238     'ш': 'w',
    239     'щ': 'w',
    240     'ъ': 'a',
    241     'ы': 'm',
    242     'ь': 'a',
    243     'э': 'e',
    244     'ю': 'm',
    245     'я': 'r',
    246 };
    247 
    248 /**
    249  * This function is a convenience function for looking up information in the
    250  * metricMap table. It takes a character as a string, and a style.
    251  *
    252  * Note: the `width` property may be undefined if fontMetricsData.js wasn't
    253  * built using `Make extended_metrics`.
    254  */
    255 const getCharacterMetrics = function(character, style) {
    256     let ch = character.charCodeAt(0);
    257     if (character[0] in extraCharacterMap) {
    258         ch = extraCharacterMap[character[0]].charCodeAt(0);
    259     } else if (cjkRegex.test(character[0])) {
    260         ch = 'M'.charCodeAt(0);
    261     }
    262     const metrics = metricMap[style][ch];
    263     if (metrics) {
    264         return {
    265             depth: metrics[0],
    266             height: metrics[1],
    267             italic: metrics[2],
    268             skew: metrics[3],
    269             width: metrics[4],
    270         };
    271     }
    272 };
    273 
    274 module.exports = {
    275     metrics: metrics,
    276     sigmas: sigmas,
    277     getCharacterMetrics: getCharacterMetrics,
    278 };