katex 0.10.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/LICENSE +1 -1
  3. package/README.md +6 -6
  4. package/cli.js +0 -0
  5. package/contrib/auto-render/auto-render.js +12 -3
  6. package/contrib/copy-tex/README.md +3 -5
  7. package/contrib/mathtex-script-type/README.md +12 -14
  8. package/contrib/mhchem/README.md +3 -1
  9. package/contrib/render-a11y-string/render-a11y-string.js +712 -0
  10. package/contrib/render-a11y-string/test/render-a11y-string-spec.js +526 -0
  11. package/dist/README.md +6 -6
  12. package/dist/contrib/auto-render.js +14 -3
  13. package/dist/contrib/auto-render.min.js +1 -1
  14. package/dist/contrib/auto-render.mjs +14 -3
  15. package/dist/contrib/mhchem.min.js +1 -1
  16. package/dist/contrib/render-a11y-string.js +870 -0
  17. package/dist/contrib/render-a11y-string.min.js +1 -0
  18. package/dist/contrib/render-a11y-string.mjs +753 -0
  19. package/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  20. package/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  21. package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  22. package/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  23. package/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  24. package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  25. package/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  26. package/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  27. package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  28. package/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  29. package/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  30. package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  31. package/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  32. package/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  33. package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  34. package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  35. package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  36. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  37. package/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  38. package/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  39. package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  40. package/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  41. package/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  42. package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  43. package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  44. package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  45. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  46. package/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  47. package/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  48. package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  49. package/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  50. package/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  51. package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  52. package/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  53. package/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  54. package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  55. package/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  56. package/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  57. package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  58. package/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  59. package/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  60. package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  61. package/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  62. package/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  63. package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  64. package/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  65. package/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  66. package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  67. package/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  68. package/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  69. package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  70. package/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  71. package/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  72. package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  73. package/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  74. package/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  75. package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  76. package/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  77. package/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  78. package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  79. package/dist/katex.css +34 -10
  80. package/dist/katex.js +2906 -2115
  81. package/dist/katex.min.css +1 -1
  82. package/dist/katex.min.js +1 -1
  83. package/dist/katex.mjs +2809 -2020
  84. package/package.json +12 -11
  85. package/src/Lexer.js +1 -0
  86. package/src/MacroExpander.js +39 -10
  87. package/src/Options.js +15 -75
  88. package/src/Parser.js +152 -115
  89. package/src/Settings.js +70 -7
  90. package/src/Token.js +2 -0
  91. package/src/buildCommon.js +24 -90
  92. package/src/buildHTML.js +31 -31
  93. package/src/buildMathML.js +52 -9
  94. package/src/buildTree.js +13 -6
  95. package/src/defineFunction.js +7 -22
  96. package/src/delimiter.js +66 -27
  97. package/src/domTree.js +71 -4
  98. package/src/environments/array.js +235 -25
  99. package/src/fontMetrics.js +11 -2
  100. package/src/functions/accent.js +9 -9
  101. package/src/functions/accentunder.js +2 -2
  102. package/src/functions/arrow.js +15 -5
  103. package/src/functions/color.js +9 -38
  104. package/src/functions/def.js +184 -0
  105. package/src/functions/delimsizing.js +32 -8
  106. package/src/functions/enclose.js +33 -6
  107. package/src/functions/font.js +4 -1
  108. package/src/functions/genfrac.js +39 -27
  109. package/src/functions/horizBrace.js +6 -7
  110. package/src/functions/href.js +16 -0
  111. package/src/functions/html.js +102 -0
  112. package/src/functions/includegraphics.js +153 -0
  113. package/src/functions/lap.js +4 -7
  114. package/src/functions/math.js +1 -5
  115. package/src/functions/mclass.js +41 -2
  116. package/src/functions/op.js +27 -111
  117. package/src/functions/operatorname.js +136 -92
  118. package/src/functions/ordgroup.js +1 -1
  119. package/src/functions/overline.js +3 -2
  120. package/src/functions/phantom.js +5 -2
  121. package/src/functions/raisebox.js +4 -16
  122. package/src/functions/rule.js +20 -9
  123. package/src/functions/styling.js +0 -9
  124. package/src/functions/supsub.js +27 -7
  125. package/src/functions/symbolsOp.js +4 -0
  126. package/src/functions/tag.js +20 -4
  127. package/src/functions/text.js +4 -3
  128. package/src/functions/underline.js +3 -2
  129. package/src/functions/utils/assembleSupSub.js +110 -0
  130. package/src/functions.js +3 -0
  131. package/src/katex.less +45 -9
  132. package/src/macros.js +259 -98
  133. package/src/mathMLTree.js +6 -4
  134. package/src/parseNode.js +37 -57
  135. package/src/stretchy.js +3 -1
  136. package/src/svgGeometry.js +136 -44
  137. package/src/symbols.js +52 -69
  138. package/src/tree.js +2 -2
  139. package/src/types.js +2 -1
  140. package/src/unicodeAccents.js +3 -1
  141. package/src/unicodeSymbols.js +30 -321
  142. package/src/utils.js +10 -0
  143. package/src/wide-character.js +2 -2
  144. package/src/unicodeMake.js +0 -70
@@ -3,115 +3,159 @@ import defineFunction, {ordargument} from "../defineFunction";
3
3
  import buildCommon from "../buildCommon";
4
4
  import mathMLTree from "../mathMLTree";
5
5
  import {SymbolNode} from "../domTree";
6
+ import {assembleSupSub} from "./utils/assembleSupSub";
7
+ import {assertNodeType} from "../parseNode";
6
8
 
7
9
  import * as html from "../buildHTML";
8
10
  import * as mml from "../buildMathML";
9
11
 
10
- // \operatorname
11
- // amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
12
- defineFunction({
13
- type: "operatorname",
14
- names: ["\\operatorname"],
15
- props: {
16
- numArgs: 1,
17
- },
18
- handler: ({parser}, args) => {
19
- const body = args[0];
20
- return {
21
- type: "operatorname",
22
- mode: parser.mode,
23
- body: ordargument(body),
24
- };
25
- },
12
+ import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
13
+ import type {ParseNode} from "../parseNode";
26
14
 
27
- htmlBuilder: (group, options) => {
28
- if (group.body.length > 0) {
29
- const body = group.body.map(child => {
30
- // $FlowFixMe: Check if the node has a string `text` property.
31
- const childText = child.text;
32
- if (typeof childText === "string") {
33
- return {
34
- type: "textord",
35
- mode: child.mode,
36
- text: childText,
37
- };
38
- } else {
39
- return child;
40
- }
41
- });
42
-
43
- // Consolidate function names into symbol characters.
44
- const expression = html.buildExpression(
45
- body, options.withFont("mathrm"), true);
46
-
47
- for (let i = 0; i < expression.length; i++) {
48
- const child = expression[i];
49
- if (child instanceof SymbolNode) {
50
- // Per amsopn package,
51
- // change minus to hyphen and \ast to asterisk
52
- child.text = child.text.replace(/\u2212/, "-")
53
- .replace(/\u2217/, "*");
54
- }
15
+ // NOTE: Unlike most `htmlBuilder`s, this one handles not only
16
+ // "operatorname", but also "supsub" since \operatorname* can
17
+ // affect super/subscripting.
18
+ export const htmlBuilder: HtmlBuilderSupSub<"operatorname"> = (grp, options) => {
19
+ // Operators are handled in the TeXbook pg. 443-444, rule 13(a).
20
+ let supGroup;
21
+ let subGroup;
22
+ let hasLimits = false;
23
+ let group: ParseNode<"operatorname">;
24
+ if (grp.type === "supsub") {
25
+ // If we have limits, supsub will pass us its group to handle. Pull
26
+ // out the superscript and subscript and set the group to the op in
27
+ // its base.
28
+ supGroup = grp.sup;
29
+ subGroup = grp.sub;
30
+ group = assertNodeType(grp.base, "operatorname");
31
+ hasLimits = true;
32
+ } else {
33
+ group = assertNodeType(grp, "operatorname");
34
+ }
35
+
36
+ let base;
37
+ if (group.body.length > 0) {
38
+ const body = group.body.map(child => {
39
+ // $FlowFixMe: Check if the node has a string `text` property.
40
+ const childText = child.text;
41
+ if (typeof childText === "string") {
42
+ return {
43
+ type: "textord",
44
+ mode: child.mode,
45
+ text: childText,
46
+ };
47
+ } else {
48
+ return child;
55
49
  }
56
- return buildCommon.makeSpan(["mop"], expression, options);
57
- } else {
58
- return buildCommon.makeSpan(["mop"], [], options);
59
- }
60
- },
50
+ });
61
51
 
62
- mathmlBuilder: (group, options) => {
63
- // The steps taken here are similar to the html version.
64
- let expression = mml.buildExpression(
65
- group.body, options.withFont("mathrm"));
52
+ // Consolidate function names into symbol characters.
53
+ const expression = html.buildExpression(
54
+ body, options.withFont("mathrm"), true);
66
55
 
67
- // Is expression a string or has it something like a fraction?
68
- let isAllString = true; // default
69
56
  for (let i = 0; i < expression.length; i++) {
70
- const node = expression[i];
71
- if (node instanceof mathMLTree.SpaceNode) {
72
- // Do nothing
73
- } else if (node instanceof mathMLTree.MathNode) {
74
- switch (node.type) {
75
- case "mi":
76
- case "mn":
77
- case "ms":
78
- case "mspace":
79
- case "mtext":
80
- break; // Do nothing yet.
81
- case "mo": {
82
- const child = node.children[0];
83
- if (node.children.length === 1 &&
84
- child instanceof mathMLTree.TextNode) {
85
- child.text =
86
- child.text.replace(/\u2212/, "-")
87
- .replace(/\u2217/, "*");
88
- } else {
89
- isAllString = false;
90
- }
91
- break;
92
- }
93
- default:
57
+ const child = expression[i];
58
+ if (child instanceof SymbolNode) {
59
+ // Per amsopn package,
60
+ // change minus to hyphen and \ast to asterisk
61
+ child.text = child.text.replace(/\u2212/, "-")
62
+ .replace(/\u2217/, "*");
63
+ }
64
+ }
65
+ base = buildCommon.makeSpan(["mop"], expression, options);
66
+ } else {
67
+ base = buildCommon.makeSpan(["mop"], [], options);
68
+ }
69
+
70
+ if (hasLimits) {
71
+ return assembleSupSub(base, supGroup, subGroup, options,
72
+ options.style, 0, 0);
73
+
74
+ } else {
75
+ return base;
76
+ }
77
+ };
78
+
79
+ const mathmlBuilder: MathMLBuilder<"operatorname"> = (group, options) => {
80
+ // The steps taken here are similar to the html version.
81
+ let expression = mml.buildExpression(
82
+ group.body, options.withFont("mathrm"));
83
+
84
+ // Is expression a string or has it something like a fraction?
85
+ let isAllString = true; // default
86
+ for (let i = 0; i < expression.length; i++) {
87
+ const node = expression[i];
88
+ if (node instanceof mathMLTree.SpaceNode) {
89
+ // Do nothing
90
+ } else if (node instanceof mathMLTree.MathNode) {
91
+ switch (node.type) {
92
+ case "mi":
93
+ case "mn":
94
+ case "ms":
95
+ case "mspace":
96
+ case "mtext":
97
+ break; // Do nothing yet.
98
+ case "mo": {
99
+ const child = node.children[0];
100
+ if (node.children.length === 1 &&
101
+ child instanceof mathMLTree.TextNode) {
102
+ child.text =
103
+ child.text.replace(/\u2212/, "-")
104
+ .replace(/\u2217/, "*");
105
+ } else {
94
106
  isAllString = false;
107
+ }
108
+ break;
95
109
  }
96
- } else {
97
- isAllString = false;
110
+ default:
111
+ isAllString = false;
98
112
  }
113
+ } else {
114
+ isAllString = false;
99
115
  }
116
+ }
100
117
 
101
- if (isAllString) {
102
- // Write a single TextNode instead of multiple nested tags.
103
- const word = expression.map(node => node.toText()).join("");
104
- expression = [new mathMLTree.TextNode(word)];
105
- }
118
+ if (isAllString) {
119
+ // Write a single TextNode instead of multiple nested tags.
120
+ const word = expression.map(node => node.toText()).join("");
121
+ expression = [new mathMLTree.TextNode(word)];
122
+ }
106
123
 
107
- const identifier = new mathMLTree.MathNode("mi", expression);
108
- identifier.setAttribute("mathvariant", "normal");
124
+ const identifier = new mathMLTree.MathNode("mi", expression);
125
+ identifier.setAttribute("mathvariant", "normal");
109
126
 
110
- // \u2061 is the same as &ApplyFunction;
111
- // ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp
112
- const operator = new mathMLTree.MathNode("mo",
113
- [mml.makeText("\u2061", "text")]);
127
+ // \u2061 is the same as &ApplyFunction;
128
+ // ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp
129
+ const operator = new mathMLTree.MathNode("mo",
130
+ [mml.makeText("\u2061", "text")]);
114
131
 
132
+ if (group.parentIsSupSub) {
133
+ return new mathMLTree.MathNode("mo", [identifier, operator]);
134
+ } else {
115
135
  return mathMLTree.newDocumentFragment([identifier, operator]);
136
+ }
137
+ };
138
+
139
+ // \operatorname
140
+ // amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
141
+ defineFunction({
142
+ type: "operatorname",
143
+ names: ["\\operatorname", "\\operatorname*"],
144
+ props: {
145
+ numArgs: 1,
116
146
  },
147
+ handler: ({parser, funcName}, args) => {
148
+ const body = args[0];
149
+ return {
150
+ type: "operatorname",
151
+ mode: parser.mode,
152
+ body: ordargument(body),
153
+ alwaysHandleSupSub: (funcName === "\\operatorname*"),
154
+ limits: false,
155
+ parentIsSupSub: false,
156
+ };
157
+ },
158
+ htmlBuilder,
159
+ mathmlBuilder,
117
160
  });
161
+
@@ -16,7 +16,7 @@ defineFunctionBuilders({
16
16
  ["mord"], html.buildExpression(group.body, options, true), options);
17
17
  },
18
18
  mathmlBuilder(group, options) {
19
- return mml.buildExpressionRow(group.body, options);
19
+ return mml.buildExpressionRow(group.body, options, true);
20
20
  },
21
21
  });
22
22
 
@@ -31,13 +31,14 @@ defineFunction({
31
31
  const line = buildCommon.makeLineSpan("overline-line", options);
32
32
 
33
33
  // Generate the vlist, with the appropriate kerns
34
+ const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
34
35
  const vlist = buildCommon.makeVList({
35
36
  positionType: "firstBaseline",
36
37
  children: [
37
38
  {type: "elem", elem: innerGroup},
38
- {type: "kern", size: 3 * line.height},
39
+ {type: "kern", size: 3 * defaultRuleThickness},
39
40
  {type: "elem", elem: line},
40
- {type: "kern", size: line.height},
41
+ {type: "kern", size: defaultRuleThickness},
41
42
  ],
42
43
  }, options);
43
44
 
@@ -76,8 +76,10 @@ defineFunction({
76
76
  },
77
77
  mathmlBuilder: (group, options) => {
78
78
  const inner = mml.buildExpression(ordargument(group.body), options);
79
- const node = new mathMLTree.MathNode("mphantom", inner);
79
+ const phantom = new mathMLTree.MathNode("mphantom", inner);
80
+ const node = new mathMLTree.MathNode("mpadded", [phantom]);
80
81
  node.setAttribute("height", "0px");
82
+ node.setAttribute("depth", "0px");
81
83
  return node;
82
84
  },
83
85
  });
@@ -107,7 +109,8 @@ defineFunction({
107
109
  },
108
110
  mathmlBuilder: (group, options) => {
109
111
  const inner = mml.buildExpression(ordargument(group.body), options);
110
- const node = new mathMLTree.MathNode("mphantom", inner);
112
+ const phantom = new mathMLTree.MathNode("mphantom", inner);
113
+ const node = new mathMLTree.MathNode("mpadded", [phantom]);
111
114
  node.setAttribute("width", "0px");
112
115
  return node;
113
116
  },
@@ -1,12 +1,12 @@
1
1
  // @flow
2
- import defineFunction, {ordargument} from "../defineFunction";
2
+ import defineFunction from "../defineFunction";
3
3
  import buildCommon from "../buildCommon";
4
4
  import mathMLTree from "../mathMLTree";
5
5
  import {assertNodeType} from "../parseNode";
6
6
  import {calculateSize} from "../units";
7
7
 
8
+ import * as html from "../buildHTML";
8
9
  import * as mml from "../buildMathML";
9
- import * as sizing from "./sizing";
10
10
 
11
11
  // Box manipulation
12
12
  defineFunction({
@@ -14,7 +14,7 @@ defineFunction({
14
14
  names: ["\\raisebox"],
15
15
  props: {
16
16
  numArgs: 2,
17
- argTypes: ["size", "text"],
17
+ argTypes: ["size", "hbox"],
18
18
  allowedInText: true,
19
19
  },
20
20
  handler({parser}, args) {
@@ -28,19 +28,7 @@ defineFunction({
28
28
  };
29
29
  },
30
30
  htmlBuilder(group, options) {
31
- const text = {
32
- type: "text",
33
- mode: group.mode,
34
- body: ordargument(group.body),
35
- font: "mathrm", // simulate \textrm
36
- };
37
- const sizedText = {
38
- type: "sizing",
39
- mode: group.mode,
40
- body: [text],
41
- size: 6, // simulate \normalsize
42
- };
43
- const body = sizing.htmlBuilder(sizedText, options);
31
+ const body = html.buildGroup(group.body, options);
44
32
  const dy = calculateSize(group.dy, options);
45
33
  return buildCommon.makeVList({
46
34
  positionType: "shift",
@@ -30,13 +30,9 @@ defineFunction({
30
30
  const rule = buildCommon.makeSpan(["mord", "rule"], [], options);
31
31
 
32
32
  // Calculate the shift, width, and height of the rule, and account for units
33
- let shift = 0;
34
- if (group.shift) {
35
- shift = calculateSize(group.shift, options);
36
- }
37
-
38
33
  const width = calculateSize(group.width, options);
39
34
  const height = calculateSize(group.height, options);
35
+ const shift = (group.shift) ? calculateSize(group.shift, options) : 0;
40
36
 
41
37
  // Style the rule to the right size
42
38
  rule.style.borderRightWidth = width + "em";
@@ -55,10 +51,25 @@ defineFunction({
55
51
  return rule;
56
52
  },
57
53
  mathmlBuilder(group, options) {
58
- // TODO(emily): Figure out if there's an actual way to draw black boxes
59
- // in MathML.
60
- const node = new mathMLTree.MathNode("mrow");
54
+ const width = calculateSize(group.width, options);
55
+ const height = calculateSize(group.height, options);
56
+ const shift = (group.shift) ? calculateSize(group.shift, options) : 0;
57
+ const color = options.color && options.getColor() || "black";
58
+
59
+ const rule = new mathMLTree.MathNode("mspace");
60
+ rule.setAttribute("mathbackground", color);
61
+ rule.setAttribute("width", width + "em");
62
+ rule.setAttribute("height", height + "em");
63
+
64
+ const wrapper = new mathMLTree.MathNode("mpadded", [rule]);
65
+ if (shift >= 0) {
66
+ wrapper.setAttribute("height", "+" + shift + "em");
67
+ } else {
68
+ wrapper.setAttribute("height", shift + "em");
69
+ wrapper.setAttribute("depth", "+" + (-shift) + "em");
70
+ }
71
+ wrapper.setAttribute("voffset", shift + "em");
61
72
 
62
- return node;
73
+ return wrapper;
63
74
  },
64
75
  });
@@ -48,15 +48,6 @@ defineFunction({
48
48
  },
49
49
  mathmlBuilder(group, options) {
50
50
  // Figure out what style we're changing to.
51
- // TODO(kevinb): dedupe this with buildHTML.js
52
- // This will be easier of handling of styling nodes is in the same file.
53
- const styleMap = {
54
- "display": Style.DISPLAY,
55
- "text": Style.TEXT,
56
- "script": Style.SCRIPT,
57
- "scriptscript": Style.SCRIPTSCRIPT,
58
- };
59
-
60
51
  const newStyle = styleMap[group.style];
61
52
  const newOptions = options.havingStyle(newStyle);
62
53
 
@@ -5,13 +5,13 @@ import {SymbolNode} from "../domTree";
5
5
  import mathMLTree from "../mathMLTree";
6
6
  import utils from "../utils";
7
7
  import Style from "../Style";
8
- import {checkNodeType} from "../parseNode";
9
8
 
10
9
  import * as html from "../buildHTML";
11
10
  import * as mml from "../buildMathML";
12
11
  import * as accent from "./accent";
13
12
  import * as horizBrace from "./horizBrace";
14
13
  import * as op from "./op";
14
+ import * as operatorname from "./operatorname";
15
15
 
16
16
  import type Options from "../Options";
17
17
  import type {ParseNode} from "../parseNode";
@@ -39,6 +39,10 @@ const htmlBuilderDelegate = function(
39
39
  (options.style.size === Style.DISPLAY.size ||
40
40
  base.alwaysHandleSupSub);
41
41
  return delegate ? op.htmlBuilder : null;
42
+ } else if (base.type === "operatorname") {
43
+ const delegate = base.alwaysHandleSupSub &&
44
+ (options.style.size === Style.DISPLAY.size || base.limits);
45
+ return delegate ? operatorname.htmlBuilder : null;
42
46
  } else if (base.type === "accent") {
43
47
  return utils.isCharacterBox(base.base) ? accent.htmlBuilder : null;
44
48
  } else if (base.type === "horizBrace") {
@@ -192,15 +196,19 @@ defineFunctionBuilders({
192
196
  let isOver;
193
197
  let isSup;
194
198
 
195
- const horizBrace = checkNodeType(group.base, "horizBrace");
196
- if (horizBrace) {
199
+ if (group.base && group.base.type === "horizBrace") {
197
200
  isSup = !!group.sup;
198
- if (isSup === horizBrace.isOver) {
201
+ if (isSup === group.base.isOver) {
199
202
  isBrace = true;
200
- isOver = horizBrace.isOver;
203
+ isOver = group.base.isOver;
201
204
  }
202
205
  }
203
206
 
207
+ if (group.base &&
208
+ (group.base.type === "op" || group.base.type === "operatorname")) {
209
+ group.base.parentIsSupSub = true;
210
+ }
211
+
204
212
  const children = [mml.buildGroup(group.base, options)];
205
213
 
206
214
  if (group.sub) {
@@ -217,7 +225,11 @@ defineFunctionBuilders({
217
225
  } else if (!group.sub) {
218
226
  const base = group.base;
219
227
  if (base && base.type === "op" && base.limits &&
220
- options.style === Style.DISPLAY) {
228
+ (options.style === Style.DISPLAY || base.alwaysHandleSupSub)) {
229
+ nodeType = "mover";
230
+ } else if (base && base.type === "operatorname" &&
231
+ base.alwaysHandleSupSub &&
232
+ (base.limits || options.style === Style.DISPLAY)) {
221
233
  nodeType = "mover";
222
234
  } else {
223
235
  nodeType = "msup";
@@ -225,7 +237,11 @@ defineFunctionBuilders({
225
237
  } else if (!group.sup) {
226
238
  const base = group.base;
227
239
  if (base && base.type === "op" && base.limits &&
228
- options.style === Style.DISPLAY) {
240
+ (options.style === Style.DISPLAY || base.alwaysHandleSupSub)) {
241
+ nodeType = "munder";
242
+ } else if (base && base.type === "operatorname" &&
243
+ base.alwaysHandleSupSub &&
244
+ (base.limits || options.style === Style.DISPLAY)) {
229
245
  nodeType = "munder";
230
246
  } else {
231
247
  nodeType = "msub";
@@ -235,6 +251,10 @@ defineFunctionBuilders({
235
251
  if (base && base.type === "op" && base.limits &&
236
252
  options.style === Style.DISPLAY) {
237
253
  nodeType = "munderover";
254
+ } else if (base && base.type === "operatorname" &&
255
+ base.alwaysHandleSupSub &&
256
+ (options.style === Style.DISPLAY || base.limits)) {
257
+ nodeType = "munderover";
238
258
  } else {
239
259
  nodeType = "msubsup";
240
260
  }
@@ -23,6 +23,10 @@ defineFunctionBuilders({
23
23
  }
24
24
  } else if (group.family === "punct") {
25
25
  node.setAttribute("separator", "true");
26
+ } else if (group.family === "open" || group.family === "close") {
27
+ // Delims built here should not stretch vertically.
28
+ // See delimsizing.js for stretchy delims.
29
+ node.setAttribute("stretchy", "false");
26
30
  }
27
31
  return node;
28
32
  },
@@ -4,21 +4,37 @@ import mathMLTree from "../mathMLTree";
4
4
 
5
5
  import * as mml from "../buildMathML";
6
6
 
7
+ const pad = () => {
8
+ const padNode = new mathMLTree.MathNode("mtd", []);
9
+ padNode.setAttribute("width", "50%");
10
+ return padNode;
11
+ };
12
+
7
13
  defineFunctionBuilders({
8
14
  type: "tag",
9
15
  mathmlBuilder(group, options) {
10
16
  const table = new mathMLTree.MathNode("mtable", [
11
- new mathMLTree.MathNode("mlabeledtr", [
17
+ new mathMLTree.MathNode("mtr", [
18
+ pad(),
12
19
  new mathMLTree.MathNode("mtd", [
13
- mml.buildExpressionRow(group.tag, options),
20
+ mml.buildExpressionRow(group.body, options),
14
21
  ]),
22
+ pad(),
15
23
  new mathMLTree.MathNode("mtd", [
16
- mml.buildExpressionRow(group.body, options),
24
+ mml.buildExpressionRow(group.tag, options),
17
25
  ]),
18
26
  ]),
19
27
  ]);
20
- table.setAttribute("side", "right");
28
+ table.setAttribute("width", "100%");
21
29
  return table;
30
+
31
+ // TODO: Left-aligned tags.
32
+ // Currently, the group and options passed here do not contain
33
+ // enough info to set tag alignment. `leqno` is in Settings but it is
34
+ // not passed to Options. On the HTML side, leqno is
35
+ // set by a CSS class applied in buildTree.js. That would have worked
36
+ // in MathML if browsers supported <mlabeledtr>. Since they don't, we
37
+ // need to rewrite the way this function is called.
22
38
  },
23
39
  });
24
40
 
@@ -13,10 +13,12 @@ const textFontFamilies = {
13
13
 
14
14
  const textFontWeights = {
15
15
  "\\textbf": "textbf",
16
+ "\\textmd": "textmd",
16
17
  };
17
18
 
18
19
  const textFontShapes = {
19
20
  "\\textit": "textit",
21
+ "\\textup": "textup",
20
22
  };
21
23
 
22
24
  const optionsWithFont = (group, options) => {
@@ -39,16 +41,15 @@ defineFunction({
39
41
  // Font families
40
42
  "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
41
43
  // Font weights
42
- "\\textbf",
44
+ "\\textbf", "\\textmd",
43
45
  // Font Shapes
44
- "\\textit",
46
+ "\\textit", "\\textup",
45
47
  ],
46
48
  props: {
47
49
  numArgs: 1,
48
50
  argTypes: ["text"],
49
51
  greediness: 2,
50
52
  allowedInText: true,
51
- consumeMode: "text",
52
53
  },
53
54
  handler({parser, funcName}, args) {
54
55
  const body = args[0];
@@ -29,13 +29,14 @@ defineFunction({
29
29
  const line = buildCommon.makeLineSpan("underline-line", options);
30
30
 
31
31
  // Generate the vlist, with the appropriate kerns
32
+ const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
32
33
  const vlist = buildCommon.makeVList({
33
34
  positionType: "top",
34
35
  positionData: innerGroup.height,
35
36
  children: [
36
- {type: "kern", size: line.height},
37
+ {type: "kern", size: defaultRuleThickness},
37
38
  {type: "elem", elem: line},
38
- {type: "kern", size: 3 * line.height},
39
+ {type: "kern", size: 3 * defaultRuleThickness},
39
40
  {type: "elem", elem: innerGroup},
40
41
  ],
41
42
  }, options);