Stacking text commands (#1009)

* Adding support for SansSerif-Bold

* Updating to include SansSerif Italic.

* WIP

* Working text stacking

* More robust screenshot.

* Don't want to break users :)

* Updating per PR comments.

* Fixing Unicode and updating snapshots.

* Adding suggested tests.

* Opting to use old method for unit testing.

* Adding TODO
This commit is contained in:
Ryan Randall
2017-12-13 09:10:23 -05:00
committed by Kevin Barabash
parent cf23517499
commit 50765a0ccd
15 changed files with 533 additions and 48 deletions

View File

@@ -36,6 +36,8 @@ def main():
'cmtt10.tfm',
'rsfs10.tfm',
'cmss10.tfm',
'cmssbx10.tfm',
'cmssi10.tfm',
]
# Extracted by running `\font\a=<font>` and then `\showthe\skewchar\a` in
@@ -57,6 +59,8 @@ def main():
'cmtt10': None,
'rsfs10': None,
'cmss10': None,
'cmssbx10': None,
'cmssi10': None,
}
font_name_to_tfm = {}

View File

@@ -1004,6 +1004,94 @@ $map{rsfs10} = {
],
};
$map{cmssbx10} = {
"SansSerif-Bold" => [
[0,1] => 0x393, # \Gamma, \Delta
2 => 0x398, # \Theta
3 => 0x39B, # \Lambda
4 => 0x39E, # \Xi
5 => 0x3A0, # \Pi
6 => 0x3A3, # \Sigma
[7,8] => 0x3A5, # \Upsilon, \Phi
[9,0xA] => 0x3A8, # \Psi, \Omega
0x10 => 0x131, # \imath (roman)
0x11 => 0x237, # \jmath (roman)
0x12 => [0x300,-550,0], # \grave (combining)
0x13 => [0x301,-550,0], # \acute (combining)
0x14 => [0x30C,-550,0], # \check (combining)
0x15 => [0x306,-550,0], # \breve (combining)
0x16 => [0x304,-550,0], # \bar (combining)
0x17 => [0x30A,-608,0], # ring above (combining)
[0x21,0x2F] => 0x21, # !, ", #, $, %, &, ', (, ), *, +, comma, -, ., /
0x22 => 0x201D, # "
0x27 => 0x2019, # '
[0x30,0x39] => 0x30, # 0-9
[0x3A,0x3B] => 0x3A, # :, ;
0x3D => 0x3D, # =
[0x3F,0x40] => 0x3F, # ?, @
[0x41,0x5A] => 0x41, # A-Z
0x5B => 0x5B, # [
0x5C => 0x201C, # ``
[0x5D,0x5E] => 0x5D, # ], ^
0x5E => [0x302,-550,0], # \hat (combining)
0x5F => [0x307,-428,0], # \dot (combining)
0x60 => 0x2018, # `
[0x61,0x7A] => 0x61, # a-z
[0x7B,0x7C] => 0x2013, # \endash, \emdash
0x7B => [0x5F,0,-350], # underline
0x7D => [0x30B,-550,0], # double acute (combining)
0x7E => [0x7E,0,-350], # ~
0x7E => [0x303,-550,0], # \tilde (combining)
0x7F => [0x308,-550,0], # \ddot (combining)
],
};
$map{cmssi10} = {
"SansSerif-Italic" => [
[0,1] => 0x393, # \Gamma, \Delta
2 => 0x398, # \Theta
3 => 0x39B, # \Lambda
4 => 0x39E, # \Xi
5 => 0x3A0, # \Pi
6 => 0x3A3, # \Sigma
[7,8] => 0x3A5, # \Upsilon, \Phi
[9,0xA] => 0x3A8, # \Psi, \Omega
0x10 => 0x131, # \imath (roman)
0x11 => 0x237, # \jmath (roman)
0x12 => [0x300,-500,0], # \grave (combining)
0x13 => [0x301,-500,0], # \acute (combining)
0x14 => [0x30C,-500,0], # \check (combining)
0x15 => [0x306,-500,0], # \breve (combining)
0x16 => [0x304,-500,0], # \bar (combining)
0x17 => [0x30A,-613,0], # ring above (combining)
[0x21,0x2F] => 0x21, # !, ", #, $, %, &, ', (, ), *, +, comma, -, ., /
0x22 => 0x201D, # "
0x27 => 0x2019, # '
[0x30,0x39] => 0x30, # 0-9
[0x3A,0x3B] => 0x3A, # :, ;
0x3D => 0x3D, # =
[0x3F,0x40] => 0x3F, # ?, @
[0x41,0x5A] => 0x41, # A-Z
0x5B => 0x5B, # [
0x5C => 0x201C, # ``
[0x5D,0x5E] => 0x5D, # ], ^
0x5E => [0x302,-500,0], # \hat (combining)
0x5F => [0x307,-389,0], # \dot (combining)
0x60 => 0x2018, # `
[0x61,0x7A] => 0x61, # a-z
[0x7B,0x7C] => 0x2013, # \endash, \emdash
0x7B => [0x5F,0,-350], # underline
0x7D => [0x30B,-500,0], # double acute (combining)
0x7E => [0x7E,0,-350], # ~
0x7E => [0x303,-500,0], # \tilde (combining)
0x7F => [0x308,-500,0], # \ddot (combining)
],
};
$map{cmss10} = {
"SansSerif-Regular" => [
[0,1] => 0x393, # \Gamma, \Delta

View File

@@ -45,6 +45,7 @@
"object-assign": "^4.1.0",
"pako": "1.0.4",
"pre-commit": "^1.2.2",
"rimraf": "^2.6.2",
"selenium-webdriver": "^2.48.2",
"sri-toolbox": "^0.2.0",
"stylelint": "^8.2.0",
@@ -58,13 +59,14 @@
"lint": "eslint katex.js server.js cli.js webpack.config.js webpackDevServer.js src test contrib dockers && stylelint static/fonts.less static/katex.less",
"flow": "flow",
"jest": "jest",
"jest-update": "jest --updateSnapshot",
"coverage": "jest --coverage",
"copy": "cp -a static/. build/ && cp -a contrib build/",
"clean": "rm -rf build/* node_modules/",
"clean-install": "npm run clean && npm i",
"test": "check-dependencies && npm run lint && npm run flow && npm run jest",
"build-css": "lessc --clean-css static/katex.less build/katex.css",
"prestart": "npm run build-css && npm run copy",
"prestart": "rimraf build && npm run build-css && npm run copy",
"start": "check-dependencies && node webpackDevServer.js",
"prepublishOnly": "make NIS= dist"
},

View File

@@ -42,7 +42,11 @@ export type OptionsData = {
size?: number;
textSize?: number;
phantom?: boolean;
font?: string | void;
// TODO(#1009): Keep consistent with fontFamily/fontWeight. Ensure this has a
// string value.
fontFamily?: string | void;
fontWeight?: string;
fontShape?: string;
maxSize: number;
};
@@ -59,7 +63,9 @@ class Options {
size: number;
textSize: number;
phantom: boolean;
font: string | void;
fontFamily: string | void;
fontWeight: string;
fontShape: string;
sizeMultiplier: number;
maxSize: number;
_fontMetrics: FontMetrics | void;
@@ -75,7 +81,9 @@ class Options {
this.size = data.size || Options.BASESIZE;
this.textSize = data.textSize || this.size;
this.phantom = !!data.phantom;
this.font = data.font;
this.fontFamily = data.fontFamily;
this.fontWeight = data.fontWeight || '';
this.fontShape = data.fontShape || '';
this.sizeMultiplier = sizeMultipliers[this.size - 1];
this.maxSize = data.maxSize;
this._fontMetrics = undefined;
@@ -92,7 +100,9 @@ class Options {
textSize: this.textSize,
color: this.color,
phantom: this.phantom,
font: this.font,
fontFamily: this.fontFamily,
fontWeight: this.fontWeight,
fontShape: this.fontShape,
maxSize: this.maxSize,
};
@@ -183,9 +193,27 @@ class Options {
/**
* Create a new options objects with the give font.
*/
withFont(font: ?string): Options {
withFontFamily(fontFamily: ?string): Options {
return this.extend({
font: font || this.font,
fontFamily: fontFamily || this.fontFamily,
});
}
/**
* Creates a new options object with the given font weight
*/
withFontWeight(fontWeight: string): Options {
return this.extend({
fontWeight,
});
}
/**
* Creates a new options object with the given font weight
*/
withFontShape(fontShape: string): Options {
return this.extend({
fontShape,
});
}

View File

@@ -115,7 +115,7 @@ const mathsym = function(
// text ordinal and is therefore not present as a symbol in the symbols
// table for text, as well as a special case for boldsymbol because it
// can be used for bold + and -
if ((options && options.font && options.font === "boldsymbol") &&
if ((options && options.fontFamily && options.fontFamily === "boldsymbol") &&
lookupSymbol(value, "Main-Bold", mode).metrics) {
return makeSymbol(value, "Main-Bold", mode, options,
classes.concat(["mathbf"]));
@@ -144,12 +144,17 @@ const mathDefault = function(
} else if (type === "textord") {
const font = symbols[mode][value] && symbols[mode][value].font;
if (font === "ams") {
const fontName = retrieveTextFontName("amsrm", options.fontWeight,
options.fontShape);
return makeSymbol(
value, "AMS-Regular", mode, options, classes.concat(["amsrm"]));
value, fontName, mode, options,
classes.concat("amsrm", options.fontWeight, options.fontShape));
} else { // if (font === "main") {
const fontName = retrieveTextFontName("textrm", options.fontWeight,
options.fontShape);
return makeSymbol(
value, "Main-Regular", mode, options,
classes.concat(["mathrm"]));
value, fontName, mode, options,
classes.concat(options.fontWeight, options.fontShape));
}
} else {
throw new Error("unexpected type: " + type + " in mathDefault");
@@ -224,19 +229,31 @@ const makeOrd = function(
const classes = ["mord"];
const font = options.font;
if (font) {
let fontLookup;
if (font === "boldsymbol") {
fontLookup = boldsymbol(value, mode, options, classes);
} else if (font === "mathit" || utils.contains(mainitLetters, value)) {
fontLookup = mathit(value, mode, options, classes);
const fontFamily = options.fontFamily;
if (fontFamily) {
let fontName;
let fontClasses;
if (fontFamily === "boldsymbol") {
const fontData = boldsymbol(value, mode, options, classes);
fontName = fontData.fontName;
fontClasses = [fontData.fontClass];
} else if (fontFamily === "mathit" ||
utils.contains(mainitLetters, value)) {
const fontData = mathit(value, mode, options, classes);
fontName = fontData.fontName;
fontClasses = [fontData.fontClass];
} else if (fontFamily.includes("math") || mode === "math") {
// To support old font functions (i.e. \rm \sf etc.) or math mode.
fontName = fontMap[fontFamily].fontName;
fontClasses = [fontFamily];
} else {
fontLookup = fontMap[font];
fontName = retrieveTextFontName(fontFamily, options.fontWeight,
options.fontShape);
fontClasses = [fontFamily, options.fontWeight, options.fontShape];
}
if (lookupSymbol(value, fontLookup.fontName, mode).metrics) {
return makeSymbol(value, fontLookup.fontName, mode, options,
classes.concat([fontLookup.fontClass || font]));
if (lookupSymbol(value, fontName, mode).metrics) {
return makeSymbol(value, fontName, mode, options,
classes.concat(fontClasses));
} else {
return mathDefault(value, mode, options, classes, type);
}
@@ -570,6 +587,52 @@ const makeVerb = function(group: ParseNode, options: Options): string {
return text;
};
// Takes an Options object, and returns the appropriate fontLookup
const retrieveTextFontName = function(
fontFamily: string,
fontWeight: string,
fontShape: string,
): string {
const baseFontName = retrieveBaseFontName(fontFamily);
const fontStylesName = retrieveFontStylesName(fontWeight, fontShape);
return `${baseFontName}-${fontStylesName}`;
};
const retrieveBaseFontName = function(font: string): string {
let baseFontName = "";
switch (font) {
case "amsrm":
baseFontName = "AMS";
break;
case "textrm":
baseFontName = "Main";
break;
case "textsf":
baseFontName = "SansSerif";
break;
case "texttt":
baseFontName = "Typewriter";
break;
default:
throw new Error(`Invalid font provided: ${font}`);
}
return baseFontName;
};
const retrieveFontStylesName = function(
fontWeight?: string,
fontShape?: string,
): string {
let fontStylesName = '';
if (fontWeight === "textbf") {
fontStylesName += "Bold";
}
if (fontShape === "textit") {
fontStylesName += "Italic";
}
return fontStylesName || "Regular";
};
// A map of spacing functions to their attributes, like size and corresponding
// CSS class
const spacingFunctions: {[string]: {| size: string, className: string |}} = {

View File

@@ -591,7 +591,7 @@ groupTypes.styling = function(group, options) {
groupTypes.font = function(group, options) {
const font = group.value.font;
return buildGroup(group.value.body, options.withFont(font));
return buildGroup(group.value.body, options.withFontFamily(font));
};
groupTypes.verb = function(group, options) {

View File

@@ -31,7 +31,7 @@ export const makeText = function(text, mode) {
* Returns the math variant as a string or null if none is required.
*/
const getVariant = function(group, options) {
const font = options.font;
const font = options.fontFamily;
if (!font) {
return null;
}
@@ -54,7 +54,7 @@ const getVariant = function(group, options) {
const fontName = buildCommon.fontMap[font].fontName;
if (fontMetrics.getCharacterMetrics(value, fontName)) {
return buildCommon.fontMap[options.font].variant;
return buildCommon.fontMap[font].variant;
}
return null;
@@ -268,7 +268,7 @@ groupTypes.spacing = function(group) {
groupTypes.font = function(group, options) {
const font = group.value.font;
return buildGroup(group.value.body, options.withFont(font));
return buildGroup(group.value.body, options.withFontFamily(font));
};
groupTypes.styling = function(group, options) {

View File

@@ -246,6 +246,9 @@ const getCharacterMetrics = function(
character: string,
font: string,
): ?CharacterMetrics {
if (!metricMap[font]) {
throw new Error(`Font metrics not found for font: ${font}.`);
}
let ch = character.charCodeAt(0);
if (character[0] in extraCharacterMap) {
ch = extraCharacterMap[character[0]].charCodeAt(0);

View File

@@ -1,5 +1,4 @@
// @flow
const fontMetricsData = {
module.exports = {
"AMS-Regular": {
"65": [0, 0.68889, 0, 0],
"66": [0, 0.68889, 0, 0],
@@ -1331,6 +1330,244 @@ const fontMetricsData = {
"1009": [0.19444, 0.43056, 0, 0.08334],
"1013": [0, 0.43056, 0, 0.05556],
},
"SansSerif-Bold": {
"33": [0, 0.69444, 0, 0],
"34": [0, 0.69444, 0, 0],
"35": [0.19444, 0.69444, 0, 0],
"36": [0.05556, 0.75, 0, 0],
"37": [0.05556, 0.75, 0, 0],
"38": [0, 0.69444, 0, 0],
"39": [0, 0.69444, 0, 0],
"40": [0.25, 0.75, 0, 0],
"41": [0.25, 0.75, 0, 0],
"42": [0, 0.75, 0, 0],
"43": [0.11667, 0.61667, 0, 0],
"44": [0.10556, 0.13056, 0, 0],
"45": [0, 0.45833, 0, 0],
"46": [0, 0.13056, 0, 0],
"47": [0.25, 0.75, 0, 0],
"48": [0, 0.69444, 0, 0],
"49": [0, 0.69444, 0, 0],
"50": [0, 0.69444, 0, 0],
"51": [0, 0.69444, 0, 0],
"52": [0, 0.69444, 0, 0],
"53": [0, 0.69444, 0, 0],
"54": [0, 0.69444, 0, 0],
"55": [0, 0.69444, 0, 0],
"56": [0, 0.69444, 0, 0],
"57": [0, 0.69444, 0, 0],
"58": [0, 0.45833, 0, 0],
"59": [0.10556, 0.45833, 0, 0],
"61": [-0.09375, 0.40625, 0, 0],
"63": [0, 0.69444, 0, 0],
"64": [0, 0.69444, 0, 0],
"65": [0, 0.69444, 0, 0],
"66": [0, 0.69444, 0, 0],
"67": [0, 0.69444, 0, 0],
"68": [0, 0.69444, 0, 0],
"69": [0, 0.69444, 0, 0],
"70": [0, 0.69444, 0, 0],
"71": [0, 0.69444, 0, 0],
"72": [0, 0.69444, 0, 0],
"73": [0, 0.69444, 0, 0],
"74": [0, 0.69444, 0, 0],
"75": [0, 0.69444, 0, 0],
"76": [0, 0.69444, 0, 0],
"77": [0, 0.69444, 0, 0],
"78": [0, 0.69444, 0, 0],
"79": [0, 0.69444, 0, 0],
"80": [0, 0.69444, 0, 0],
"81": [0.10556, 0.69444, 0, 0],
"82": [0, 0.69444, 0, 0],
"83": [0, 0.69444, 0, 0],
"84": [0, 0.69444, 0, 0],
"85": [0, 0.69444, 0, 0],
"86": [0, 0.69444, 0.01528, 0],
"87": [0, 0.69444, 0.01528, 0],
"88": [0, 0.69444, 0, 0],
"89": [0, 0.69444, 0.0275, 0],
"90": [0, 0.69444, 0, 0],
"91": [0.25, 0.75, 0, 0],
"93": [0.25, 0.75, 0, 0],
"94": [0, 0.69444, 0, 0],
"95": [0.35, 0.10833, 0.03056, 0],
"97": [0, 0.45833, 0, 0],
"98": [0, 0.69444, 0, 0],
"99": [0, 0.45833, 0, 0],
"100": [0, 0.69444, 0, 0],
"101": [0, 0.45833, 0, 0],
"102": [0, 0.69444, 0.07639, 0],
"103": [0.19444, 0.45833, 0.01528, 0],
"104": [0, 0.69444, 0, 0],
"105": [0, 0.69444, 0, 0],
"106": [0.19444, 0.69444, 0, 0],
"107": [0, 0.69444, 0, 0],
"108": [0, 0.69444, 0, 0],
"109": [0, 0.45833, 0, 0],
"110": [0, 0.45833, 0, 0],
"111": [0, 0.45833, 0, 0],
"112": [0.19444, 0.45833, 0, 0],
"113": [0.19444, 0.45833, 0, 0],
"114": [0, 0.45833, 0.01528, 0],
"115": [0, 0.45833, 0, 0],
"116": [0, 0.58929, 0, 0],
"117": [0, 0.45833, 0, 0],
"118": [0, 0.45833, 0.01528, 0],
"119": [0, 0.45833, 0.01528, 0],
"120": [0, 0.45833, 0, 0],
"121": [0.19444, 0.45833, 0.01528, 0],
"122": [0, 0.45833, 0, 0],
"126": [0.35, 0.34444, 0, 0],
"305": [0, 0.45833, 0, 0],
"567": [0.19444, 0.45833, 0, 0],
"768": [0, 0.69444, 0, 0],
"769": [0, 0.69444, 0, 0],
"770": [0, 0.69444, 0, 0],
"771": [0, 0.69444, 0, 0],
"772": [0, 0.63778, 0, 0],
"774": [0, 0.69444, 0, 0],
"775": [0, 0.69444, 0, 0],
"776": [0, 0.69444, 0, 0],
"778": [0, 0.69444, 0, 0],
"779": [0, 0.69444, 0, 0],
"780": [0, 0.63542, 0, 0],
"915": [0, 0.69444, 0, 0],
"916": [0, 0.69444, 0, 0],
"920": [0, 0.69444, 0, 0],
"923": [0, 0.69444, 0, 0],
"926": [0, 0.69444, 0, 0],
"928": [0, 0.69444, 0, 0],
"931": [0, 0.69444, 0, 0],
"933": [0, 0.69444, 0, 0],
"934": [0, 0.69444, 0, 0],
"936": [0, 0.69444, 0, 0],
"937": [0, 0.69444, 0, 0],
"8211": [0, 0.45833, 0.03056, 0],
"8212": [0, 0.45833, 0.03056, 0],
"8216": [0, 0.69444, 0, 0],
"8217": [0, 0.69444, 0, 0],
"8220": [0, 0.69444, 0, 0],
"8221": [0, 0.69444, 0, 0],
},
"SansSerif-Italic": {
"33": [0, 0.69444, 0.05733, 0],
"34": [0, 0.69444, 0.00316, 0],
"35": [0.19444, 0.69444, 0.05087, 0],
"36": [0.05556, 0.75, 0.11156, 0],
"37": [0.05556, 0.75, 0.03126, 0],
"38": [0, 0.69444, 0.03058, 0],
"39": [0, 0.69444, 0.07816, 0],
"40": [0.25, 0.75, 0.13164, 0],
"41": [0.25, 0.75, 0.02536, 0],
"42": [0, 0.75, 0.11775, 0],
"43": [0.08333, 0.58333, 0.02536, 0],
"44": [0.125, 0.08333, 0, 0],
"45": [0, 0.44444, 0.01946, 0],
"46": [0, 0.08333, 0, 0],
"47": [0.25, 0.75, 0.13164, 0],
"48": [0, 0.65556, 0.11156, 0],
"49": [0, 0.65556, 0.11156, 0],
"50": [0, 0.65556, 0.11156, 0],
"51": [0, 0.65556, 0.11156, 0],
"52": [0, 0.65556, 0.11156, 0],
"53": [0, 0.65556, 0.11156, 0],
"54": [0, 0.65556, 0.11156, 0],
"55": [0, 0.65556, 0.11156, 0],
"56": [0, 0.65556, 0.11156, 0],
"57": [0, 0.65556, 0.11156, 0],
"58": [0, 0.44444, 0.02502, 0],
"59": [0.125, 0.44444, 0.02502, 0],
"61": [-0.13, 0.37, 0.05087, 0],
"63": [0, 0.69444, 0.11809, 0],
"64": [0, 0.69444, 0.07555, 0],
"65": [0, 0.69444, 0, 0],
"66": [0, 0.69444, 0.08293, 0],
"67": [0, 0.69444, 0.11983, 0],
"68": [0, 0.69444, 0.07555, 0],
"69": [0, 0.69444, 0.11983, 0],
"70": [0, 0.69444, 0.13372, 0],
"71": [0, 0.69444, 0.11983, 0],
"72": [0, 0.69444, 0.08094, 0],
"73": [0, 0.69444, 0.13372, 0],
"74": [0, 0.69444, 0.08094, 0],
"75": [0, 0.69444, 0.11983, 0],
"76": [0, 0.69444, 0, 0],
"77": [0, 0.69444, 0.08094, 0],
"78": [0, 0.69444, 0.08094, 0],
"79": [0, 0.69444, 0.07555, 0],
"80": [0, 0.69444, 0.08293, 0],
"81": [0.125, 0.69444, 0.07555, 0],
"82": [0, 0.69444, 0.08293, 0],
"83": [0, 0.69444, 0.09205, 0],
"84": [0, 0.69444, 0.13372, 0],
"85": [0, 0.69444, 0.08094, 0],
"86": [0, 0.69444, 0.1615, 0],
"87": [0, 0.69444, 0.1615, 0],
"88": [0, 0.69444, 0.13372, 0],
"89": [0, 0.69444, 0.17261, 0],
"90": [0, 0.69444, 0.11983, 0],
"91": [0.25, 0.75, 0.15942, 0],
"93": [0.25, 0.75, 0.08719, 0],
"94": [0, 0.69444, 0.0799, 0],
"95": [0.35, 0.09444, 0.08616, 0],
"97": [0, 0.44444, 0.00981, 0],
"98": [0, 0.69444, 0.03057, 0],
"99": [0, 0.44444, 0.08336, 0],
"100": [0, 0.69444, 0.09483, 0],
"101": [0, 0.44444, 0.06778, 0],
"102": [0, 0.69444, 0.21705, 0],
"103": [0.19444, 0.44444, 0.10836, 0],
"104": [0, 0.69444, 0.01778, 0],
"105": [0, 0.67937, 0.09718, 0],
"106": [0.19444, 0.67937, 0.09162, 0],
"107": [0, 0.69444, 0.08336, 0],
"108": [0, 0.69444, 0.09483, 0],
"109": [0, 0.44444, 0.01778, 0],
"110": [0, 0.44444, 0.01778, 0],
"111": [0, 0.44444, 0.06613, 0],
"112": [0.19444, 0.44444, 0.0389, 0],
"113": [0.19444, 0.44444, 0.04169, 0],
"114": [0, 0.44444, 0.10836, 0],
"115": [0, 0.44444, 0.0778, 0],
"116": [0, 0.57143, 0.07225, 0],
"117": [0, 0.44444, 0.04169, 0],
"118": [0, 0.44444, 0.10836, 0],
"119": [0, 0.44444, 0.10836, 0],
"120": [0, 0.44444, 0.09169, 0],
"121": [0.19444, 0.44444, 0.10836, 0],
"122": [0, 0.44444, 0.08752, 0],
"126": [0.35, 0.32659, 0.08826, 0],
"305": [0, 0.44444, 0.04169, 0],
"567": [0.19444, 0.44444, 0.04169, 0],
"768": [0, 0.69444, 0, 0],
"769": [0, 0.69444, 0.09205, 0],
"770": [0, 0.69444, 0.0799, 0],
"771": [0, 0.67659, 0.08826, 0],
"772": [0, 0.60889, 0.08776, 0],
"774": [0, 0.69444, 0.09483, 0],
"775": [0, 0.67937, 0.07774, 0],
"776": [0, 0.67937, 0.06385, 0],
"778": [0, 0.69444, 0, 0],
"779": [0, 0.69444, 0.09205, 0],
"780": [0, 0.63194, 0.08432, 0],
"915": [0, 0.69444, 0.13372, 0],
"916": [0, 0.69444, 0, 0],
"920": [0, 0.69444, 0.07555, 0],
"923": [0, 0.69444, 0, 0],
"926": [0, 0.69444, 0.12816, 0],
"928": [0, 0.69444, 0.08094, 0],
"931": [0, 0.69444, 0.11983, 0],
"933": [0, 0.69444, 0.09031, 0],
"934": [0, 0.69444, 0.04603, 0],
"936": [0, 0.69444, 0.09031, 0],
"937": [0, 0.69444, 0.08293, 0],
"8211": [0, 0.44444, 0.08616, 0],
"8212": [0, 0.44444, 0.08616, 0],
"8216": [0, 0.69444, 0.07816, 0],
"8217": [0, 0.69444, 0.07816, 0],
"8220": [0, 0.69444, 0.14205, 0],
"8221": [0, 0.69444, 0.00316, 0],
},
"SansSerif-Regular": {
"33": [0, 0.69444, 0, 0],
"34": [0, 0.69444, 0, 0],
@@ -1746,13 +1983,9 @@ const fontMetricsData = {
"934": [0, 0.61111, 0, 0],
"936": [0, 0.61111, 0, 0],
"937": [0, 0.61111, 0, 0],
"2018": [0, 0.61111, 0, 0],
"2019": [0, 0.61111, 0, 0],
"8216": [0, 0.61111, 0, 0],
"8217": [0, 0.61111, 0, 0],
"8242": [0, 0.61111, 0, 0],
"9251": [0.11111, 0.21944, 0, 0],
},
};
export default fontMetricsData;

View File

@@ -7,17 +7,28 @@ import * as html from "../buildHTML";
import * as mml from "../buildMathML";
// Non-mathy text, possibly in a font
const textFunctionFonts = {
"\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",
"\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",
const textFontFamilies = {
"\\text": undefined, "\\textrm": "textrm", "\\textsf": "textsf",
"\\texttt": "texttt", "\\textnormal": "textrm",
};
const textFontWeights = {
"\\textbf": "textbf",
};
const textFontShapes = {
"\\textit": "textit",
};
defineFunction({
type: "text",
names: [
// Font families
"\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
"\\textbf", "\\textit",
// Font weights
"\\textbf",
// Font Shapes
"\\textit",
],
props: {
numArgs: 1,
@@ -30,11 +41,20 @@ defineFunction({
return {
type: "text",
body: ordargument(body),
font: textFunctionFonts[context.funcName],
font: context.funcName,
};
},
htmlBuilder(group, options) {
const newOptions = options.withFont(group.value.font);
const font = group.value.font;
// Checks if the argument is a font family or a font style.
let newOptions;
if (textFontFamilies[font]) {
newOptions = options.withFontFamily(textFontFamilies[font]);
} else if (textFontWeights[font]) {
newOptions = options.withFontWeight(textFontWeights[font]);
} else {
newOptions = options.withFontShape(textFontShapes[font]);
}
const inner = html.buildExpression(group.value.body, newOptions, true);
buildCommon.tryCombineChars(inner);
return buildCommon.makeSpan(["mord", "text"],

View File

@@ -56,19 +56,39 @@
.strut {
display: inline-block;
}
.mathrm {
font-style: normal;
// Text font weights
.textbf {
font-weight: bold;
}
// Text font shapes.
.textit {
font-style: italic;
}
// Text font families.
.textrm {
font-family: KaTeX_Main;
}
.textsf {
font-family: KaTeX_SansSerif;
}
.texttt {
font-family: KaTeX_Typewriter;
}
// Math fonts.
.mathit {
font-family: KaTeX_Math;
font-style: italic;
}
.mathrm {
font-style: normal;
}
.mathbf {
font-family: KaTeX_Main;

View File

@@ -1585,7 +1585,7 @@ describe("An HTML font tree-builder", function() {
it("should render \\text{R} with the correct font", function() {
const markup = katex.renderToString("\\text{R}");
expect(markup).toContain("<span class=\"mord mathrm\">R</span>");
expect(markup).toContain("<span class=\"mord\">R</span>");
});
it("should render \\textit{R} with the correct font", function() {
@@ -1600,24 +1600,41 @@ describe("An HTML font tree-builder", function() {
it("should render \\text{R\\textit{S}T} with the correct fonts", function() {
const markup = katex.renderToString("\\text{R\\textit{S}T}");
expect(markup).toContain("<span class=\"mord mathrm\">R</span>");
expect(markup).toContain("<span class=\"mord\">R</span>");
expect(markup).toContain("<span class=\"mord textit\">S</span>");
expect(markup).toContain("<span class=\"mord mathrm\">T</span>");
expect(markup).toContain("<span class=\"mord\">T</span>");
});
it("should render \\textbf{R} with the correct font", function() {
const markup = katex.renderToString("\\textbf{R}");
expect(markup).toContain("<span class=\"mord mathbf\">R</span>");
expect(markup).toContain("<span class=\"mord textbf\">R</span>");
});
it("should render \\textsf{R} with the correct font", function() {
const markup = katex.renderToString("\\textsf{R}");
expect(markup).toContain("<span class=\"mord mathsf\">R</span>");
expect(markup).toContain("<span class=\"mord textsf\">R</span>");
});
it("should render \\textsf{\\textit{R}G\\textbf{B}} with the correct font", function() {
const markup = katex.renderToString("\\textsf{\\textit{R}G\\textbf{B}}");
expect(markup).toContain("<span class=\"mord textsf textit\">R</span>");
expect(markup).toContain("<span class=\"mord textsf\">G</span>");
expect(markup).toContain("<span class=\"mord textsf textbf\">B</span>");
});
it("should render \\textsf{\\textbf{$\\mathrm{A}$}} with the correct font", function() {
const markup = katex.renderToString("\\textsf{\\textbf{$\\mathrm{A}$}}");
expect(markup).toContain("<span class=\"mord mathrm\">A</span>");
});
it("should render \\textsf{\\textbf{$\\mathrm{\\textsf{A}}$}} with the correct font", function() {
const markup = katex.renderToString("\\textsf{\\textbf{$\\mathrm{\\textsf{A}}$}}");
expect(markup).toContain("<span class=\"mord textsf textbf\">A</span>");
});
it("should render \\texttt{R} with the correct font", function() {
const markup = katex.renderToString("\\texttt{R}");
expect(markup).toContain("<span class=\"mord mathtt\">R</span>");
expect(markup).toContain("<span class=\"mord texttt\">R</span>");
});
it("should render a combination of font and color changes", function() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -268,6 +268,13 @@ Symbols1: |
\maltese\degree\pounds\$
\text{\maltese\degree\pounds\textdollar}
Text: \frac{a}{b}\text{c~ {ab} \ e}+fg
TextStacked:
\begin{matrix}
\textsf{abc123 \textbf{abc123} \textit{abc123}}\\
\text{abc123 \textbf{abc123} \textit{abc123}}\\
\textrm{abc123 \textbf{abc123} \textit{abc123}}\\
\textsf{\textrm{\textbf{abc123}} \textbf{abc123} \textit{abc123}}\\
\end{matrix}
TextWithMath: \text{for $a < b$ and $ c < d $}.
Unicode: \begin{matrix}\text{ÀàÇçÉéÏïÖöÛû} \\ \text{БГДЖЗЙЛФЦШЫЮЯ} \\ \text{여보세요} \\ \text{私はバナナです} \end{matrix}
Units: |