|
|
// @flow
|
|
|
|
|
|
/**
|
|
|
* This file provides support for Unicode range U+1D400 to U+1D7FF,
|
|
|
* Mathematical Alphanumeric Symbols.
|
|
|
*
|
|
|
* Function wideCharacterFont takes a wide character as input and returns
|
|
|
* the font information necessary to render it properly.
|
|
|
*/
|
|
|
|
|
|
import type {Mode} from "./types";
|
|
|
import ParseError from "./ParseError";
|
|
|
|
|
|
/**
|
|
|
* Data below is from https://www.unicode.org/charts/PDF/U1D400.pdf
|
|
|
* That document sorts characters into groups by font type, say bold or italic.
|
|
|
*
|
|
|
* In the arrays below, each subarray consists three elements:
|
|
|
* * The CSS class of that group when in math mode.
|
|
|
* * The CSS class of that group when in text mode.
|
|
|
* * The font name, so that KaTeX can get font metrics.
|
|
|
*/
|
|
|
|
|
|
const wideLatinLetterData: Array<[string, string, string]> = [
|
|
|
["mathbf", "textbf", "Main-Bold"], // A-Z bold upright
|
|
|
["mathbf", "textbf", "Main-Bold"], // a-z bold upright
|
|
|
|
|
|
["mathnormal", "textit", "Math-Italic"], // A-Z italic
|
|
|
["mathnormal", "textit", "Math-Italic"], // a-z italic
|
|
|
|
|
|
["boldsymbol", "boldsymbol", "Main-BoldItalic"], // A-Z bold italic
|
|
|
["boldsymbol", "boldsymbol", "Main-BoldItalic"], // a-z bold italic
|
|
|
|
|
|
// Map fancy A-Z letters to script, not calligraphic.
|
|
|
// This aligns with unicode-math and math fonts (except Cambria Math).
|
|
|
["mathscr", "textscr", "Script-Regular"], // A-Z script
|
|
|
["", "", ""], // a-z script. No font
|
|
|
|
|
|
["", "", ""], // A-Z bold script. No font
|
|
|
["", "", ""], // a-z bold script. No font
|
|
|
|
|
|
["mathfrak", "textfrak", "Fraktur-Regular"], // A-Z Fraktur
|
|
|
["mathfrak", "textfrak", "Fraktur-Regular"], // a-z Fraktur
|
|
|
|
|
|
["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck
|
|
|
["mathbb", "textbb", "AMS-Regular"], // k double-struck
|
|
|
|
|
|
["", "", ""], // A-Z bold Fraktur No font metrics
|
|
|
["", "", ""], // a-z bold Fraktur. No font.
|
|
|
|
|
|
["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif
|
|
|
["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif
|
|
|
|
|
|
["mathboldsf", "textboldsf", "SansSerif-Bold"], // A-Z bold sans-serif
|
|
|
["mathboldsf", "textboldsf", "SansSerif-Bold"], // a-z bold sans-serif
|
|
|
|
|
|
["mathitsf", "textitsf", "SansSerif-Italic"], // A-Z italic sans-serif
|
|
|
["mathitsf", "textitsf", "SansSerif-Italic"], // a-z italic sans-serif
|
|
|
|
|
|
["", "", ""], // A-Z bold italic sans. No font
|
|
|
["", "", ""], // a-z bold italic sans. No font
|
|
|
|
|
|
["mathtt", "texttt", "Typewriter-Regular"], // A-Z monospace
|
|
|
["mathtt", "texttt", "Typewriter-Regular"], // a-z monospace
|
|
|
];
|
|
|
|
|
|
const wideNumeralData: Array<[string, string, string]> = [
|
|
|
["mathbf", "textbf", "Main-Bold"], // 0-9 bold
|
|
|
["", "", ""], // 0-9 double-struck. No KaTeX font.
|
|
|
["mathsf", "textsf", "SansSerif-Regular"], // 0-9 sans-serif
|
|
|
["mathboldsf", "textboldsf", "SansSerif-Bold"], // 0-9 bold sans-serif
|
|
|
["mathtt", "texttt", "Typewriter-Regular"], // 0-9 monospace
|
|
|
];
|
|
|
|
|
|
export const wideCharacterFont = function(
|
|
|
wideChar: string,
|
|
|
mode: Mode,
|
|
|
): [string, string] {
|
|
|
|
|
|
// IE doesn't support codePointAt(). So work with the surrogate pair.
|
|
|
const H = wideChar.charCodeAt(0); // high surrogate
|
|
|
const L = wideChar.charCodeAt(1); // low surrogate
|
|
|
const codePoint = ((H - 0xD800) * 0x400) + (L - 0xDC00) + 0x10000;
|
|
|
|
|
|
const j = mode === "math" ? 0 : 1; // column index for CSS class.
|
|
|
|
|
|
if (0x1D400 <= codePoint && codePoint < 0x1D6A4) {
|
|
|
// wideLatinLetterData contains exactly 26 chars on each row.
|
|
|
// So we can calculate the relevant row. No traverse necessary.
|
|
|
const i = Math.floor((codePoint - 0x1D400) / 26);
|
|
|
return [wideLatinLetterData[i][2], wideLatinLetterData[i][j]];
|
|
|
|
|
|
} else if (0x1D7CE <= codePoint && codePoint <= 0x1D7FF) {
|
|
|
// Numerals, ten per row.
|
|
|
const i = Math.floor((codePoint - 0x1D7CE) / 10);
|
|
|
return [wideNumeralData[i][2], wideNumeralData[i][j]];
|
|
|
|
|
|
} else if (codePoint === 0x1D6A5 || codePoint === 0x1D6A6) {
|
|
|
// dotless i or j
|
|
|
return [wideLatinLetterData[0][2], wideLatinLetterData[0][j]];
|
|
|
|
|
|
} else if (0x1D6A6 < codePoint && codePoint < 0x1D7CE) {
|
|
|
// Greek letters. Not supported, yet.
|
|
|
return ["", ""];
|
|
|
|
|
|
} else {
|
|
|
// We don't support any wide characters outside 1D400–1D7FF.
|
|
|
throw new ParseError("Unsupported character: " + wideChar);
|
|
|
}
|
|
|
};
|