diff --git a/src/buildCommon.js b/src/buildCommon.js index 3f53bf91..e0796707 100644 --- a/src/buildCommon.js +++ b/src/buildCommon.js @@ -113,8 +113,13 @@ const mathsym = function( // Have a special case for when the value = \ because the \ is used as a // textord in unsupported command errors but cannot be parsed as a regular // text ordinal and is therefore not present as a symbol in the symbols - // table for text - if (value === "\\" || symbols[mode][value].font === "main") { + // 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") && + lookupSymbol(value, "Main-Bold", mode).metrics) { + return makeSymbol(value, "Main-Bold", mode, options, + classes.concat(["mathbf"])); + } else if (value === "\\" || symbols[mode][value].font === "main") { return makeSymbol(value, "Main-Regular", mode, options, classes); } else { return makeSymbol( @@ -179,6 +184,33 @@ const mathit = function( } }; +/** + * Determines which of the two font names (Main-Bold and Math-BoldItalic) and + * corresponding style tags (mathbf or boldsymbol) to use for font "boldsymbol", + * depending on the symbol. Use this function instead of fontMap for font + * "boldsymbol". + */ +const boldsymbol = function( + value: string, + mode: Mode, + options: Options, + classes: string[], +): {| fontName: string, fontClass: string |} { + if (lookupSymbol(value, "Math-BoldItalic", mode).metrics) { + return { + fontName: "Math-BoldItalic", + fontClass: "boldsymbol", + }; + } else { + // Some glyphs do not exist in Math-BoldItalic so we need to use + // Main-Bold instead. + return { + fontName: "Main-Bold", + fontClass: "mathbf", + }; + } +}; + /** * Makes either a mathord or textord in the correct font and color. */ @@ -195,7 +227,9 @@ const makeOrd = function( const font = options.font; if (font) { let fontLookup; - if (font === "mathit" || utils.contains(mainitLetters, value)) { + if (font === "boldsymbol") { + fontLookup = boldsymbol(value, mode, options, classes); + } else if (font === "mathit" || utils.contains(mainitLetters, value)) { fontLookup = mathit(value, mode, options, classes); } else { fontLookup = fontMap[font]; @@ -590,9 +624,10 @@ const fontMap: {[string]: {| variant: string, fontName: string |}} = { fontName: "Main-Italic", }, - // "mathit" is missing because it requires the use of two fonts: Main-Italic - // and Math-Italic. This is handled by a special case in makeOrd which ends - // up calling mathit. + // "mathit" and "boldsymbol" are missing because they require the use of two + // fonts: Main-Italic and Math-Italic for "mathit", and Math-BoldItalic and + // Main-Bold for "boldsymbol". This is handled by a special case in makeOrd + // which ends up calling mathit and boldsymbol. // families "mathbb": { diff --git a/src/buildMathML.js b/src/buildMathML.js index a71a1433..b14d4183 100644 --- a/src/buildMathML.js +++ b/src/buildMathML.js @@ -39,6 +39,8 @@ const getVariant = function(group, options) { const mode = group.mode; if (font === "mathit") { return "italic"; + } else if (font === "boldsymbol") { + return "bold-italic"; } let value = group.value; @@ -106,10 +108,15 @@ groupTypes.textord = function(group, options) { return node; }; -groupTypes.bin = function(group) { +groupTypes.bin = function(group, options) { const node = new mathMLTree.MathNode( "mo", [makeText(group.value, group.mode)]); + const variant = getVariant(group, options); + if (variant === "bold-italic") { + node.setAttribute("mathvariant", variant); + } + return node; }; diff --git a/src/functions.js b/src/functions.js index 08a3d07e..eaa9e509 100644 --- a/src/functions.js +++ b/src/functions.js @@ -147,6 +147,7 @@ const fontAliases = { "\\Bbb": "\\mathbb", "\\bold": "\\mathbf", "\\frak": "\\mathfrak", + "\\bm": "\\boldsymbol", }; const singleCharIntegrals: {[string]: string} = { @@ -244,14 +245,14 @@ defineFunction([ defineFunction([ // styles - "\\mathrm", "\\mathit", "\\mathbf", + "\\mathrm", "\\mathit", "\\mathbf", "\\boldsymbol", // families "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf", "\\mathtt", // aliases - "\\Bbb", "\\bold", "\\frak", + "\\Bbb", "\\bold", "\\frak", "\\bm", ], { numArgs: 1, greediness: 2, diff --git a/static/katex.less b/static/katex.less index 1c69188f..5e455a40 100644 --- a/static/katex.less +++ b/static/katex.less @@ -75,6 +75,12 @@ font-weight: bold; } + .boldsymbol { + font-family: KaTeX_Math; + font-weight: bold; + font-style: italic; + } + .amsrm { font-family: KaTeX_AMS; } diff --git a/test/__snapshots__/mathml-spec.js.snap b/test/__snapshots__/mathml-spec.js.snap index 723e3642..f45c319f 100644 --- a/test/__snapshots__/mathml-spec.js.snap +++ b/test/__snapshots__/mathml-spec.js.snap @@ -77,6 +77,46 @@ exports[`A MathML builder should make prime operators into nodes 1`] = ` `; +exports[`A MathML builder should render boldsymbol with the correct mathvariants 1`] = ` + + + + + + + A + + + x + + + 2 + + + k + + + ω + + + Ω + + + ı + + + + + + + + + \\boldsymbol{Ax2k\\omega\\Omega\\imath+} + + + + +`; + exports[`A MathML builder should render mathchoice as if there was nothing 1`] = ` diff --git a/test/mathml-spec.js b/test/mathml-spec.js index 7b285058..a931d41f 100644 --- a/test/mathml-spec.js +++ b/test/mathml-spec.js @@ -75,4 +75,9 @@ describe("A MathML builder", function() { expect(getMathML(`x_{y_{\\mathchoice{D}{T}{S}{${cmd}}}}`)) .toMatchSnapshot(); }); + + it("should render boldsymbol with the correct mathvariants", () => { + expect(getMathML(`\\boldsymbol{Ax2k\\omega\\Omega\\imath+}`)) + .toMatchSnapshot(); + }); }); diff --git a/test/screenshotter/images/BoldSymbol-chrome.png b/test/screenshotter/images/BoldSymbol-chrome.png new file mode 100644 index 00000000..f4347660 Binary files /dev/null and b/test/screenshotter/images/BoldSymbol-chrome.png differ diff --git a/test/screenshotter/images/BoldSymbol-firefox.png b/test/screenshotter/images/BoldSymbol-firefox.png new file mode 100644 index 00000000..f97143af Binary files /dev/null and b/test/screenshotter/images/BoldSymbol-firefox.png differ diff --git a/test/screenshotter/ss_data.yaml b/test/screenshotter/ss_data.yaml index af2f050e..52e17b60 100644 --- a/test/screenshotter/ss_data.yaml +++ b/test/screenshotter/ss_data.yaml @@ -57,6 +57,7 @@ BinCancellation: | \end{array} BinomTest: \dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17} BoldSpacing: \mathbf{A}^2+\mathbf{B}_3*\mathscr{C}' +BoldSymbol: \sum_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} \boldsymbol{\omega}+ \int_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} \boldsymbol{\Omega}+\boldsymbol{Ax2k\omega\Omega\imath+} Boxed: \boxed{F=ma} \quad \boxed{ac}\color{magenta}{\boxed{F}}\boxed{F=mg} Cases: | f(a,b)=\begin{cases}