katex 0.12.0 → 0.13.3

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 (167) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +1 -1
  3. package/README.md +8 -7
  4. package/contrib/auto-render/auto-render.js +12 -19
  5. package/contrib/auto-render/index.html +9 -3
  6. package/contrib/auto-render/splitAtDelimiters.js +44 -61
  7. package/contrib/auto-render/test/auto-render-spec.js +88 -52
  8. package/contrib/copy-tex/README.md +5 -9
  9. package/contrib/copy-tex/copy-tex.css +0 -3
  10. package/contrib/mathtex-script-type/README.md +5 -5
  11. package/contrib/mhchem/README.md +4 -2
  12. package/contrib/render-a11y-string/render-a11y-string.js +31 -2
  13. package/contrib/render-a11y-string/test/render-a11y-string-spec.js +23 -0
  14. package/dist/README.md +8 -7
  15. package/dist/contrib/auto-render.js +148 -171
  16. package/dist/contrib/auto-render.min.js +1 -1
  17. package/dist/contrib/auto-render.mjs +91 -95
  18. package/dist/contrib/copy-tex.css +3 -3
  19. package/dist/contrib/copy-tex.js +11 -108
  20. package/dist/contrib/copy-tex.min.css +1 -1
  21. package/dist/contrib/copy-tex.min.js +1 -1
  22. package/dist/contrib/copy-tex.mjs +21 -20
  23. package/dist/contrib/mathtex-script-type.js +66 -91
  24. package/dist/contrib/mathtex-script-type.min.js +1 -1
  25. package/dist/contrib/mathtex-script-type.mjs +3 -3
  26. package/dist/contrib/mhchem.js +70 -95
  27. package/dist/contrib/mhchem.min.js +1 -1
  28. package/dist/contrib/mhchem.mjs +2 -2
  29. package/dist/contrib/render-a11y-string.js +97 -92
  30. package/dist/contrib/render-a11y-string.min.js +1 -1
  31. package/dist/contrib/render-a11y-string.mjs +86 -45
  32. package/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  33. package/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  34. package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  35. package/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  36. package/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  37. package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  38. package/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  39. package/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  40. package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  41. package/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  42. package/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  43. package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  44. package/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  45. package/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  46. package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  47. package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  48. package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  49. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  50. package/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  51. package/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  52. package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  53. package/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  54. package/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  55. package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  56. package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  57. package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  58. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  59. package/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  60. package/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  61. package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  62. package/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  63. package/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  64. package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  65. package/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  66. package/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  67. package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  68. package/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  69. package/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  70. package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  71. package/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  72. package/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  73. package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  74. package/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  75. package/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  76. package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  77. package/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  78. package/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  79. package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  80. package/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  81. package/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  82. package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  83. package/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  84. package/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  85. package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  86. package/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  87. package/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  88. package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  89. package/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  90. package/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  91. package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  92. package/dist/katex.css +66 -10
  93. package/dist/katex.js +2714 -1950
  94. package/dist/katex.min.css +1 -1
  95. package/dist/katex.min.js +1 -1
  96. package/dist/katex.mjs +3162 -2372
  97. package/katex.js +4 -3
  98. package/package.json +69 -59
  99. package/src/Lexer.js +4 -2
  100. package/src/MacroExpander.js +117 -37
  101. package/src/Options.js +2 -2
  102. package/src/ParseError.js +1 -1
  103. package/src/Parser.js +100 -159
  104. package/src/Settings.js +2 -2
  105. package/src/Style.js +4 -4
  106. package/src/Token.js +1 -1
  107. package/src/buildCommon.js +12 -5
  108. package/src/buildHTML.js +11 -0
  109. package/src/buildMathML.js +6 -0
  110. package/src/defineEnvironment.js +0 -3
  111. package/src/defineFunction.js +15 -22
  112. package/src/delimiter.js +61 -57
  113. package/src/domTree.js +1 -1
  114. package/src/environments/array.js +223 -35
  115. package/src/environments/cd.js +312 -0
  116. package/src/fontMetrics.js +1 -1
  117. package/src/fontMetricsData.js +2076 -0
  118. package/src/fonts/.gitignore +9 -0
  119. package/src/fonts/Makefile +139 -0
  120. package/src/fonts/default.cfg +20 -0
  121. package/src/fonts/generate_fonts.py +61 -0
  122. package/src/fonts/lib/Extra.otf +0 -0
  123. package/src/fonts/lib/Space.ttx +234 -0
  124. package/src/fonts/makeBlacker +49 -0
  125. package/src/fonts/makeFF +2003 -0
  126. package/src/fonts/xbbold.mf +182 -0
  127. package/src/fonts.less +64 -0
  128. package/src/functions/accent.js +3 -2
  129. package/src/functions/arrow.js +8 -2
  130. package/src/functions/color.js +4 -4
  131. package/src/functions/cr.js +7 -25
  132. package/src/functions/def.js +50 -24
  133. package/src/functions/delimsizing.js +8 -0
  134. package/src/functions/enclose.js +80 -12
  135. package/src/functions/environment.js +1 -1
  136. package/src/functions/font.js +3 -4
  137. package/src/functions/genfrac.js +36 -11
  138. package/src/functions/hbox.js +39 -0
  139. package/src/functions/kern.js +1 -0
  140. package/src/functions/mathchoice.js +1 -0
  141. package/src/functions/mclass.js +2 -1
  142. package/src/functions/op.js +3 -7
  143. package/src/functions/operatorname.js +1 -1
  144. package/src/functions/raisebox.js +0 -1
  145. package/src/functions/styling.js +1 -0
  146. package/src/functions/supsub.js +1 -3
  147. package/src/functions/symbolsOrd.js +0 -2
  148. package/src/functions/text.js +2 -3
  149. package/src/functions/vcenter.js +44 -0
  150. package/src/functions.js +3 -0
  151. package/src/katex.less +69 -16
  152. package/src/macros.js +42 -6
  153. package/src/mathMLTree.js +16 -1
  154. package/src/metrics/.gitignore +1 -0
  155. package/src/metrics/README.md +23 -0
  156. package/src/metrics/extract_tfms.py +114 -0
  157. package/src/metrics/extract_ttfs.py +119 -0
  158. package/src/metrics/format_json.py +28 -0
  159. package/src/metrics/mapping.pl +1224 -0
  160. package/src/metrics/parse_tfm.py +211 -0
  161. package/src/parseNode.js +29 -1
  162. package/src/parseTree.js +6 -0
  163. package/src/stretchy.js +12 -5
  164. package/src/svgGeometry.js +33 -4
  165. package/src/symbols.js +5 -3
  166. package/src/types.js +3 -2
  167. package/src/unicodeScripts.js +5 -0
package/src/katex.less CHANGED
@@ -1,8 +1,8 @@
1
1
  /* stylelint-disable font-family-no-missing-generic-family-keyword */
2
- @import "../submodules/katex-fonts/fonts.less";
2
+ @import "fonts.less";
3
3
 
4
4
  // The mu unit is defined as 1/18 em
5
- @mu: 1/18em;
5
+ @mu: (1em / 18);
6
6
 
7
7
  // The version is dynamically set from package.json via webpack.common.js
8
8
  @version: "";
@@ -17,20 +17,22 @@
17
17
  // Prevent a rendering bug that misplaces \vec in Chrome.
18
18
  text-rendering: auto;
19
19
 
20
- // Insulate fraction bars and rules from CSS that sets border-color.
21
- border-color: currentColor;
20
+ * {
21
+ // Prevent background resetting on elements in Windows's high-contrast
22
+ // mode, while still allowing background/foreground setting on root .katex
23
+ -ms-high-contrast-adjust: none !important;
22
24
 
23
- // Prevent background resetting on elements in Windows's high-contrast
24
- // mode, while still allowing background/foreground setting on root .katex
25
- * { -ms-high-contrast-adjust: none !important; }
25
+ // Insulate fraction bars and rules from CSS that sets border-color.
26
+ border-color: currentColor;
27
+ }
26
28
 
27
29
  .katex-version::after {
28
30
  content: @version;
29
31
  }
30
32
 
31
33
  .katex-mathml {
32
- // Accessibility hack to only show to screen readers
33
- // Found at: http://a11yproject.com/posts/how-to-hide-content/
34
+ /* Accessibility hack to only show to screen readers
35
+ Found at: http://a11yproject.com/posts/how-to-hide-content/ */
34
36
  position: absolute;
35
37
  clip: rect(1px, 1px, 1px, 1px);
36
38
  padding: 0;
@@ -161,7 +163,7 @@
161
163
  // This value is also used in fontMetrics.js, if you change it make sure the
162
164
  // values match.
163
165
  @ptperem: 10;
164
- @nulldelimiterspace: 1.2em / @ptperem;
166
+ @nulldelimiterspace: (1.2em / @ptperem);
165
167
 
166
168
  @muspace: 0.055556em; // 1mu
167
169
  @thinspace: 0.16667em; // 3mu
@@ -219,17 +221,13 @@
219
221
  }
220
222
 
221
223
  .vbox {
222
- display: -ms-inline-flexbox;
223
224
  display: inline-flex;
224
- -ms-flex-direction: column;
225
225
  flex-direction: column;
226
226
  align-items: baseline;
227
227
  }
228
228
 
229
229
  .hbox {
230
- display: -ms-inline-flexbox;
231
230
  display: inline-flex;
232
- -ms-flex-direction: row;
233
231
  flex-direction: row;
234
232
  width: 100%;
235
233
  }
@@ -322,8 +320,8 @@
322
320
 
323
321
  .sqrt {
324
322
  > .root {
325
- // These values are taken from the definition of `\r@@t`,
326
- // `\mkern 5mu` and `\mkern -10mu`.
323
+ /* These values are taken from the definition of `\r@@t`,
324
+ `\mkern 5mu` and `\mkern -10mu`. */
327
325
  margin-left: 5*@mu;
328
326
  margin-right: -10*@mu;
329
327
  }
@@ -559,6 +557,10 @@
559
557
  padding: 0 0.5em;
560
558
  }
561
559
 
560
+ .cd-arrow-pad {
561
+ padding: 0 0.55556em 0 0.27778em; // \;{#1}\;\;
562
+ }
563
+
562
564
  .x-arrow,
563
565
  .mover,
564
566
  .munder {
@@ -588,6 +590,51 @@
588
590
  border-bottom-style: solid;
589
591
  border-bottom-width: 0.08em;
590
592
  }
593
+
594
+ .angl {
595
+ // from package actuarialangle, which is always used in a subscript.
596
+ box-sizing: border-content;
597
+ border-top: 0.049em solid; // defaultRuleThickness in scriptstyle
598
+ border-right: 0.049em solid; // ditto
599
+ margin-right: 0.03889em; // 1 mu
600
+ }
601
+
602
+ .anglpad {
603
+ padding: 0 0.03889em 0 0.03889em; // pad 1mu left and right (in scriptstyle)
604
+ }
605
+
606
+ .eqn-num::before {
607
+ counter-increment: katexEqnNo;
608
+ content: "(" counter(katexEqnNo) ")";
609
+ }
610
+
611
+ .mml-eqn-num::before {
612
+ counter-increment: mmlEqnNo;
613
+ content: "(" counter(mmlEqnNo) ")";
614
+ }
615
+
616
+ .mtr-glue {
617
+ width: 50%;
618
+ }
619
+
620
+ .cd-vert-arrow {
621
+ display: inline-block;
622
+ position: relative;
623
+ }
624
+
625
+ .cd-label-left {
626
+ display: inline-block;
627
+ position: absolute;
628
+ right: calc(50% + 0.3em);
629
+ text-align: left;
630
+ }
631
+
632
+ .cd-label-right {
633
+ display: inline-block;
634
+ position: absolute;
635
+ left: calc(50% + 0.3em);
636
+ text-align: right;
637
+ }
591
638
  }
592
639
 
593
640
  .katex-display {
@@ -623,3 +670,9 @@
623
670
  text-align: left;
624
671
  padding-left: 2em;
625
672
  }
673
+
674
+ // Automatic equation numbers for some environments.
675
+ // Use parallel counters for HTML and MathML.
676
+ body {
677
+ counter-reset: katexEqnNo mmlEqnNo;
678
+ }
package/src/macros.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * This can be used to define some commands in terms of others.
5
5
  */
6
6
 
7
- import fontMetricsData from "../submodules/katex-fonts/fontMetricsData";
7
+ import fontMetricsData from "./fontMetricsData";
8
8
  import functions from "./functions";
9
9
  import symbols from "./symbols";
10
10
  import utils from "./utils";
@@ -71,6 +71,12 @@ export interface MacroContextInterface {
71
71
  */
72
72
  expandMacroAsText(name: string): string | void;
73
73
 
74
+ /**
75
+ * Consume an argument from the token stream, and return the resulting array
76
+ * of tokens and start/end token.
77
+ */
78
+ consumeArg(delims?: ?string[]): MacroArg;
79
+
74
80
  /**
75
81
  * Consume the specified number of arguments from the token stream,
76
82
  * and return the resulting array of arguments.
@@ -91,10 +97,17 @@ export interface MacroContextInterface {
91
97
  isExpandable(name: string): boolean;
92
98
  }
93
99
 
100
+ export type MacroArg = {
101
+ tokens: Token[],
102
+ start: Token,
103
+ end: Token
104
+ };
105
+
94
106
  /** Macro tokens (in reverse order). */
95
107
  export type MacroExpansion = {
96
108
  tokens: Token[],
97
109
  numArgs: number,
110
+ delimiters?: string[][],
98
111
  unexpandable?: boolean, // used in \let
99
112
  };
100
113
 
@@ -240,7 +253,7 @@ defineMacro("\\char", function(context) {
240
253
  // \renewcommand{\macro}[args]{definition}
241
254
  // TODO: Optional arguments: \newcommand{\macro}[args][default]{definition}
242
255
  const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
243
- let arg = context.consumeArgs(1)[0];
256
+ let arg = context.consumeArg().tokens;
244
257
  if (arg.length !== 1) {
245
258
  throw new ParseError(
246
259
  "\\newcommand's first argument must be a macro name");
@@ -258,7 +271,7 @@ const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
258
271
  }
259
272
 
260
273
  let numArgs = 0;
261
- arg = context.consumeArgs(1)[0];
274
+ arg = context.consumeArg().tokens;
262
275
  if (arg.length === 1 && arg[0].text === "[") {
263
276
  let argText = '';
264
277
  let token = context.expandNextToken();
@@ -271,7 +284,7 @@ const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
271
284
  throw new ParseError(`Invalid number of arguments: ${argText}`);
272
285
  }
273
286
  numArgs = parseInt(argText);
274
- arg = context.consumeArgs(1)[0];
287
+ arg = context.consumeArg().tokens;
275
288
  }
276
289
 
277
290
  // Final arg is the expansion of the macro
@@ -314,10 +327,12 @@ defineMacro("\\bgroup", "{");
314
327
  defineMacro("\\egroup", "}");
315
328
 
316
329
  // Symbols from latex.ltx:
330
+ // \def~{\nobreakspace{}}
317
331
  // \def\lq{`}
318
332
  // \def\rq{'}
319
333
  // \def \aa {\r a}
320
334
  // \def \AA {\r A}
335
+ defineMacro("~", "\\nobreakspace");
321
336
  defineMacro("\\lq", "`");
322
337
  defineMacro("\\rq", "'");
323
338
  defineMacro("\\aa", "\\r a");
@@ -361,6 +376,12 @@ defineMacro("\\llap", "\\mathllap{\\textrm{#1}}");
361
376
  defineMacro("\\rlap", "\\mathrlap{\\textrm{#1}}");
362
377
  defineMacro("\\clap", "\\mathclap{\\textrm{#1}}");
363
378
 
379
+ // \mathstrut from the TeXbook, p 360
380
+ defineMacro("\\mathstrut", "\\vphantom{(}");
381
+
382
+ // \underbar from TeXbook p 353
383
+ defineMacro("\\underbar", "\\underline{\\text{#1}}");
384
+
364
385
  // \not is defined by base/fontmath.ltx via
365
386
  // \DeclareMathSymbol{\not}{\mathrel}{symbols}{"36}
366
387
  // It's thus treated like a \mathrel, but defined by a symbol that has zero
@@ -693,8 +714,10 @@ defineMacro("\\pmb", "\\html@mathml{" +
693
714
  //////////////////////////////////////////////////////////////////////
694
715
  // LaTeX source2e
695
716
 
696
- // \\ defaults to \newline, but changes to \cr within array environment
697
- defineMacro("\\\\", "\\newline");
717
+ // \expandafter\let\expandafter\@normalcr
718
+ // \csname\expandafter\@gobble\string\\ \endcsname
719
+ // \DeclareRobustCommand\newline{\@normalcr\relax}
720
+ defineMacro("\\newline", "\\\\\\relax");
698
721
 
699
722
  // \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
700
723
  // TODO: Doesn't normally work in math mode because \@ fails. KaTeX doesn't
@@ -839,6 +862,15 @@ defineMacro("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220C}}");
839
862
  defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}");
840
863
  defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}");
841
864
 
865
+ //////////////////////////////////////////////////////////////////////
866
+ // From amsopn.sty
867
+ defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}");
868
+ defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}");
869
+ defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{lim}}");
870
+ defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{lim}}");
871
+ defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{lim}}");
872
+ defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{lim}}");
873
+
842
874
  //////////////////////////////////////////////////////////////////////
843
875
  // MathML alternates for KaTeX glyphs in the Unicode private area
844
876
  defineMacro("\\gvertneqq", "\\html@mathml{\\@gvertneqq}{\u2269}");
@@ -987,6 +1019,10 @@ defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}");
987
1019
  defineMacro("\\Bra", "\\left\\langle#1\\right|");
988
1020
  defineMacro("\\Ket", "\\left|#1\\right\\rangle");
989
1021
 
1022
+ //////////////////////////////////////////////////////////////////////
1023
+ // actuarialangle.dtx
1024
+ defineMacro("\\angln", "{\\angl n}");
1025
+
990
1026
  // Custom Khan Academy colors, should be moved to an optional package
991
1027
  defineMacro("\\blue", "\\textcolor{##6495ed}{#1}");
992
1028
  defineMacro("\\orange", "\\textcolor{##ffa500}{#1}");
package/src/mathMLTree.js CHANGED
@@ -11,6 +11,7 @@
11
11
 
12
12
  import utils from "./utils";
13
13
  import {DocumentFragment} from "./tree";
14
+ import {createClass} from "./domTree";
14
15
 
15
16
  import type {VirtualNode} from "./tree";
16
17
 
@@ -47,11 +48,17 @@ export class MathNode implements MathDomNode {
47
48
  type: MathNodeType;
48
49
  attributes: {[string]: string};
49
50
  children: $ReadOnlyArray<MathDomNode>;
51
+ classes: string[];
50
52
 
51
- constructor(type: MathNodeType, children?: $ReadOnlyArray<MathDomNode>) {
53
+ constructor(
54
+ type: MathNodeType,
55
+ children?: $ReadOnlyArray<MathDomNode>,
56
+ classes?: string[]
57
+ ) {
52
58
  this.type = type;
53
59
  this.attributes = {};
54
60
  this.children = children || [];
61
+ this.classes = classes || [];
55
62
  }
56
63
 
57
64
  /**
@@ -82,6 +89,10 @@ export class MathNode implements MathDomNode {
82
89
  }
83
90
  }
84
91
 
92
+ if (this.classes.length > 0) {
93
+ node.className = createClass(this.classes);
94
+ }
95
+
85
96
  for (let i = 0; i < this.children.length; i++) {
86
97
  node.appendChild(this.children[i].toNode());
87
98
  }
@@ -104,6 +115,10 @@ export class MathNode implements MathDomNode {
104
115
  }
105
116
  }
106
117
 
118
+ if (this.classes.length > 0) {
119
+ markup += ` class ="${utils.escape(createClass(this.classes))}"`;
120
+ }
121
+
107
122
  markup += ">";
108
123
 
109
124
  for (let i = 0; i < this.children.length; i++) {
@@ -0,0 +1 @@
1
+ *.pyc
@@ -0,0 +1,23 @@
1
+ ### How to generate new metrics
2
+ -------------------------------
3
+
4
+ There are several requirements for generating the metrics used by KaTeX.
5
+
6
+ - You need to have an installation of TeX which supports kpathsea. You can check
7
+ this by running `tex --version`, and seeing if it has a line that looks like
8
+ > kpathsea version 6.2.0
9
+
10
+ - You need the Perl module `JSON`. You can install this either from CPAN
11
+ (e.g. using the `cpan` command line tool: `cpan install JSON`)
12
+ or with your package manager.
13
+
14
+ - You need the Python module `fonttools`. You can install this either from PyPI
15
+ (using `easy_install` or `pip`: `pip install fonttools`)
16
+ or with your package manager.
17
+
18
+ Once you have these things, run the following command from the root directory:
19
+
20
+ sh ./docker/fonts/buildMetrics.sh
21
+
22
+ which should generate new metrics and place them into `fontMetricsData.json`.
23
+ You're done!
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env python
2
+
3
+ import collections
4
+ import json
5
+ import parse_tfm
6
+ import subprocess
7
+ import sys
8
+
9
+
10
+ def find_font_path(font_name):
11
+ try:
12
+ font_path = subprocess.check_output(['kpsewhich', font_name])
13
+ except OSError:
14
+ raise RuntimeError("Couldn't find kpsewhich program, make sure you" +
15
+ " have TeX installed")
16
+ except subprocess.CalledProcessError:
17
+ raise RuntimeError("Couldn't find font metrics: '%s'" % font_name)
18
+ return font_path.strip()
19
+
20
+
21
+ def main():
22
+ mapping = json.load(sys.stdin)
23
+
24
+ fonts = [
25
+ 'cmbsy10.tfm',
26
+ 'cmbx10.tfm',
27
+ 'cmbxti10.tfm',
28
+ 'cmex10.tfm',
29
+ 'cmmi10.tfm',
30
+ 'cmmib10.tfm',
31
+ 'cmr10.tfm',
32
+ 'cmsy10.tfm',
33
+ 'cmti10.tfm',
34
+ 'msam10.tfm',
35
+ 'msbm10.tfm',
36
+ 'eufm10.tfm',
37
+ 'cmtt10.tfm',
38
+ 'rsfs10.tfm',
39
+ 'cmss10.tfm',
40
+ 'cmssbx10.tfm',
41
+ 'cmssi10.tfm',
42
+ ]
43
+
44
+ # Extracted by running `\font\a=<font>` and then `\showthe\skewchar\a` in
45
+ # TeX, where `<font>` is the name of the font listed here. The skewchar
46
+ # will be printed out in the output. If it outputs `-1`, that means there
47
+ # is no skewchar, so we use `None` here.
48
+ font_skewchar = {
49
+ 'cmbsy10': None,
50
+ 'cmbx10': None,
51
+ 'cmbxti10': None,
52
+ 'cmex10': None,
53
+ 'cmmi10': 127,
54
+ 'cmmib10': None,
55
+ 'cmr10': None,
56
+ 'cmsy10': 48,
57
+ 'cmti10': None,
58
+ 'msam10': None,
59
+ 'msbm10': None,
60
+ 'eufm10': None,
61
+ 'cmtt10': None,
62
+ 'rsfs10': None,
63
+ 'cmss10': None,
64
+ 'cmssbx10': None,
65
+ 'cmssi10': None,
66
+ }
67
+
68
+ font_name_to_tfm = {}
69
+
70
+ for font_name in fonts:
71
+ font_basename = font_name.split('.')[0]
72
+ font_path = find_font_path(font_name)
73
+ font_name_to_tfm[font_basename] = parse_tfm.read_tfm_file(font_path)
74
+
75
+ families = collections.defaultdict(dict)
76
+
77
+ for family, chars in mapping.iteritems():
78
+ for char, char_data in chars.iteritems():
79
+ char_num = int(char)
80
+
81
+ font = char_data['font']
82
+ tex_char_num = int(char_data['char'])
83
+ yshift = float(char_data['yshift'])
84
+
85
+ if family == "Script-Regular":
86
+ tfm_char = font_name_to_tfm[font].get_char_metrics(tex_char_num,
87
+ fix_rsfs=True)
88
+ else:
89
+ tfm_char = font_name_to_tfm[font].get_char_metrics(tex_char_num)
90
+
91
+ height = round(tfm_char.height + yshift / 1000.0, 5)
92
+ depth = round(tfm_char.depth - yshift / 1000.0, 5)
93
+ italic = round(tfm_char.italic_correction, 5)
94
+ width = round(tfm_char.width, 5)
95
+
96
+ skewkern = 0.0
97
+ if (font_skewchar[font] and
98
+ font_skewchar[font] in tfm_char.kern_table):
99
+ skewkern = round(
100
+ tfm_char.kern_table[font_skewchar[font]], 5)
101
+
102
+ families[family][char_num] = {
103
+ 'height': height,
104
+ 'depth': depth,
105
+ 'italic': italic,
106
+ 'skew': skewkern,
107
+ 'width': width
108
+ }
109
+
110
+ sys.stdout.write(
111
+ json.dumps(families, separators=(',', ':'), sort_keys=True))
112
+
113
+ if __name__ == '__main__':
114
+ main()
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env python
2
+
3
+ from fontTools.ttLib import TTFont
4
+ import sys
5
+ import json
6
+
7
+ # map of characters to extract
8
+ metrics_to_extract = {
9
+ # Font name
10
+ "AMS-Regular": {
11
+ u"\u21e2": None, # \dashrightarrow
12
+ u"\u21e0": None, # \dashleftarrow
13
+ },
14
+ "Main-Regular": {
15
+ # Skew and italic metrics can't be easily parsed from the TTF. Instead,
16
+ # we map each character to a "base character", which is a character
17
+ # from the same font with correct italic and skew metrics. A character
18
+ # maps to None if it doesn't have a base.
19
+
20
+ #u"\u2209": None, # \notin
21
+ #u"\u2260": None, # \neq
22
+ u"\u2245": None, # \cong
23
+ u"\u2026": None, # \ldots
24
+ u"\u22ef": None, # \cdots
25
+ u"\u22f1": None, # \ddots
26
+ u"\u22ee": None, # \vdots
27
+ u"\u22ee": None, # \vdots
28
+ u"\u22a8": None, # \models
29
+ u"\u22c8": None, # \bowtie
30
+ u"\u2250": None, # \doteq
31
+ u"\u23b0": None, # \lmoustache
32
+ u"\u23b1": None, # \rmoustache
33
+ u"\u27ee": None, # \lgroup
34
+ u"\u27ef": None, # \rgroup
35
+ u"\u27f5": None, # \longleftarrow
36
+ u"\u27f8": None, # \Longleftarrow
37
+ u"\u27f6": None, # \longrightarrow
38
+ u"\u27f9": None, # \Longrightarrow
39
+ u"\u27f7": None, # \longleftrightarrow
40
+ u"\u27fa": None, # \Longleftrightarrow
41
+ u"\u21a6": None, # \mapsto
42
+ u"\u27fc": None, # \longmapsto
43
+ u"\u21a9": None, # \hookleftarrow
44
+ u"\u21aa": None, # \hookrightarrow
45
+ u"\u21cc": None, # \rightleftharpoons
46
+ },
47
+ "Size1-Regular": {
48
+ u"\u222c": u"\u222b", # \iint, based on \int
49
+ u"\u222d": u"\u222b", # \iiint, based on \int
50
+ },
51
+ "Size2-Regular": {
52
+ u"\u222c": u"\u222b", # \iint, based on \int
53
+ u"\u222d": u"\u222b", # \iiint, based on \int
54
+ },
55
+ }
56
+
57
+
58
+ def main():
59
+ start_json = json.load(sys.stdin)
60
+
61
+ for font in start_json:
62
+ fontInfo = TTFont("../../fonts/KaTeX_" + font + ".ttf")
63
+ glyf = fontInfo["glyf"]
64
+ widths = fontInfo.getGlyphSet()
65
+ unitsPerEm = float(fontInfo["head"].unitsPerEm)
66
+
67
+ # We keep ALL Unicode cmaps, not just fontInfo["cmap"].getcmap(3, 1).
68
+ # This is playing it extra safe, since it reports inconsistencies.
69
+ # Platform 0 is Unicode, platform 3 is Windows. For platform 3,
70
+ # encoding 1 is UCS-2 and encoding 10 is UCS-4.
71
+ cmap = [t.cmap for t in fontInfo["cmap"].tables
72
+ if (t.platformID == 0)
73
+ or (t.platformID == 3 and t.platEncID in (1, 10))]
74
+
75
+ chars = metrics_to_extract.get(font, {})
76
+ chars[u"\u0020"] = None # space
77
+ chars[u"\u00a0"] = None # nbsp
78
+
79
+ for char, base_char in chars.iteritems():
80
+ code = ord(char)
81
+ names = set(t.get(code) for t in cmap)
82
+ if not names:
83
+ sys.stderr.write(
84
+ "Codepoint {} of font {} maps to no name\n"
85
+ .format(code, font))
86
+ continue
87
+ if len(names) != 1:
88
+ sys.stderr.write(
89
+ "Codepoint {} of font {} maps to multiple names: {}\n"
90
+ .format(code, font, ", ".join(sorted(names))))
91
+ continue
92
+ name = names.pop()
93
+
94
+ height = depth = italic = skew = width = 0
95
+ glyph = glyf[name]
96
+ if glyph.numberOfContours:
97
+ height = glyph.yMax / unitsPerEm
98
+ depth = -glyph.yMin / unitsPerEm
99
+ width = widths[name].width / unitsPerEm
100
+ if base_char:
101
+ base_char_str = str(ord(base_char))
102
+ base_metrics = start_json[font][base_char_str]
103
+ italic = base_metrics["italic"]
104
+ skew = base_metrics["skew"]
105
+ width = base_metrics["width"]
106
+
107
+ start_json[font][str(code)] = {
108
+ "height": height,
109
+ "depth": depth,
110
+ "italic": italic,
111
+ "skew": skew,
112
+ "width": width
113
+ }
114
+
115
+ sys.stdout.write(
116
+ json.dumps(start_json, separators=(',', ':'), sort_keys=True))
117
+
118
+ if __name__ == "__main__":
119
+ main()
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env python
2
+
3
+ import sys
4
+ import json
5
+
6
+ props = ['depth', 'height', 'italic', 'skew']
7
+
8
+ if len(sys.argv) > 1:
9
+ if sys.argv[1] == '--width':
10
+ props.append('width')
11
+
12
+ data = json.load(sys.stdin)
13
+ sys.stdout.write(
14
+ "// This file is GENERATED by buildMetrics.sh. DO NOT MODIFY.\n")
15
+ sep = "export default {\n "
16
+ for font in sorted(data):
17
+ sys.stdout.write(sep + json.dumps(font))
18
+ sep = ": {\n "
19
+ for glyph in sorted(data[font], key=int):
20
+ sys.stdout.write(sep + json.dumps(glyph) + ": ")
21
+
22
+ values = [value if value != 0.0 else 0 for value in
23
+ [data[font][glyph][key] for key in props]]
24
+
25
+ sys.stdout.write(json.dumps(values))
26
+ sep = ",\n "
27
+ sep = ",\n },\n "
28
+ sys.stdout.write(",\n },\n};\n")