mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-07 12:18:39 +00:00
Summary: This diff provides support for Latin-1, Cyrillic, and CJK characters inside \text{} groups. For Latin-1 and Cyrillic characters we use glyph metrics from a glyph from Basic Latin that has roughly the same bounding box. We use the metrics for a capital 'M' to approximate the full-width CJK characters. Half-width characters are not supported yet. Test Plan: - make test - make screenshots Reviewers: emily
294 lines
6.8 KiB
JavaScript
294 lines
6.8 KiB
JavaScript
/* eslint no-unused-vars:0 */
|
||
|
||
var Style = require("./Style");
|
||
var cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||
|
||
/**
|
||
* This file contains metrics regarding fonts and individual symbols. The sigma
|
||
* and xi variables, as well as the metricMap map contain data extracted from
|
||
* TeX, TeX font metrics, and the TTF files. These data are then exposed via the
|
||
* `metrics` variable and the getCharacterMetrics function.
|
||
*/
|
||
|
||
// These font metrics are extracted from TeX by using
|
||
// \font\a=cmmi10
|
||
// \showthe\fontdimenX\a
|
||
// where X is the corresponding variable number. These correspond to the font
|
||
// parameters of the symbol fonts. In TeX, there are actually three sets of
|
||
// dimensions, one for each of textstyle, scriptstyle, and scriptscriptstyle,
|
||
// but we only use the textstyle ones, and scale certain dimensions accordingly.
|
||
// See the TeXbook, page 441.
|
||
var sigma1 = 0.025;
|
||
var sigma2 = 0;
|
||
var sigma3 = 0;
|
||
var sigma4 = 0;
|
||
var sigma5 = 0.431;
|
||
var sigma6 = 1;
|
||
var sigma7 = 0;
|
||
var sigma8 = 0.677;
|
||
var sigma9 = 0.394;
|
||
var sigma10 = 0.444;
|
||
var sigma11 = 0.686;
|
||
var sigma12 = 0.345;
|
||
var sigma13 = 0.413;
|
||
var sigma14 = 0.363;
|
||
var sigma15 = 0.289;
|
||
var sigma16 = 0.150;
|
||
var sigma17 = 0.247;
|
||
var sigma18 = 0.386;
|
||
var sigma19 = 0.050;
|
||
var sigma20 = 2.390;
|
||
var sigma21 = 1.01;
|
||
var sigma21Script = 0.81;
|
||
var sigma21ScriptScript = 0.71;
|
||
var sigma22 = 0.250;
|
||
|
||
// These font metrics are extracted from TeX by using
|
||
// \font\a=cmex10
|
||
// \showthe\fontdimenX\a
|
||
// where X is the corresponding variable number. These correspond to the font
|
||
// parameters of the extension fonts (family 3). See the TeXbook, page 441.
|
||
var xi1 = 0;
|
||
var xi2 = 0;
|
||
var xi3 = 0;
|
||
var xi4 = 0;
|
||
var xi5 = 0.431;
|
||
var xi6 = 1;
|
||
var xi7 = 0;
|
||
var xi8 = 0.04;
|
||
var xi9 = 0.111;
|
||
var xi10 = 0.166;
|
||
var xi11 = 0.2;
|
||
var xi12 = 0.6;
|
||
var xi13 = 0.1;
|
||
|
||
// This value determines how large a pt is, for metrics which are defined in
|
||
// terms of pts.
|
||
// This value is also used in katex.less; if you change it make sure the values
|
||
// match.
|
||
var ptPerEm = 10.0;
|
||
|
||
// The space between adjacent `|` columns in an array definition. From
|
||
// `\showthe\doublerulesep` in LaTeX.
|
||
var doubleRuleSep = 2.0 / ptPerEm;
|
||
|
||
/**
|
||
* This is just a mapping from common names to real metrics
|
||
*/
|
||
var metrics = {
|
||
xHeight: sigma5,
|
||
quad: sigma6,
|
||
num1: sigma8,
|
||
num2: sigma9,
|
||
num3: sigma10,
|
||
denom1: sigma11,
|
||
denom2: sigma12,
|
||
sup1: sigma13,
|
||
sup2: sigma14,
|
||
sup3: sigma15,
|
||
sub1: sigma16,
|
||
sub2: sigma17,
|
||
supDrop: sigma18,
|
||
subDrop: sigma19,
|
||
axisHeight: sigma22,
|
||
defaultRuleThickness: xi8,
|
||
bigOpSpacing1: xi9,
|
||
bigOpSpacing2: xi10,
|
||
bigOpSpacing3: xi11,
|
||
bigOpSpacing4: xi12,
|
||
bigOpSpacing5: xi13,
|
||
ptPerEm: ptPerEm,
|
||
emPerEx: sigma5 / sigma6,
|
||
doubleRuleSep: doubleRuleSep,
|
||
|
||
// TODO(alpert): Missing parallel structure here. We should probably add
|
||
// style-specific metrics for all of these.
|
||
delim1: sigma20,
|
||
getDelim2: function(style) {
|
||
if (style.size === Style.TEXT.size) {
|
||
return sigma21;
|
||
} else if (style.size === Style.SCRIPT.size) {
|
||
return sigma21Script;
|
||
} else if (style.size === Style.SCRIPTSCRIPT.size) {
|
||
return sigma21ScriptScript;
|
||
}
|
||
throw new Error("Unexpected style size: " + style.size);
|
||
},
|
||
};
|
||
|
||
// This map contains a mapping from font name and character code to character
|
||
// metrics, including height, depth, italic correction, and skew (kern from the
|
||
// character to the corresponding \skewchar)
|
||
// This map is generated via `make metrics`. It should not be changed manually.
|
||
var metricMap = require("./fontMetricsData");
|
||
|
||
// These are very rough approximations. We default to Times New Roman which
|
||
// should have Latin-1 and Cyrillic characters, but may not depending on the
|
||
// operating system. The metrics do not account for extra height from the
|
||
// accents. In the case of Cyrillic characters which have both ascenders and
|
||
// descenders we prefer approximations with ascenders, primarily to prevent
|
||
// the fraction bar or root line from intersecting the glyph.
|
||
// TODO(kevinb) allow union of multiple glyph metrics for better accuracy.
|
||
var extraCharacterMap = {
|
||
// Latin-1
|
||
'À': 'A',
|
||
'Á': 'A',
|
||
'Â': 'A',
|
||
'Ã': 'A',
|
||
'Ä': 'A',
|
||
'Å': 'A',
|
||
'Æ': 'A',
|
||
'Ç': 'C',
|
||
'È': 'E',
|
||
'É': 'E',
|
||
'Ê': 'E',
|
||
'Ë': 'E',
|
||
'Ì': 'I',
|
||
'Í': 'I',
|
||
'Î': 'I',
|
||
'Ï': 'I',
|
||
'Ð': 'D',
|
||
'Ñ': 'N',
|
||
'Ò': 'O',
|
||
'Ó': 'O',
|
||
'Ô': 'O',
|
||
'Õ': 'O',
|
||
'Ö': 'O',
|
||
'Ø': 'O',
|
||
'Ù': 'U',
|
||
'Ú': 'U',
|
||
'Û': 'U',
|
||
'Ü': 'U',
|
||
'Ý': 'Y',
|
||
'Þ': 'o',
|
||
'ß': 'B',
|
||
'à': 'a',
|
||
'á': 'a',
|
||
'â': 'a',
|
||
'ã': 'a',
|
||
'ä': 'a',
|
||
'å': 'a',
|
||
'æ': 'a',
|
||
'ç': 'c',
|
||
'è': 'e',
|
||
'é': 'e',
|
||
'ê': 'e',
|
||
'ë': 'e',
|
||
'ì': 'i',
|
||
'í': 'i',
|
||
'î': 'i',
|
||
'ï': 'i',
|
||
'ð': 'd',
|
||
'ñ': 'n',
|
||
'ò': 'o',
|
||
'ó': 'o',
|
||
'ô': 'o',
|
||
'õ': 'o',
|
||
'ö': 'o',
|
||
'ø': 'o',
|
||
'ù': 'u',
|
||
'ú': 'u',
|
||
'û': 'u',
|
||
'ü': 'u',
|
||
'ý': 'y',
|
||
'þ': 'o',
|
||
'ÿ': 'y',
|
||
|
||
// Cyrillic
|
||
'А': 'A',
|
||
'Б': 'B',
|
||
'В': 'B',
|
||
'Г': 'F',
|
||
'Д': 'A',
|
||
'Е': 'E',
|
||
'Ж': 'K',
|
||
'З': '3',
|
||
'И': 'N',
|
||
'Й': 'N',
|
||
'К': 'K',
|
||
'Л': 'N',
|
||
'М': 'M',
|
||
'Н': 'H',
|
||
'О': 'O',
|
||
'П': 'N',
|
||
'Р': 'P',
|
||
'С': 'C',
|
||
'Т': 'T',
|
||
'У': 'y',
|
||
'Ф': 'O',
|
||
'Х': 'X',
|
||
'Ц': 'U',
|
||
'Ч': 'h',
|
||
'Ш': 'W',
|
||
'Щ': 'W',
|
||
'Ъ': 'B',
|
||
'Ы': 'X',
|
||
'Ь': 'B',
|
||
'Э': '3',
|
||
'Ю': 'X',
|
||
'Я': 'R',
|
||
'а': 'a',
|
||
'б': 'b',
|
||
'в': 'a',
|
||
'г': 'r',
|
||
'д': 'y',
|
||
'е': 'e',
|
||
'ж': 'm',
|
||
'з': 'e',
|
||
'и': 'n',
|
||
'й': 'n',
|
||
'к': 'n',
|
||
'л': 'n',
|
||
'м': 'm',
|
||
'н': 'n',
|
||
'о': 'o',
|
||
'п': 'n',
|
||
'р': 'p',
|
||
'с': 'c',
|
||
'т': 'o',
|
||
'у': 'y',
|
||
'ф': 'b',
|
||
'х': 'x',
|
||
'ц': 'n',
|
||
'ч': 'n',
|
||
'ш': 'w',
|
||
'щ': 'w',
|
||
'ъ': 'a',
|
||
'ы': 'm',
|
||
'ь': 'a',
|
||
'э': 'e',
|
||
'ю': 'm',
|
||
'я': 'r',
|
||
};
|
||
|
||
/**
|
||
* This function is a convenience function for looking up information in the
|
||
* metricMap table. It takes a character as a string, and a style.
|
||
*
|
||
* Note: the `width` property may be undefined if fontMetricsData.js wasn't
|
||
* built using `Make extended_metrics`.
|
||
*/
|
||
var getCharacterMetrics = function(character, style) {
|
||
var ch = character.charCodeAt(0);
|
||
if (character[0] in extraCharacterMap) {
|
||
ch = extraCharacterMap[character[0]].charCodeAt(0);
|
||
} else if (cjkRegex.test(character[0])) {
|
||
ch = 'M'.charCodeAt(0);
|
||
}
|
||
var metrics = metricMap[style][ch];
|
||
if (metrics) {
|
||
return {
|
||
depth: metrics[0],
|
||
height: metrics[1],
|
||
italic: metrics[2],
|
||
skew: metrics[3],
|
||
width: metrics[4],
|
||
};
|
||
}
|
||
};
|
||
|
||
module.exports = {
|
||
metrics: metrics,
|
||
getCharacterMetrics: getCharacterMetrics,
|
||
};
|