\kern fixes, \hskip support, \TeX, \LaTeX, \KaTeX (#974)

* Refactor \kern, proper \mkern support, add \hskip

* Move \kern, \mkern into functions directory
* Add \hskip, \mskip support (but without supporting plus/minus)
* Properly separate \kern, \hskip from \mkern, \mskip.
  (The former work in both modes, and don't support mu units.
  The latter work only in math mode and only support mu units.)

* Render \kern etc. using MathML <mspace>

* Implement \TeX macro

* Implement \LaTeX

* New KaTeX logo \katex

* Rename hskip.js -> kern.js

* Tweak katex \kern to 0.16em

* \katex kern -.17em

* Compute A raise height in \LaTeX and \katex

* Switch mu unit errors to warnings

* LaTeX screenshot test

* Replace \KaTeX with macro definition

* Update screenshots with \KaTeX in them

* Fix font selection for \*TeX macros
This commit is contained in:
Erik Demaine
2017-11-27 14:40:38 -05:00
committed by Kevin Barabash
parent f6a377b91c
commit 7036eb85cd
32 changed files with 108 additions and 93 deletions

View File

@@ -735,18 +735,6 @@ groupTypes.rule = function(group, options) {
return rule;
};
groupTypes.kern = function(group, options) {
// Make an empty span for the rule
const rule = makeSpan(["mord", "rule"], [], options);
if (group.value.dimension) {
const dimension = calculateSize(group.value.dimension, options);
rule.style.marginLeft = dimension + "em";
}
return rule;
};
groupTypes.accent = function(group, options) {
// Accents are handled in the TeXbook pg. 443, rule 12.
let base = group.value.base;

View File

@@ -468,13 +468,6 @@ groupTypes.rule = function(group) {
return node;
};
groupTypes.kern = function(group) {
// TODO(kevin): Figure out if there's a way to add space in MathML
const node = new mathMLTree.MathNode("mrow");
return node;
};
groupTypes.mclass = function(group, options) {
const inner = buildExpression(group.value.value, options);
return new mathMLTree.MathNode("mstyle", inner);

View File

@@ -163,19 +163,7 @@ defineFunction(["\\rule"], {
};
});
// TODO: In TeX, \mkern only accepts mu-units, and \kern does not accept
// mu-units. In current KaTeX we relax this; both commands accept any unit.
defineFunction(["\\kern", "\\mkern"], {
numArgs: 1,
argTypes: ["size"],
}, function(context, args) {
return {
type: "kern",
dimension: args[0].value,
};
});
import "./functions/katex";
import "./functions/kern";
import "./functions/phantom";

View File

@@ -1,51 +0,0 @@
// @flow
// A KaTeX logo
import defineFunction from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
defineFunction({
type: "katex",
names: ["\\KaTeX"],
props: {
numArgs: 0,
allowedInText: true,
},
handler: (context, args) => {
return {
type: "katex",
};
},
htmlBuilder: (group, options) => {
// The KaTeX logo. The offsets for the K and a were chosen to look
// good, but the offsets for the T, E, and X were taken from the
// definition of \TeX in TeX (see TeXbook pg. 356)
const k = buildCommon.makeSpan(
["k"], [buildCommon.mathsym("K", group.mode)], options);
const a = buildCommon.makeSpan(
["a"], [buildCommon.mathsym("A", group.mode)], options);
a.height = (a.height + 0.2) * 0.75;
a.depth = (a.height - 0.2) * 0.75;
const t = buildCommon.makeSpan(
["t"], [buildCommon.mathsym("T", group.mode)], options);
const e = buildCommon.makeSpan(
["e"], [buildCommon.mathsym("E", group.mode)], options);
e.height = (e.height - 0.2155);
e.depth = (e.depth + 0.2155);
const x = buildCommon.makeSpan(
["x"], [buildCommon.mathsym("X", group.mode)], options);
return buildCommon.makeSpan(
["mord", "katex-logo"], [k, a, t, e, x], options);
},
mathmlBuilder: (group, options) => {
const node = new mathMLTree.MathNode(
"mtext", [new mathMLTree.TextNode("KaTeX")]);
return node;
},
});

66
src/functions/kern.js Normal file
View File

@@ -0,0 +1,66 @@
//@flow
/* eslint no-console:0 */
// Horizontal spacing commands
import defineFunction from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import { calculateSize } from "../units";
import ParseError from "../ParseError";
// TODO: \hskip and \mskip should support plus and minus in lengths
defineFunction({
type: "kern",
names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"],
props: {
numArgs: 1,
argTypes: ["size"],
allowedInText: true,
},
handler: (context, args) => {
const mathFunction = (context.funcName[1] === 'm'); // \mkern, \mskip
const muUnit = (args[0].value.unit === 'mu');
if (mathFunction) {
if (!muUnit) {
typeof console !== "undefined" && console.warn(
`In LaTeX, ${context.funcName} supports only mu units, ` +
`not ${args[0].value.unit} units`);
}
if (context.parser.mode !== "math") {
throw new ParseError(
`Can't use function '${context.funcName}' in text mode`);
}
} else { // !mathFunction
if (muUnit) {
typeof console !== "undefined" && console.warn(
`In LaTeX, ${context.funcName} does not support mu units`);
}
}
return {
type: "kern",
dimension: args[0].value,
};
},
htmlBuilder: (group, options) => {
// Make an empty span for the rule
const rule = buildCommon.makeSpan(["mord", "rule"], [], options);
if (group.value.dimension) {
const dimension = calculateSize(group.value.dimension, options);
rule.style.marginLeft = dimension + "em";
}
return rule;
},
mathmlBuilder: (group, options) => {
const node = new mathMLTree.MathNode("mspace");
if (group.value.dimension) {
const dimension = calculateSize(group.value.dimension, options);
node.setAttribute("width", dimension + "em");
}
return node;
},
});

View File

@@ -4,6 +4,7 @@
* This can be used to define some commands in terms of others.
*/
import fontMetricsData from "./fontMetricsData";
import symbols from "./symbols";
import utils from "./utils";
import {Token} from "./Token";
@@ -85,10 +86,6 @@ defineMacro("\u211A", "\\mathbb{Q}");
defineMacro("\u211D", "\\mathbb{R}");
defineMacro("\u2124", "\\mathbb{Z}");
// We don't distinguish between math and nonmath kerns.
// (In TeX, the mu unit works only with \mkern.)
defineMacro("\\mkern", "\\kern");
// \llap and \rlap render their contents in text mode
defineMacro("\\llap", "\\mathllap{\\textrm{#1}}");
defineMacro("\\rlap", "\\mathrlap{\\textrm{#1}}");
@@ -270,6 +267,37 @@ defineMacro("\\thickspace", "\\;"); // \let\thickspace\;
//////////////////////////////////////////////////////////////////////
// LaTeX source2e
// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
// TODO: Doesn't normally work in math mode because \@ fails. KaTeX doesn't
// support \@ yet, so that's omitted, and we add \text so that the result
// doesn't look funny in math mode.
defineMacro("\\TeX", "\\textrm{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}");
// \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
// {\sbox\z@ T%
// \vbox to\ht\z@{\hbox{\check@mathfonts
// \fontsize\sf@size\z@
// \math@fontsfalse\selectfont
// A}%
// \vss}%
// }%
// \kern-.15em%
// \TeX}
// This code aligns the top of the A with the T (from the perspective of TeX's
// boxes, though visually the A appears to extend above slightly).
// We compute the corresponding \raisebox when A is rendered at \scriptsize,
// which is size3, which has a scale factor of 0.7 (see Options.js).
const latexRaiseA = fontMetricsData['Main-Regular']["T".charCodeAt(0)][1] -
0.7 * fontMetricsData['Main-Regular']["A".charCodeAt(0)][1] + "em";
defineMacro("\\LaTeX",
`\\textrm{L\\kern-.36em\\raisebox{${latexRaiseA}}{\\scriptsize A}` +
"\\kern-.15em\\TeX}");
// New KaTeX logo based on tweaking LaTeX logo
defineMacro("\\KaTeX",
`\\textrm{K\\kern-.17em\\raisebox{${latexRaiseA}}{\\scriptsize A}` +
"\\kern-.15em\\TeX}");
// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
// \def\@hspace#1{\hskip #1\relax}
// KaTeX doesn't do line breaks, so \hspace and \hspace* are the same as \kern