1/** 2 * Lexing or parsing positional information for error reporting. 3 * This object is immutable. 4 */ 5class SourceLocation { 6 // The + prefix indicates that these fields aren't writeable 7 // Lexer holding the input string. 8 // Start offset, zero-based inclusive. 9 // End offset, zero-based exclusive. 10 constructor(lexer, start, end) { 11 this.lexer = void 0; 12 this.start = void 0; 13 this.end = void 0; 14 this.lexer = lexer; 15 this.start = start; 16 this.end = end; 17 } 18 /** 19 * Merges two `SourceLocation`s from location providers, given they are 20 * provided in order of appearance. 21 * - Returns the first one's location if only the first is provided. 22 * - Returns a merged range of the first and the last if both are provided 23 * and their lexers match. 24 * - Otherwise, returns null. 25 */ 26 27 28 static range(first, second) { 29 if (!second) { 30 return first && first.loc; 31 } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { 32 return null; 33 } else { 34 return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); 35 } 36 } 37 38} 39 40/** 41 * Interface required to break circular dependency between Token, Lexer, and 42 * ParseError. 43 */ 44 45/** 46 * The resulting token returned from `lex`. 47 * 48 * It consists of the token text plus some position information. 49 * The position information is essentially a range in an input string, 50 * but instead of referencing the bare input string, we refer to the lexer. 51 * That way it is possible to attach extra metadata to the input string, 52 * like for example a file name or similar. 53 * 54 * The position information is optional, so it is OK to construct synthetic 55 * tokens if appropriate. Not providing available position information may 56 * lead to degraded error reporting, though. 57 */ 58class Token { 59 constructor(text, // the text of this token 60 loc) { 61 this.text = void 0; 62 this.loc = void 0; 63 this.text = text; 64 this.loc = loc; 65 } 66 /** 67 * Given a pair of tokens (this and endToken), compute a `Token` encompassing 68 * the whole input range enclosed by these two. 69 */ 70 71 72 range(endToken, // last token of the range, inclusive 73 text) // the text of the newly constructed token 74 { 75 return new Token(text, SourceLocation.range(this, endToken)); 76 } 77 78} 79 80/** 81 * This is the ParseError class, which is the main error thrown by KaTeX 82 * functions when something has gone wrong. This is used to distinguish internal 83 * errors from errors in the expression that the user provided. 84 * 85 * If possible, a caller should provide a Token or ParseNode with information 86 * about where in the source string the problem occurred. 87 */ 88class ParseError { 89 // Error position based on passed-in Token or ParseNode. 90 constructor(message, // The error message 91 token) // An object providing position information 92 { 93 this.position = void 0; 94 let error = "KaTeX parse error: " + message; 95 let start; 96 const loc = token && token.loc; 97 98 if (loc && loc.start <= loc.end) { 99 // If we have the input and a position, make the error a bit fancier 100 // Get the input 101 const input = loc.lexer.input; // Prepend some information 102 103 start = loc.start; 104 const end = loc.end; 105 106 if (start === input.length) { 107 error += " at end of input: "; 108 } else { 109 error += " at position " + (start + 1) + ": "; 110 } // Underline token in question using combining underscores 111 112 113 const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); // Extract some context from the input and add it to the error 114 115 let left; 116 117 if (start > 15) { 118 left = "…" + input.slice(start - 15, start); 119 } else { 120 left = input.slice(0, start); 121 } 122 123 let right; 124 125 if (end + 15 < input.length) { 126 right = input.slice(end, end + 15) + "…"; 127 } else { 128 right = input.slice(end); 129 } 130 131 error += left + underlined + right; 132 } // Some hackery to make ParseError a prototype of Error 133 // See http://stackoverflow.com/a/8460753 134 135 136 const self = new Error(error); 137 self.name = "ParseError"; // $FlowFixMe 138 139 self.__proto__ = ParseError.prototype; // $FlowFixMe 140 141 self.position = start; 142 return self; 143 } 144 145} // $FlowFixMe More hackery 146 147 148ParseError.prototype.__proto__ = Error.prototype; 149 150/** 151 * This file contains a list of utility functions which are useful in other 152 * files. 153 */ 154 155/** 156 * Return whether an element is contained in a list 157 */ 158const contains = function contains(list, elem) { 159 return list.indexOf(elem) !== -1; 160}; 161/** 162 * Provide a default value if a setting is undefined 163 * NOTE: Couldn't use `T` as the output type due to facebook/flow#5022. 164 */ 165 166 167const deflt = function deflt(setting, defaultIfUndefined) { 168 return setting === undefined ? defaultIfUndefined : setting; 169}; // hyphenate and escape adapted from Facebook's React under Apache 2 license 170 171 172const uppercase = /([A-Z])/g; 173 174const hyphenate = function hyphenate(str) { 175 return str.replace(uppercase, "-$1").toLowerCase(); 176}; 177 178const ESCAPE_LOOKUP = { 179 "&": "&", 180 ">": ">", 181 "<": "<", 182 "\"": """, 183 "'": "'" 184}; 185const ESCAPE_REGEX = /[&><"']/g; 186/** 187 * Escapes text to prevent scripting attacks. 188 */ 189 190function escape(text) { 191 return String(text).replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); 192} 193/** 194 * Sometimes we want to pull out the innermost element of a group. In most 195 * cases, this will just be the group itself, but when ordgroups and colors have 196 * a single element, we want to pull that out. 197 */ 198 199 200const getBaseElem = function getBaseElem(group) { 201 if (group.type === "ordgroup") { 202 if (group.body.length === 1) { 203 return getBaseElem(group.body[0]); 204 } else { 205 return group; 206 } 207 } else if (group.type === "color") { 208 if (group.body.length === 1) { 209 return getBaseElem(group.body[0]); 210 } else { 211 return group; 212 } 213 } else if (group.type === "font") { 214 return getBaseElem(group.body); 215 } else { 216 return group; 217 } 218}; 219/** 220 * TeXbook algorithms often reference "character boxes", which are simply groups 221 * with a single character in them. To decide if something is a character box, 222 * we find its innermost group, and see if it is a single character. 223 */ 224 225 226const isCharacterBox = function isCharacterBox(group) { 227 const baseElem = getBaseElem(group); // These are all they types of groups which hold single characters 228 229 return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom"; 230}; 231 232const assert = function assert(value) { 233 if (!value) { 234 throw new Error('Expected non-null, but got ' + String(value)); 235 } 236 237 return value; 238}; 239/** 240 * Return the protocol of a URL, or "_relative" if the URL does not specify a 241 * protocol (and thus is relative). 242 */ 243 244const protocolFromUrl = function protocolFromUrl(url) { 245 const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); 246 return protocol != null ? protocol[1] : "_relative"; 247}; 248var utils = { 249 contains, 250 deflt, 251 escape, 252 hyphenate, 253 getBaseElem, 254 isCharacterBox, 255 protocolFromUrl 256}; 257 258/* eslint no-console:0 */ 259 260/** 261 * The main Settings object 262 * 263 * The current options stored are: 264 * - displayMode: Whether the expression should be typeset as inline math 265 * (false, the default), meaning that the math starts in 266 * \textstyle and is placed in an inline-block); or as display 267 * math (true), meaning that the math starts in \displaystyle 268 * and is placed in a block with vertical margin. 269 */ 270class Settings { 271 constructor(options) { 272 this.displayMode = void 0; 273 this.output = void 0; 274 this.leqno = void 0; 275 this.fleqn = void 0; 276 this.throwOnError = void 0; 277 this.errorColor = void 0; 278 this.macros = void 0; 279 this.minRuleThickness = void 0; 280 this.colorIsTextColor = void 0; 281 this.strict = void 0; 282 this.trust = void 0; 283 this.maxSize = void 0; 284 this.maxExpand = void 0; 285 // allow null options 286 options = options || {}; 287 this.displayMode = utils.deflt(options.displayMode, false); 288 this.output = utils.deflt(options.output, "htmlAndMathml"); 289 this.leqno = utils.deflt(options.leqno, false); 290 this.fleqn = utils.deflt(options.fleqn, false); 291 this.throwOnError = utils.deflt(options.throwOnError, true); 292 this.errorColor = utils.deflt(options.errorColor, "#cc0000"); 293 this.macros = options.macros || {}; 294 this.minRuleThickness = Math.max(0, utils.deflt(options.minRuleThickness, 0)); 295 this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); 296 this.strict = utils.deflt(options.strict, "warn"); 297 this.trust = utils.deflt(options.trust, false); 298 this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity)); 299 this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); 300 } 301 /** 302 * Report nonstrict (non-LaTeX-compatible) input. 303 * Can safely not be called if `this.strict` is false in JavaScript. 304 */ 305 306 307 reportNonstrict(errorCode, errorMsg, token) { 308 let strict = this.strict; 309 310 if (typeof strict === "function") { 311 // Allow return value of strict function to be boolean or string 312 // (or null/undefined, meaning no further processing). 313 strict = strict(errorCode, errorMsg, token); 314 } 315 316 if (!strict || strict === "ignore") { 317 return; 318 } else if (strict === true || strict === "error") { 319 throw new ParseError("LaTeX-incompatible input and strict mode is set to 'error': " + `${errorMsg} [${errorCode}]`, token); 320 } else if (strict === "warn") { 321 typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to 'warn': " + `${errorMsg} [${errorCode}]`); 322 } else { 323 // won't happen in type-safe code 324 typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to " + `unrecognized '${strict}': ${errorMsg} [${errorCode}]`); 325 } 326 } 327 /** 328 * Check whether to apply strict (LaTeX-adhering) behavior for unusual 329 * input (like `\\`). Unlike `nonstrict`, will not throw an error; 330 * instead, "error" translates to a return value of `true`, while "ignore" 331 * translates to a return value of `false`. May still print a warning: 332 * "warn" prints a warning and returns `false`. 333 * This is for the second category of `errorCode`s listed in the README. 334 */ 335 336 337 useStrictBehavior(errorCode, errorMsg, token) { 338 let strict = this.strict; 339 340 if (typeof strict === "function") { 341 // Allow return value of strict function to be boolean or string 342 // (or null/undefined, meaning no further processing). 343 // But catch any exceptions thrown by function, treating them 344 // like "error". 345 try { 346 strict = strict(errorCode, errorMsg, token); 347 } catch (error) { 348 strict = "error"; 349 } 350 } 351 352 if (!strict || strict === "ignore") { 353 return false; 354 } else if (strict === true || strict === "error") { 355 return true; 356 } else if (strict === "warn") { 357 typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to 'warn': " + `${errorMsg} [${errorCode}]`); 358 return false; 359 } else { 360 // won't happen in type-safe code 361 typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to " + `unrecognized '${strict}': ${errorMsg} [${errorCode}]`); 362 return false; 363 } 364 } 365 /** 366 * Check whether to test potentially dangerous input, and return 367 * `true` (trusted) or `false` (untrusted). The sole argument `context` 368 * should be an object with `command` field specifying the relevant LaTeX 369 * command (as a string starting with `\`), and any other arguments, etc. 370 * If `context` has a `url` field, a `protocol` field will automatically 371 * get added by this function (changing the specified object). 372 */ 373 374 375 isTrusted(context) { 376 if (context.url && !context.protocol) { 377 context.protocol = utils.protocolFromUrl(context.url); 378 } 379 380 const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; 381 return Boolean(trust); 382 } 383 384} 385 386/** 387 * This file contains information and classes for the various kinds of styles 388 * used in TeX. It provides a generic `Style` class, which holds information 389 * about a specific style. It then provides instances of all the different kinds 390 * of styles possible, and provides functions to move between them and get 391 * information about them. 392 */ 393 394/** 395 * The main style class. Contains a unique id for the style, a size (which is 396 * the same for cramped and uncramped version of a style), and a cramped flag. 397 */ 398class Style { 399 constructor(id, size, cramped) { 400 this.id = void 0; 401 this.size = void 0; 402 this.cramped = void 0; 403 this.id = id; 404 this.size = size; 405 this.cramped = cramped; 406 } 407 /** 408 * Get the style of a superscript given a base in the current style. 409 */ 410 411 412 sup() { 413 return styles[sup[this.id]]; 414 } 415 /** 416 * Get the style of a subscript given a base in the current style. 417 */ 418 419 420 sub() { 421 return styles[sub[this.id]]; 422 } 423 /** 424 * Get the style of a fraction numerator given the fraction in the current 425 * style. 426 */ 427 428 429 fracNum() { 430 return styles[fracNum[this.id]]; 431 } 432 /** 433 * Get the style of a fraction denominator given the fraction in the current 434 * style. 435 */ 436 437 438 fracDen() { 439 return styles[fracDen[this.id]]; 440 } 441 /** 442 * Get the cramped version of a style (in particular, cramping a cramped style 443 * doesn't change the style). 444 */ 445 446 447 cramp() { 448 return styles[cramp[this.id]]; 449 } 450 /** 451 * Get a text or display version of this style. 452 */ 453 454 455 text() { 456 return styles[text[this.id]]; 457 } 458 /** 459 * Return true if this style is tightly spaced (scriptstyle/scriptscriptstyle) 460 */ 461 462 463 isTight() { 464 return this.size >= 2; 465 } 466 467} // Export an interface for type checking, but don't expose the implementation. 468// This way, no more styles can be generated. 469 470 471// IDs of the different styles 472const D = 0; 473const Dc = 1; 474const T = 2; 475const Tc = 3; 476const S = 4; 477const Sc = 5; 478const SS = 6; 479const SSc = 7; // Instances of the different styles 480 481const styles = [new Style(D, 0, false), new Style(Dc, 0, true), new Style(T, 1, false), new Style(Tc, 1, true), new Style(S, 2, false), new Style(Sc, 2, true), new Style(SS, 3, false), new Style(SSc, 3, true)]; // Lookup tables for switching from one style to another 482 483const sup = [S, Sc, S, Sc, SS, SSc, SS, SSc]; 484const sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc]; 485const fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc]; 486const fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc]; 487const cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc]; 488const text = [D, Dc, T, Tc, T, Tc, T, Tc]; // We only export some of the styles. 489 490var Style$1 = { 491 DISPLAY: styles[D], 492 TEXT: styles[T], 493 SCRIPT: styles[S], 494 SCRIPTSCRIPT: styles[SS] 495}; 496 497/* 498 * This file defines the Unicode scripts and script families that we 499 * support. To add new scripts or families, just add a new entry to the 500 * scriptData array below. Adding scripts to the scriptData array allows 501 * characters from that script to appear in \text{} environments. 502 */ 503 504/** 505 * Each script or script family has a name and an array of blocks. 506 * Each block is an array of two numbers which specify the start and 507 * end points (inclusive) of a block of Unicode codepoints. 508 */ 509 510/** 511 * Unicode block data for the families of scripts we support in \text{}. 512 * Scripts only need to appear here if they do not have font metrics. 513 */ 514const scriptData = [{ 515 // Latin characters beyond the Latin-1 characters we have metrics for. 516 // Needed for Czech, Hungarian and Turkish text, for example. 517 name: 'latin', 518 blocks: [[0x0100, 0x024f], // Latin Extended-A and Latin Extended-B 519 [0x0300, 0x036f]] 520}, { 521 // The Cyrillic script used by Russian and related languages. 522 // A Cyrillic subset used to be supported as explicitly defined 523 // symbols in symbols.js 524 name: 'cyrillic', 525 blocks: [[0x0400, 0x04ff]] 526}, { 527 // The Brahmic scripts of South and Southeast Asia 528 // Devanagari (0900–097F) 529 // Bengali (0980–09FF) 530 // Gurmukhi (0A00–0A7F) 531 // Gujarati (0A80–0AFF) 532 // Oriya (0B00–0B7F) 533 // Tamil (0B80–0BFF) 534 // Telugu (0C00–0C7F) 535 // Kannada (0C80–0CFF) 536 // Malayalam (0D00–0D7F) 537 // Sinhala (0D80–0DFF) 538 // Thai (0E00–0E7F) 539 // Lao (0E80–0EFF) 540 // Tibetan (0F00–0FFF) 541 // Myanmar (1000–109F) 542 name: 'brahmic', 543 blocks: [[0x0900, 0x109F]] 544}, { 545 name: 'georgian', 546 blocks: [[0x10A0, 0x10ff]] 547}, { 548 // Chinese and Japanese. 549 // The "k" in cjk is for Korean, but we've separated Korean out 550 name: "cjk", 551 blocks: [[0x3000, 0x30FF], // CJK symbols and punctuation, Hiragana, Katakana 552 [0x4E00, 0x9FAF], // CJK ideograms 553 [0xFF00, 0xFF60]] 554}, { 555 // Korean 556 name: 'hangul', 557 blocks: [[0xAC00, 0xD7AF]] 558}]; 559/** 560 * Given a codepoint, return the name of the script or script family 561 * it is from, or null if it is not part of a known block 562 */ 563 564function scriptFromCodepoint(codepoint) { 565 for (let i = 0; i < scriptData.length; i++) { 566 const script = scriptData[i]; 567 568 for (let i = 0; i < script.blocks.length; i++) { 569 const block = script.blocks[i]; 570 571 if (codepoint >= block[0] && codepoint <= block[1]) { 572 return script.name; 573 } 574 } 575 } 576 577 return null; 578} 579/** 580 * A flattened version of all the supported blocks in a single array. 581 * This is an optimization to make supportedCodepoint() fast. 582 */ 583 584const allBlocks = []; 585scriptData.forEach(s => s.blocks.forEach(b => allBlocks.push(...b))); 586/** 587 * Given a codepoint, return true if it falls within one of the 588 * scripts or script families defined above and false otherwise. 589 * 590 * Micro benchmarks shows that this is faster than 591 * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() 592 * in Firefox, Chrome and Node. 593 */ 594 595function supportedCodepoint(codepoint) { 596 for (let i = 0; i < allBlocks.length; i += 2) { 597 if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { 598 return true; 599 } 600 } 601 602 return false; 603} 604 605/** 606 * This file provides support to domTree.js and delimiter.js. 607 * It's a storehouse of path geometry for SVG images. 608 */ 609// In all paths below, the viewBox-to-em scale is 1000:1. 610const hLinePad = 80; // padding above a sqrt viniculum. Prevents image cropping. 611// The viniculum of a \sqrt can be made thicker by a KaTeX rendering option. 612// Think of variable extraViniculum as two detours in the SVG path. 613// The detour begins at the lower left of the area labeled extraViniculum below. 614// The detour proceeds one extraViniculum distance up and slightly to the right, 615// displacing the radiused corner between surd and viniculum. The radius is 616// traversed as usual, then the detour resumes. It goes right, to the end of 617// the very long viniculumn, then down one extraViniculum distance, 618// after which it resumes regular path geometry for the radical. 619 620/* viniculum 621 / 622 /▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒←extraViniculum 623 / █████████████████████←0.04em (40 unit) std viniculum thickness 624 / / 625 / / 626 / /\ 627 / / surd 628*/ 629 630const sqrtMain = function sqrtMain(extraViniculum, hLinePad) { 631 // sqrtMain path geometry is from glyph U221A in the font KaTeX Main 632 return `M95,${622 + extraViniculum + hLinePad} 633c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14 634c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54 635c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10 636s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429 637c69,-144,104.5,-217.7,106.5,-221 638l${extraViniculum / 2.075} -${extraViniculum} 639c5.3,-9.3,12,-14,20,-14 640H400000v${40 + extraViniculum}H845.2724 641s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7 642c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z 643M${834 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`; 644}; 645 646const sqrtSize1 = function sqrtSize1(extraViniculum, hLinePad) { 647 // size1 is from glyph U221A in the font KaTeX_Size1-Regular 648 return `M263,${601 + extraViniculum + hLinePad}c0.7,0,18,39.7,52,119 649c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120 650c340,-704.7,510.7,-1060.3,512,-1067 651l${extraViniculum / 2.084} -${extraViniculum} 652c4.7,-7.3,11,-11,19,-11 653H40000v${40 + extraViniculum}H1012.3 654s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232 655c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1 656s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26 657c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z 658M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`; 659}; 660 661const sqrtSize2 = function sqrtSize2(extraViniculum, hLinePad) { 662 // size2 is from glyph U221A in the font KaTeX_Size2-Regular 663 return `M983 ${10 + extraViniculum + hLinePad} 664l${extraViniculum / 3.13} -${extraViniculum} 665c4,-6.7,10,-10,18,-10 H400000v${40 + extraViniculum} 666H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7 667s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744 668c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30 669c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722 670c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5 671c53.7,-170.3,84.5,-266.8,92.5,-289.5z 672M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`; 673}; 674 675const sqrtSize3 = function sqrtSize3(extraViniculum, hLinePad) { 676 // size3 is from glyph U221A in the font KaTeX_Size3-Regular 677 return `M424,${2398 + extraViniculum + hLinePad} 678c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514 679c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20 680s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121 681s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081 682l${extraViniculum / 4.223} -${extraViniculum}c4,-6.7,10,-10,18,-10 H400000 683v${40 + extraViniculum}H1014.6 684s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185 685c-2,6,-10,9,-24,9 686c-8,0,-12,-0.7,-12,-2z M${1001 + extraViniculum} ${hLinePad} 687h400000v${40 + extraViniculum}h-400000z`; 688}; 689 690const sqrtSize4 = function sqrtSize4(extraViniculum, hLinePad) { 691 // size4 is from glyph U221A in the font KaTeX_Size4-Regular 692 return `M473,${2713 + extraViniculum + hLinePad} 693c339.3,-1799.3,509.3,-2700,510,-2702 l${extraViniculum / 5.298} -${extraViniculum} 694c3.3,-7.3,9.3,-11,18,-11 H400000v${40 + extraViniculum}H1017.7 695s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9 696c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200 697c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26 698s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104, 699606zM${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}H1017.7z`; 700}; 701 702const sqrtTall = function sqrtTall(extraViniculum, hLinePad, viewBoxHeight) { 703 // sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular 704 // One path edge has a variable length. It runs vertically from the viniculumn 705 // to a point near (14 units) the bottom of the surd. The viniculum 706 // is normally 40 units thick. So the length of the line in question is: 707 const vertSegment = viewBoxHeight - 54 - hLinePad - extraViniculum; 708 return `M702 ${extraViniculum + hLinePad}H400000${40 + extraViniculum} 709H742v${vertSegment}l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1 710h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170 711c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667 712219 661 l218 661zM702 ${hLinePad}H400000v${40 + extraViniculum}H742z`; 713}; 714 715const sqrtPath = function sqrtPath(size, extraViniculum, viewBoxHeight) { 716 extraViniculum = 1000 * extraViniculum; // Convert from document ems to viewBox. 717 718 let path = ""; 719 720 switch (size) { 721 case "sqrtMain": 722 path = sqrtMain(extraViniculum, hLinePad); 723 break; 724 725 case "sqrtSize1": 726 path = sqrtSize1(extraViniculum, hLinePad); 727 break; 728 729 case "sqrtSize2": 730 path = sqrtSize2(extraViniculum, hLinePad); 731 break; 732 733 case "sqrtSize3": 734 path = sqrtSize3(extraViniculum, hLinePad); 735 break; 736 737 case "sqrtSize4": 738 path = sqrtSize4(extraViniculum, hLinePad); 739 break; 740 741 case "sqrtTall": 742 path = sqrtTall(extraViniculum, hLinePad, viewBoxHeight); 743 } 744 745 return path; 746}; 747const path = { 748 // The doubleleftarrow geometry is from glyph U+21D0 in the font KaTeX Main 749 doubleleftarrow: `M262 157 750l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3 751 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28 752 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5 753c2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5 754 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87 755-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7 756-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z 757m8 0v40h399730v-40zm0 194v40h399730v-40z`, 758 // doublerightarrow is from glyph U+21D2 in font KaTeX Main 759 doublerightarrow: `M399738 392l 760-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5 761 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88 762-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68 763-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18 764-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782 765c-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3 766-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z`, 767 // leftarrow is from glyph U+2190 in font KaTeX Main 768 leftarrow: `M400000 241H110l3-3c68.7-52.7 113.7-120 769 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8 770-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247 771c-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208 772 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3 773 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202 774 l-3-3h399890zM100 241v40h399900v-40z`, 775 // overbrace is from glyphs U+23A9/23A8/23A7 in font KaTeX_Size4-Regular 776 leftbrace: `M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117 777-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7 778 5-6 9-10 13-.7 1-7.3 1-20 1H6z`, 779 leftbraceunder: `M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13 780 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688 781 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7 782-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z`, 783 // overgroup is from the MnSymbol package (public domain) 784 leftgroup: `M400000 80 785H435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0 786 435 0h399565z`, 787 leftgroupunder: `M400000 262 788H435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219 789 435 219h399565z`, 790 // Harpoons are from glyph U+21BD in font KaTeX Main 791 leftharpoon: `M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3 792-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5 793-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7 794-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z`, 795 leftharpoonplus: `M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5 796 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3 797-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7 798-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z 799m0 0v40h400000v-40z`, 800 leftharpoondown: `M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333 801 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5 802 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667 803-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z`, 804 leftharpoondownplus: `M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12 805 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7 806-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0 807v40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z`, 808 // hook is from glyph U+21A9 in font KaTeX Main 809 lefthook: `M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5 810-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3 811-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21 812 71.5 23h399859zM103 281v-40h399897v40z`, 813 leftlinesegment: `M40 281 V428 H0 V94 H40 V241 H400000 v40z 814M40 281 V428 H0 V94 H40 V241 H400000 v40z`, 815 leftmapsto: `M40 281 V448H0V74H40V241H400000v40z 816M40 281 V448H0V74H40V241H400000v40z`, 817 // tofrom is from glyph U+21C4 in font KaTeX AMS Regular 818 leftToFrom: `M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23 819-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8 820c28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3 821 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z`, 822 longequal: `M0 50 h400000 v40H0z m0 194h40000v40H0z 823M0 50 h400000 v40H0z m0 194h40000v40H0z`, 824 midbrace: `M200428 334 825c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14 826-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7 827 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11 828 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z`, 829 midbraceunder: `M199572 214 830c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14 831 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3 832 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0 833-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z`, 834 oiintSize1: `M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6 835-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z 836m368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8 83760.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z`, 838 oiintSize2: `M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8 839-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z 840m502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2 841c0 110 84 276 504 276s502.4-166 502.4-276z`, 842 oiiintSize1: `M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6 843-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z 844m525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0 84585.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z`, 846 oiiintSize2: `M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8 847-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z 848m770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1 849c0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z`, 850 rightarrow: `M0 241v40h399891c-47.3 35.3-84 78-110 128 851-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 852 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 853 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85 854-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 855-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 856 151.7 139 205zm0 0v40h399900v-40z`, 857 rightbrace: `M400000 542l 858-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5 859s-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1 860c124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z`, 861 rightbraceunder: `M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3 862 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237 863-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z`, 864 rightgroup: `M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0 865 3-1 3-3v-38c-76-158-257-219-435-219H0z`, 866 rightgroupunder: `M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18 867 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z`, 868 rightharpoon: `M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3 869-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2 870-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 871 69.2 92 94.5zm0 0v40h399900v-40z`, 872 rightharpoonplus: `M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11 873-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7 874 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z 875m0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z`, 876 rightharpoondown: `M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8 877 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5 878-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95 879-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z`, 880 rightharpoondownplus: `M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8 881 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 882 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3 883-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z 884m0-194v40h400000v-40zm0 0v40h400000v-40z`, 885 righthook: `M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3 886 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0 887-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21 888 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z`, 889 rightlinesegment: `M399960 241 V94 h40 V428 h-40 V281 H0 v-40z 890M399960 241 V94 h40 V428 h-40 V281 H0 v-40z`, 891 rightToFrom: `M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23 892 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32 893-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142 894-167z M100 147v40h399900v-40zM0 341v40h399900v-40z`, 895 // twoheadleftarrow is from glyph U+219E in font KaTeX AMS Regular 896 twoheadleftarrow: `M0 167c68 40 897 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69 898-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3 899-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19 900-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101 901 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z`, 902 twoheadrightarrow: `M400000 167 903c-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3 904 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42 905 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333 906-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70 907 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z`, 908 // tilde1 is a modified version of a glyph from the MnSymbol package 909 tilde1: `M200 55.538c-77 0-168 73.953-177 73.953-3 0-7 910-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0 911 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0 912 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128 913-68.267.847-113-73.952-191-73.952z`, 914 // ditto tilde2, tilde3, & tilde4 915 tilde2: `M344 55.266c-142 0-300.638 81.316-311.5 86.418 916-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9 917 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114 918c1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751 919 181.476 676 181.476c-149 0-189-126.21-332-126.21z`, 920 tilde3: `M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457 921-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0 922 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697 923 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696 924 -338 0-409-156.573-744-156.573z`, 925 tilde4: `M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345 926-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409 927 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9 928 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409 929 -175.236-744-175.236z`, 930 // vec is from glyph U+20D7 in font KaTeX Main 931 vec: `M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5 9323.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11 93310.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63 934-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1 935-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59 936H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359 937c-16-25.333-24-45-24-59z`, 938 // widehat1 is a modified version of a glyph from the MnSymbol package 939 widehat1: `M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22 940c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z`, 941 // ditto widehat2, widehat3, & widehat4 942 widehat2: `M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10 943-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, 944 widehat3: `M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10 945-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, 946 widehat4: `M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10 947-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, 948 // widecheck paths are all inverted versions of widehat 949 widecheck1: `M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1, 950-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z`, 951 widecheck2: `M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, 952-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`, 953 widecheck3: `M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, 954-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`, 955 widecheck4: `M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, 956-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`, 957 // The next ten paths support reaction arrows from the mhchem package. 958 // Arrows for \ce{<-->} are offset from xAxis by 0.22ex, per mhchem in LaTeX 959 // baraboveleftarrow is mostly from from glyph U+2190 in font KaTeX Main 960 baraboveleftarrow: `M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202 961c4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5 962c-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130 963s-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47 964121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6 965s2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11 966c0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z 967M100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z`, 968 // rightarrowabovebar is mostly from glyph U+2192, KaTeX Main 969 rightarrowabovebar: `M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32 970-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0 97113.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39 972-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5 973-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 974-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 975151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z`, 976 // The short left harpoon has 0.5em (i.e. 500 units) kern on the left end. 977 // Ref from mhchem.sty: \rlap{\raisebox{-.22ex}{$\kern0.5em 978 baraboveshortleftharpoon: `M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 979c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 980c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 981c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 982c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z 983M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`, 984 rightharpoonaboveshortbar: `M0,241 l0,40c399126,0,399993,0,399993,0 985c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, 986-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 987c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z 988M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`, 989 shortbaraboveleftharpoon: `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 990c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, 9911c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, 992-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z 993M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`, 994 shortrightharpoonabovebar: `M53,241l0,40c398570,0,399437,0,399437,0 995c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, 996-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 997c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z 998M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z` 999}; 1000 1001/** 1002 * This node represents a document fragment, which contains elements, but when 1003 * placed into the DOM doesn't have any representation itself. It only contains 1004 * children and doesn't have any DOM node properties. 1005 */ 1006class DocumentFragment { 1007 // HtmlDomNode 1008 // Never used; needed for satisfying interface. 1009 constructor(children) { 1010 this.children = void 0; 1011 this.classes = void 0; 1012 this.height = void 0; 1013 this.depth = void 0; 1014 this.maxFontSize = void 0; 1015 this.style = void 0; 1016 this.children = children; 1017 this.classes = []; 1018 this.height = 0; 1019 this.depth = 0; 1020 this.maxFontSize = 0; 1021 this.style = {}; 1022 } 1023 1024 hasClass(className) { 1025 return utils.contains(this.classes, className); 1026 } 1027 /** Convert the fragment into a node. */ 1028 1029 1030 toNode() { 1031 const frag = document.createDocumentFragment(); 1032 1033 for (let i = 0; i < this.children.length; i++) { 1034 frag.appendChild(this.children[i].toNode()); 1035 } 1036 1037 return frag; 1038 } 1039 /** Convert the fragment into HTML markup. */ 1040 1041 1042 toMarkup() { 1043 let markup = ""; // Simply concatenate the markup for the children together. 1044 1045 for (let i = 0; i < this.children.length; i++) { 1046 markup += this.children[i].toMarkup(); 1047 } 1048 1049 return markup; 1050 } 1051 /** 1052 * Converts the math node into a string, similar to innerText. Applies to 1053 * MathDomNode's only. 1054 */ 1055 1056 1057 toText() { 1058 // To avoid this, we would subclass documentFragment separately for 1059 // MathML, but polyfills for subclassing is expensive per PR 1469. 1060 // $FlowFixMe: Only works for ChildType = MathDomNode. 1061 const toText = child => child.toText(); 1062 1063 return this.children.map(toText).join(""); 1064 } 1065 1066} 1067 1068/** 1069 * These objects store the data about the DOM nodes we create, as well as some 1070 * extra data. They can then be transformed into real DOM nodes with the 1071 * `toNode` function or HTML markup using `toMarkup`. They are useful for both 1072 * storing extra properties on the nodes, as well as providing a way to easily 1073 * work with the DOM. 1074 * 1075 * Similar functions for working with MathML nodes exist in mathMLTree.js. 1076 * 1077 * TODO: refactor `span` and `anchor` into common superclass when 1078 * target environments support class inheritance 1079 */ 1080 1081/** 1082 * Create an HTML className based on a list of classes. In addition to joining 1083 * with spaces, we also remove empty classes. 1084 */ 1085const createClass = function createClass(classes) { 1086 return classes.filter(cls => cls).join(" "); 1087}; 1088 1089const initNode = function initNode(classes, options, style) { 1090 this.classes = classes || []; 1091 this.attributes = {}; 1092 this.height = 0; 1093 this.depth = 0; 1094 this.maxFontSize = 0; 1095 this.style = style || {}; 1096 1097 if (options) { 1098 if (options.style.isTight()) { 1099 this.classes.push("mtight"); 1100 } 1101 1102 const color = options.getColor(); 1103 1104 if (color) { 1105 this.style.color = color; 1106 } 1107 } 1108}; 1109/** 1110 * Convert into an HTML node 1111 */ 1112 1113 1114const toNode = function toNode(tagName) { 1115 const node = document.createElement(tagName); // Apply the class 1116 1117 node.className = createClass(this.classes); // Apply inline styles 1118 1119 for (const style in this.style) { 1120 if (this.style.hasOwnProperty(style)) { 1121 // $FlowFixMe Flow doesn't seem to understand span.style's type. 1122 node.style[style] = this.style[style]; 1123 } 1124 } // Apply attributes 1125 1126 1127 for (const attr in this.attributes) { 1128 if (this.attributes.hasOwnProperty(attr)) { 1129 node.setAttribute(attr, this.attributes[attr]); 1130 } 1131 } // Append the children, also as HTML nodes 1132 1133 1134 for (let i = 0; i < this.children.length; i++) { 1135 node.appendChild(this.children[i].toNode()); 1136 } 1137 1138 return node; 1139}; 1140/** 1141 * Convert into an HTML markup string 1142 */ 1143 1144 1145const toMarkup = function toMarkup(tagName) { 1146 let markup = `<${tagName}`; // Add the class 1147 1148 if (this.classes.length) { 1149 markup += ` class="${utils.escape(createClass(this.classes))}"`; 1150 } 1151 1152 let styles = ""; // Add the styles, after hyphenation 1153 1154 for (const style in this.style) { 1155 if (this.style.hasOwnProperty(style)) { 1156 styles += `${utils.hyphenate(style)}:${this.style[style]};`; 1157 } 1158 } 1159 1160 if (styles) { 1161 markup += ` style="${utils.escape(styles)}"`; 1162 } // Add the attributes 1163 1164 1165 for (const attr in this.attributes) { 1166 if (this.attributes.hasOwnProperty(attr)) { 1167 markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; 1168 } 1169 } 1170 1171 markup += ">"; // Add the markup of the children, also as markup 1172 1173 for (let i = 0; i < this.children.length; i++) { 1174 markup += this.children[i].toMarkup(); 1175 } 1176 1177 markup += `</${tagName}>`; 1178 return markup; 1179}; // Making the type below exact with all optional fields doesn't work due to 1180// - https://github.com/facebook/flow/issues/4582 1181// - https://github.com/facebook/flow/issues/5688 1182// However, since *all* fields are optional, $Shape<> works as suggested in 5688 1183// above. 1184// This type does not include all CSS properties. Additional properties should 1185// be added as needed. 1186 1187 1188/** 1189 * This node represents a span node, with a className, a list of children, and 1190 * an inline style. It also contains information about its height, depth, and 1191 * maxFontSize. 1192 * 1193 * Represents two types with different uses: SvgSpan to wrap an SVG and DomSpan 1194 * otherwise. This typesafety is important when HTML builders access a span's 1195 * children. 1196 */ 1197class Span { 1198 constructor(classes, children, options, style) { 1199 this.children = void 0; 1200 this.attributes = void 0; 1201 this.classes = void 0; 1202 this.height = void 0; 1203 this.depth = void 0; 1204 this.width = void 0; 1205 this.maxFontSize = void 0; 1206 this.style = void 0; 1207 initNode.call(this, classes, options, style); 1208 this.children = children || []; 1209 } 1210 /** 1211 * Sets an arbitrary attribute on the span. Warning: use this wisely. Not 1212 * all browsers support attributes the same, and having too many custom 1213 * attributes is probably bad. 1214 */ 1215 1216 1217 setAttribute(attribute, value) { 1218 this.attributes[attribute] = value; 1219 } 1220 1221 hasClass(className) { 1222 return utils.contains(this.classes, className); 1223 } 1224 1225 toNode() { 1226 return toNode.call(this, "span"); 1227 } 1228 1229 toMarkup() { 1230 return toMarkup.call(this, "span"); 1231 } 1232 1233} 1234/** 1235 * This node represents an anchor (<a>) element with a hyperlink. See `span` 1236 * for further details. 1237 */ 1238 1239class Anchor { 1240 constructor(href, classes, children, options) { 1241 this.children = void 0; 1242 this.attributes = void 0; 1243 this.classes = void 0; 1244 this.height = void 0; 1245 this.depth = void 0; 1246 this.maxFontSize = void 0; 1247 this.style = void 0; 1248 initNode.call(this, classes, options); 1249 this.children = children || []; 1250 this.setAttribute('href', href); 1251 } 1252 1253 setAttribute(attribute, value) { 1254 this.attributes[attribute] = value; 1255 } 1256 1257 hasClass(className) { 1258 return utils.contains(this.classes, className); 1259 } 1260 1261 toNode() { 1262 return toNode.call(this, "a"); 1263 } 1264 1265 toMarkup() { 1266 return toMarkup.call(this, "a"); 1267 } 1268 1269} 1270/** 1271 * This node represents an image embed (<img>) element. 1272 */ 1273 1274class Img { 1275 constructor(src, alt, style) { 1276 this.src = void 0; 1277 this.alt = void 0; 1278 this.classes = void 0; 1279 this.height = void 0; 1280 this.depth = void 0; 1281 this.maxFontSize = void 0; 1282 this.style = void 0; 1283 this.alt = alt; 1284 this.src = src; 1285 this.classes = ["mord"]; 1286 this.style = style; 1287 } 1288 1289 hasClass(className) { 1290 return utils.contains(this.classes, className); 1291 } 1292 1293 toNode() { 1294 const node = document.createElement("img"); 1295 node.src = this.src; 1296 node.alt = this.alt; 1297 node.className = "mord"; // Apply inline styles 1298 1299 for (const style in this.style) { 1300 if (this.style.hasOwnProperty(style)) { 1301 // $FlowFixMe 1302 node.style[style] = this.style[style]; 1303 } 1304 } 1305 1306 return node; 1307 } 1308 1309 toMarkup() { 1310 let markup = `<img src='${this.src} 'alt='${this.alt}' `; // Add the styles, after hyphenation 1311 1312 let styles = ""; 1313 1314 for (const style in this.style) { 1315 if (this.style.hasOwnProperty(style)) { 1316 styles += `${utils.hyphenate(style)}:${this.style[style]};`; 1317 } 1318 } 1319 1320 if (styles) { 1321 markup += ` style="${utils.escape(styles)}"`; 1322 } 1323 1324 markup += "'/>"; 1325 return markup; 1326 } 1327 1328} 1329const iCombinations = { 1330 'î': '\u0131\u0302', 1331 'ï': '\u0131\u0308', 1332 'í': '\u0131\u0301', 1333 // 'ī': '\u0131\u0304', // enable when we add Extended Latin 1334 'ì': '\u0131\u0300' 1335}; 1336/** 1337 * A symbol node contains information about a single symbol. It either renders 1338 * to a single text node, or a span with a single text node in it, depending on 1339 * whether it has CSS classes, styles, or needs italic correction. 1340 */ 1341 1342class SymbolNode { 1343 constructor(text, height, depth, italic, skew, width, classes, style) { 1344 this.text = void 0; 1345 this.height = void 0; 1346 this.depth = void 0; 1347 this.italic = void 0; 1348 this.skew = void 0; 1349 this.width = void 0; 1350 this.maxFontSize = void 0; 1351 this.classes = void 0; 1352 this.style = void 0; 1353 this.text = text; 1354 this.height = height || 0; 1355 this.depth = depth || 0; 1356 this.italic = italic || 0; 1357 this.skew = skew || 0; 1358 this.width = width || 0; 1359 this.classes = classes || []; 1360 this.style = style || {}; 1361 this.maxFontSize = 0; // Mark text from non-Latin scripts with specific classes so that we 1362 // can specify which fonts to use. This allows us to render these 1363 // characters with a serif font in situations where the browser would 1364 // either default to a sans serif or render a placeholder character. 1365 // We use CSS class names like cjk_fallback, hangul_fallback and 1366 // brahmic_fallback. See ./unicodeScripts.js for the set of possible 1367 // script names 1368 1369 const script = scriptFromCodepoint(this.text.charCodeAt(0)); 1370 1371 if (script) { 1372 this.classes.push(script + "_fallback"); 1373 } 1374 1375 if (/[îïíì]/.test(this.text)) { 1376 // add ī when we add Extended Latin 1377 this.text = iCombinations[this.text]; 1378 } 1379 } 1380 1381 hasClass(className) { 1382 return utils.contains(this.classes, className); 1383 } 1384 /** 1385 * Creates a text node or span from a symbol node. Note that a span is only 1386 * created if it is needed. 1387 */ 1388 1389 1390 toNode() { 1391 const node = document.createTextNode(this.text); 1392 let span = null; 1393 1394 if (this.italic > 0) { 1395 span = document.createElement("span"); 1396 span.style.marginRight = this.italic + "em"; 1397 } 1398 1399 if (this.classes.length > 0) { 1400 span = span || document.createElement("span"); 1401 span.className = createClass(this.classes); 1402 } 1403 1404 for (const style in this.style) { 1405 if (this.style.hasOwnProperty(style)) { 1406 span = span || document.createElement("span"); // $FlowFixMe Flow doesn't seem to understand span.style's type. 1407 1408 span.style[style] = this.style[style]; 1409 } 1410 } 1411 1412 if (span) { 1413 span.appendChild(node); 1414 return span; 1415 } else { 1416 return node; 1417 } 1418 } 1419 /** 1420 * Creates markup for a symbol node. 1421 */ 1422 1423 1424 toMarkup() { 1425 // TODO(alpert): More duplication than I'd like from 1426 // span.prototype.toMarkup and symbolNode.prototype.toNode... 1427 let needsSpan = false; 1428 let markup = "<span"; 1429 1430 if (this.classes.length) { 1431 needsSpan = true; 1432 markup += " class=\""; 1433 markup += utils.escape(createClass(this.classes)); 1434 markup += "\""; 1435 } 1436 1437 let styles = ""; 1438 1439 if (this.italic > 0) { 1440 styles += "margin-right:" + this.italic + "em;"; 1441 } 1442 1443 for (const style in this.style) { 1444 if (this.style.hasOwnProperty(style)) { 1445 styles += utils.hyphenate(style) + ":" + this.style[style] + ";"; 1446 } 1447 } 1448 1449 if (styles) { 1450 needsSpan = true; 1451 markup += " style=\"" + utils.escape(styles) + "\""; 1452 } 1453 1454 const escaped = utils.escape(this.text); 1455 1456 if (needsSpan) { 1457 markup += ">"; 1458 markup += escaped; 1459 markup += "</span>"; 1460 return markup; 1461 } else { 1462 return escaped; 1463 } 1464 } 1465 1466} 1467/** 1468 * SVG nodes are used to render stretchy wide elements. 1469 */ 1470 1471class SvgNode { 1472 constructor(children, attributes) { 1473 this.children = void 0; 1474 this.attributes = void 0; 1475 this.children = children || []; 1476 this.attributes = attributes || {}; 1477 } 1478 1479 toNode() { 1480 const svgNS = "http://www.w3.org/2000/svg"; 1481 const node = document.createElementNS(svgNS, "svg"); // Apply attributes 1482 1483 for (const attr in this.attributes) { 1484 if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { 1485 node.setAttribute(attr, this.attributes[attr]); 1486 } 1487 } 1488 1489 for (let i = 0; i < this.children.length; i++) { 1490 node.appendChild(this.children[i].toNode()); 1491 } 1492 1493 return node; 1494 } 1495 1496 toMarkup() { 1497 let markup = "<svg"; // Apply attributes 1498 1499 for (const attr in this.attributes) { 1500 if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { 1501 markup += ` ${attr}='${this.attributes[attr]}'`; 1502 } 1503 } 1504 1505 markup += ">"; 1506 1507 for (let i = 0; i < this.children.length; i++) { 1508 markup += this.children[i].toMarkup(); 1509 } 1510 1511 markup += "</svg>"; 1512 return markup; 1513 } 1514 1515} 1516class PathNode { 1517 constructor(pathName, alternate) { 1518 this.pathName = void 0; 1519 this.alternate = void 0; 1520 this.pathName = pathName; 1521 this.alternate = alternate; // Used only for \sqrt 1522 } 1523 1524 toNode() { 1525 const svgNS = "http://www.w3.org/2000/svg"; 1526 const node = document.createElementNS(svgNS, "path"); 1527 1528 if (this.alternate) { 1529 node.setAttribute("d", this.alternate); 1530 } else { 1531 node.setAttribute("d", path[this.pathName]); 1532 } 1533 1534 return node; 1535 } 1536 1537 toMarkup() { 1538 if (this.alternate) { 1539 return `<path d='${this.alternate}'/>`; 1540 } else { 1541 return `<path d='${path[this.pathName]}'/>`; 1542 } 1543 } 1544 1545} 1546class LineNode { 1547 constructor(attributes) { 1548 this.attributes = void 0; 1549 this.attributes = attributes || {}; 1550 } 1551 1552 toNode() { 1553 const svgNS = "http://www.w3.org/2000/svg"; 1554 const node = document.createElementNS(svgNS, "line"); // Apply attributes 1555 1556 for (const attr in this.attributes) { 1557 if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { 1558 node.setAttribute(attr, this.attributes[attr]); 1559 } 1560 } 1561 1562 return node; 1563 } 1564 1565 toMarkup() { 1566 let markup = "<line"; 1567 1568 for (const attr in this.attributes) { 1569 if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { 1570 markup += ` ${attr}='${this.attributes[attr]}'`; 1571 } 1572 } 1573 1574 markup += "/>"; 1575 return markup; 1576 } 1577 1578} 1579function assertSymbolDomNode(group) { 1580 if (group instanceof SymbolNode) { 1581 return group; 1582 } else { 1583 throw new Error(`Expected symbolNode but got ${String(group)}.`); 1584 } 1585} 1586function assertSpan(group) { 1587 if (group instanceof Span) { 1588 return group; 1589 } else { 1590 throw new Error(`Expected span<HtmlDomNode> but got ${String(group)}.`); 1591 } 1592} 1593 1594// This file is GENERATED by buildMetrics.sh. DO NOT MODIFY. 1595var metricMap = { 1596 "AMS-Regular": { 1597 "65": [0, 0.68889, 0, 0, 0.72222], 1598 "66": [0, 0.68889, 0, 0, 0.66667], 1599 "67": [0, 0.68889, 0, 0, 0.72222], 1600 "68": [0, 0.68889, 0, 0, 0.72222], 1601 "69": [0, 0.68889, 0, 0, 0.66667], 1602 "70": [0, 0.68889, 0, 0, 0.61111], 1603 "71": [0, 0.68889, 0, 0, 0.77778], 1604 "72": [0, 0.68889, 0, 0, 0.77778], 1605 "73": [0, 0.68889, 0, 0, 0.38889], 1606 "74": [0.16667, 0.68889, 0, 0, 0.5], 1607 "75": [0, 0.68889, 0, 0, 0.77778], 1608 "76": [0, 0.68889, 0, 0, 0.66667], 1609 "77": [0, 0.68889, 0, 0, 0.94445], 1610 "78": [0, 0.68889, 0, 0, 0.72222], 1611 "79": [0.16667, 0.68889, 0, 0, 0.77778], 1612 "80": [0, 0.68889, 0, 0, 0.61111], 1613 "81": [0.16667, 0.68889, 0, 0, 0.77778], 1614 "82": [0, 0.68889, 0, 0, 0.72222], 1615 "83": [0, 0.68889, 0, 0, 0.55556], 1616 "84": [0, 0.68889, 0, 0, 0.66667], 1617 "85": [0, 0.68889, 0, 0, 0.72222], 1618 "86": [0, 0.68889, 0, 0, 0.72222], 1619 "87": [0, 0.68889, 0, 0, 1.0], 1620 "88": [0, 0.68889, 0, 0, 0.72222], 1621 "89": [0, 0.68889, 0, 0, 0.72222], 1622 "90": [0, 0.68889, 0, 0, 0.66667], 1623 "107": [0, 0.68889, 0, 0, 0.55556], 1624 "165": [0, 0.675, 0.025, 0, 0.75], 1625 "174": [0.15559, 0.69224, 0, 0, 0.94666], 1626 "240": [0, 0.68889, 0, 0, 0.55556], 1627 "295": [0, 0.68889, 0, 0, 0.54028], 1628 "710": [0, 0.825, 0, 0, 2.33334], 1629 "732": [0, 0.9, 0, 0, 2.33334], 1630 "770": [0, 0.825, 0, 0, 2.33334], 1631 "771": [0, 0.9, 0, 0, 2.33334], 1632 "989": [0.08167, 0.58167, 0, 0, 0.77778], 1633 "1008": [0, 0.43056, 0.04028, 0, 0.66667], 1634 "8245": [0, 0.54986, 0, 0, 0.275], 1635 "8463": [0, 0.68889, 0, 0, 0.54028], 1636 "8487": [0, 0.68889, 0, 0, 0.72222], 1637 "8498": [0, 0.68889, 0, 0, 0.55556], 1638 "8502": [0, 0.68889, 0, 0, 0.66667], 1639 "8503": [0, 0.68889, 0, 0, 0.44445], 1640 "8504": [0, 0.68889, 0, 0, 0.66667], 1641 "8513": [0, 0.68889, 0, 0, 0.63889], 1642 "8592": [-0.03598, 0.46402, 0, 0, 0.5], 1643 "8594": [-0.03598, 0.46402, 0, 0, 0.5], 1644 "8602": [-0.13313, 0.36687, 0, 0, 1.0], 1645 "8603": [-0.13313, 0.36687, 0, 0, 1.0], 1646 "8606": [0.01354, 0.52239, 0, 0, 1.0], 1647 "8608": [0.01354, 0.52239, 0, 0, 1.0], 1648 "8610": [0.01354, 0.52239, 0, 0, 1.11111], 1649 "8611": [0.01354, 0.52239, 0, 0, 1.11111], 1650 "8619": [0, 0.54986, 0, 0, 1.0], 1651 "8620": [0, 0.54986, 0, 0, 1.0], 1652 "8621": [-0.13313, 0.37788, 0, 0, 1.38889], 1653 "8622": [-0.13313, 0.36687, 0, 0, 1.0], 1654 "8624": [0, 0.69224, 0, 0, 0.5], 1655 "8625": [0, 0.69224, 0, 0, 0.5], 1656 "8630": [0, 0.43056, 0, 0, 1.0], 1657 "8631": [0, 0.43056, 0, 0, 1.0], 1658 "8634": [0.08198, 0.58198, 0, 0, 0.77778], 1659 "8635": [0.08198, 0.58198, 0, 0, 0.77778], 1660 "8638": [0.19444, 0.69224, 0, 0, 0.41667], 1661 "8639": [0.19444, 0.69224, 0, 0, 0.41667], 1662 "8642": [0.19444, 0.69224, 0, 0, 0.41667], 1663 "8643": [0.19444, 0.69224, 0, 0, 0.41667], 1664 "8644": [0.1808, 0.675, 0, 0, 1.0], 1665 "8646": [0.1808, 0.675, 0, 0, 1.0], 1666 "8647": [0.1808, 0.675, 0, 0, 1.0], 1667 "8648": [0.19444, 0.69224, 0, 0, 0.83334], 1668 "8649": [0.1808, 0.675, 0, 0, 1.0], 1669 "8650": [0.19444, 0.69224, 0, 0, 0.83334], 1670 "8651": [0.01354, 0.52239, 0, 0, 1.0], 1671 "8652": [0.01354, 0.52239, 0, 0, 1.0], 1672 "8653": [-0.13313, 0.36687, 0, 0, 1.0], 1673 "8654": [-0.13313, 0.36687, 0, 0, 1.0], 1674 "8655": [-0.13313, 0.36687, 0, 0, 1.0], 1675 "8666": [0.13667, 0.63667, 0, 0, 1.0], 1676 "8667": [0.13667, 0.63667, 0, 0, 1.0], 1677 "8669": [-0.13313, 0.37788, 0, 0, 1.0], 1678 "8672": [-0.064, 0.437, 0, 0, 1.334], 1679 "8674": [-0.064, 0.437, 0, 0, 1.334], 1680 "8705": [0, 0.825, 0, 0, 0.5], 1681 "8708": [0, 0.68889, 0, 0, 0.55556], 1682 "8709": [0.08167, 0.58167, 0, 0, 0.77778], 1683 "8717": [0, 0.43056, 0, 0, 0.42917], 1684 "8722": [-0.03598, 0.46402, 0, 0, 0.5], 1685 "8724": [0.08198, 0.69224, 0, 0, 0.77778], 1686 "8726": [0.08167, 0.58167, 0, 0, 0.77778], 1687 "8733": [0, 0.69224, 0, 0, 0.77778], 1688 "8736": [0, 0.69224, 0, 0, 0.72222], 1689 "8737": [0, 0.69224, 0, 0, 0.72222], 1690 "8738": [0.03517, 0.52239, 0, 0, 0.72222], 1691 "8739": [0.08167, 0.58167, 0, 0, 0.22222], 1692 "8740": [0.25142, 0.74111, 0, 0, 0.27778], 1693 "8741": [0.08167, 0.58167, 0, 0, 0.38889], 1694 "8742": [0.25142, 0.74111, 0, 0, 0.5], 1695 "8756": [0, 0.69224, 0, 0, 0.66667], 1696 "8757": [0, 0.69224, 0, 0, 0.66667], 1697 "8764": [-0.13313, 0.36687, 0, 0, 0.77778], 1698 "8765": [-0.13313, 0.37788, 0, 0, 0.77778], 1699 "8769": [-0.13313, 0.36687, 0, 0, 0.77778], 1700 "8770": [-0.03625, 0.46375, 0, 0, 0.77778], 1701 "8774": [0.30274, 0.79383, 0, 0, 0.77778], 1702 "8776": [-0.01688, 0.48312, 0, 0, 0.77778], 1703 "8778": [0.08167, 0.58167, 0, 0, 0.77778], 1704 "8782": [0.06062, 0.54986, 0, 0, 0.77778], 1705 "8783": [0.06062, 0.54986, 0, 0, 0.77778], 1706 "8785": [0.08198, 0.58198, 0, 0, 0.77778], 1707 "8786": [0.08198, 0.58198, 0, 0, 0.77778], 1708 "8787": [0.08198, 0.58198, 0, 0, 0.77778], 1709 "8790": [0, 0.69224, 0, 0, 0.77778], 1710 "8791": [0.22958, 0.72958, 0, 0, 0.77778], 1711 "8796": [0.08198, 0.91667, 0, 0, 0.77778], 1712 "8806": [0.25583, 0.75583, 0, 0, 0.77778], 1713 "8807": [0.25583, 0.75583, 0, 0, 0.77778], 1714 "8808": [0.25142, 0.75726, 0, 0, 0.77778], 1715 "8809": [0.25142, 0.75726, 0, 0, 0.77778], 1716 "8812": [0.25583, 0.75583, 0, 0, 0.5], 1717 "8814": [0.20576, 0.70576, 0, 0, 0.77778], 1718 "8815": [0.20576, 0.70576, 0, 0, 0.77778], 1719 "8816": [0.30274, 0.79383, 0, 0, 0.77778], 1720 "8817": [0.30274, 0.79383, 0, 0, 0.77778], 1721 "8818": [0.22958, 0.72958, 0, 0, 0.77778], 1722 "8819": [0.22958, 0.72958, 0, 0, 0.77778], 1723 "8822": [0.1808, 0.675, 0, 0, 0.77778], 1724 "8823": [0.1808, 0.675, 0, 0, 0.77778], 1725 "8828": [0.13667, 0.63667, 0, 0, 0.77778], 1726 "8829": [0.13667, 0.63667, 0, 0, 0.77778], 1727 "8830": [0.22958, 0.72958, 0, 0, 0.77778], 1728 "8831": [0.22958, 0.72958, 0, 0, 0.77778], 1729 "8832": [0.20576, 0.70576, 0, 0, 0.77778], 1730 "8833": [0.20576, 0.70576, 0, 0, 0.77778], 1731 "8840": [0.30274, 0.79383, 0, 0, 0.77778], 1732 "8841": [0.30274, 0.79383, 0, 0, 0.77778], 1733 "8842": [0.13597, 0.63597, 0, 0, 0.77778], 1734 "8843": [0.13597, 0.63597, 0, 0, 0.77778], 1735 "8847": [0.03517, 0.54986, 0, 0, 0.77778], 1736 "8848": [0.03517, 0.54986, 0, 0, 0.77778], 1737 "8858": [0.08198, 0.58198, 0, 0, 0.77778], 1738 "8859": [0.08198, 0.58198, 0, 0, 0.77778], 1739 "8861": [0.08198, 0.58198, 0, 0, 0.77778], 1740 "8862": [0, 0.675, 0, 0, 0.77778], 1741 "8863": [0, 0.675, 0, 0, 0.77778], 1742 "8864": [0, 0.675, 0, 0, 0.77778], 1743 "8865": [0, 0.675, 0, 0, 0.77778], 1744 "8872": [0, 0.69224, 0, 0, 0.61111], 1745 "8873": [0, 0.69224, 0, 0, 0.72222], 1746 "8874": [0, 0.69224, 0, 0, 0.88889], 1747 "8876": [0, 0.68889, 0, 0, 0.61111], 1748 "8877": [0, 0.68889, 0, 0, 0.61111], 1749 "8878": [0, 0.68889, 0, 0, 0.72222], 1750 "8879": [0, 0.68889, 0, 0, 0.72222], 1751 "8882": [0.03517, 0.54986, 0, 0, 0.77778], 1752 "8883": [0.03517, 0.54986, 0, 0, 0.77778], 1753 "8884": [0.13667, 0.63667, 0, 0, 0.77778], 1754 "8885": [0.13667, 0.63667, 0, 0, 0.77778], 1755 "8888": [0, 0.54986, 0, 0, 1.11111], 1756 "8890": [0.19444, 0.43056, 0, 0, 0.55556], 1757 "8891": [0.19444, 0.69224, 0, 0, 0.61111], 1758 "8892": [0.19444, 0.69224, 0, 0, 0.61111], 1759 "8901": [0, 0.54986, 0, 0, 0.27778], 1760 "8903": [0.08167, 0.58167, 0, 0, 0.77778], 1761 "8905": [0.08167, 0.58167, 0, 0, 0.77778], 1762 "8906": [0.08167, 0.58167, 0, 0, 0.77778], 1763 "8907": [0, 0.69224, 0, 0, 0.77778], 1764 "8908": [0, 0.69224, 0, 0, 0.77778], 1765 "8909": [-0.03598, 0.46402, 0, 0, 0.77778], 1766 "8910": [0, 0.54986, 0, 0, 0.76042], 1767 "8911": [0, 0.54986, 0, 0, 0.76042], 1768 "8912": [0.03517, 0.54986, 0, 0, 0.77778], 1769 "8913": [0.03517, 0.54986, 0, 0, 0.77778], 1770 "8914": [0, 0.54986, 0, 0, 0.66667], 1771 "8915": [0, 0.54986, 0, 0, 0.66667], 1772 "8916": [0, 0.69224, 0, 0, 0.66667], 1773 "8918": [0.0391, 0.5391, 0, 0, 0.77778], 1774 "8919": [0.0391, 0.5391, 0, 0, 0.77778], 1775 "8920": [0.03517, 0.54986, 0, 0, 1.33334], 1776 "8921": [0.03517, 0.54986, 0, 0, 1.33334], 1777 "8922": [0.38569, 0.88569, 0, 0, 0.77778], 1778 "8923": [0.38569, 0.88569, 0, 0, 0.77778], 1779 "8926": [0.13667, 0.63667, 0, 0, 0.77778], 1780 "8927": [0.13667, 0.63667, 0, 0, 0.77778], 1781 "8928": [0.30274, 0.79383, 0, 0, 0.77778], 1782 "8929": [0.30274, 0.79383, 0, 0, 0.77778], 1783 "8934": [0.23222, 0.74111, 0, 0, 0.77778], 1784 "8935": [0.23222, 0.74111, 0, 0, 0.77778], 1785 "8936": [0.23222, 0.74111, 0, 0, 0.77778], 1786 "8937": [0.23222, 0.74111, 0, 0, 0.77778], 1787 "8938": [0.20576, 0.70576, 0, 0, 0.77778], 1788 "8939": [0.20576, 0.70576, 0, 0, 0.77778], 1789 "8940": [0.30274, 0.79383, 0, 0, 0.77778], 1790 "8941": [0.30274, 0.79383, 0, 0, 0.77778], 1791 "8994": [0.19444, 0.69224, 0, 0, 0.77778], 1792 "8995": [0.19444, 0.69224, 0, 0, 0.77778], 1793 "9416": [0.15559, 0.69224, 0, 0, 0.90222], 1794 "9484": [0, 0.69224, 0, 0, 0.5], 1795 "9488": [0, 0.69224, 0, 0, 0.5], 1796 "9492": [0, 0.37788, 0, 0, 0.5], 1797 "9496": [0, 0.37788, 0, 0, 0.5], 1798 "9585": [0.19444, 0.68889, 0, 0, 0.88889], 1799 "9586": [0.19444, 0.74111, 0, 0, 0.88889], 1800 "9632": [0, 0.675, 0, 0, 0.77778], 1801 "9633": [0, 0.675, 0, 0, 0.77778], 1802 "9650": [0, 0.54986, 0, 0, 0.72222], 1803 "9651": [0, 0.54986, 0, 0, 0.72222], 1804 "9654": [0.03517, 0.54986, 0, 0, 0.77778], 1805 "9660": [0, 0.54986, 0, 0, 0.72222], 1806 "9661": [0, 0.54986, 0, 0, 0.72222], 1807 "9664": [0.03517, 0.54986, 0, 0, 0.77778], 1808 "9674": [0.11111, 0.69224, 0, 0, 0.66667], 1809 "9733": [0.19444, 0.69224, 0, 0, 0.94445], 1810 "10003": [0, 0.69224, 0, 0, 0.83334], 1811 "10016": [0, 0.69224, 0, 0, 0.83334], 1812 "10731": [0.11111, 0.69224, 0, 0, 0.66667], 1813 "10846": [0.19444, 0.75583, 0, 0, 0.61111], 1814 "10877": [0.13667, 0.63667, 0, 0, 0.77778], 1815 "10878": [0.13667, 0.63667, 0, 0, 0.77778], 1816 "10885": [0.25583, 0.75583, 0, 0, 0.77778], 1817 "10886": [0.25583, 0.75583, 0, 0, 0.77778], 1818 "10887": [0.13597, 0.63597, 0, 0, 0.77778], 1819 "10888": [0.13597, 0.63597, 0, 0, 0.77778], 1820 "10889": [0.26167, 0.75726, 0, 0, 0.77778], 1821 "10890": [0.26167, 0.75726, 0, 0, 0.77778], 1822 "10891": [0.48256, 0.98256, 0, 0, 0.77778], 1823 "10892": [0.48256, 0.98256, 0, 0, 0.77778], 1824 "10901": [0.13667, 0.63667, 0, 0, 0.77778], 1825 "10902": [0.13667, 0.63667, 0, 0, 0.77778], 1826 "10933": [0.25142, 0.75726, 0, 0, 0.77778], 1827 "10934": [0.25142, 0.75726, 0, 0, 0.77778], 1828 "10935": [0.26167, 0.75726, 0, 0, 0.77778], 1829 "10936": [0.26167, 0.75726, 0, 0, 0.77778], 1830 "10937": [0.26167, 0.75726, 0, 0, 0.77778], 1831 "10938": [0.26167, 0.75726, 0, 0, 0.77778], 1832 "10949": [0.25583, 0.75583, 0, 0, 0.77778], 1833 "10950": [0.25583, 0.75583, 0, 0, 0.77778], 1834 "10955": [0.28481, 0.79383, 0, 0, 0.77778], 1835 "10956": [0.28481, 0.79383, 0, 0, 0.77778], 1836 "57350": [0.08167, 0.58167, 0, 0, 0.22222], 1837 "57351": [0.08167, 0.58167, 0, 0, 0.38889], 1838 "57352": [0.08167, 0.58167, 0, 0, 0.77778], 1839 "57353": [0, 0.43056, 0.04028, 0, 0.66667], 1840 "57356": [0.25142, 0.75726, 0, 0, 0.77778], 1841 "57357": [0.25142, 0.75726, 0, 0, 0.77778], 1842 "57358": [0.41951, 0.91951, 0, 0, 0.77778], 1843 "57359": [0.30274, 0.79383, 0, 0, 0.77778], 1844 "57360": [0.30274, 0.79383, 0, 0, 0.77778], 1845 "57361": [0.41951, 0.91951, 0, 0, 0.77778], 1846 "57366": [0.25142, 0.75726, 0, 0, 0.77778], 1847 "57367": [0.25142, 0.75726, 0, 0, 0.77778], 1848 "57368": [0.25142, 0.75726, 0, 0, 0.77778], 1849 "57369": [0.25142, 0.75726, 0, 0, 0.77778], 1850 "57370": [0.13597, 0.63597, 0, 0, 0.77778], 1851 "57371": [0.13597, 0.63597, 0, 0, 0.77778] 1852 }, 1853 "Caligraphic-Regular": { 1854 "48": [0, 0.43056, 0, 0, 0.5], 1855 "49": [0, 0.43056, 0, 0, 0.5], 1856 "50": [0, 0.43056, 0, 0, 0.5], 1857 "51": [0.19444, 0.43056, 0, 0, 0.5], 1858 "52": [0.19444, 0.43056, 0, 0, 0.5], 1859 "53": [0.19444, 0.43056, 0, 0, 0.5], 1860 "54": [0, 0.64444, 0, 0, 0.5], 1861 "55": [0.19444, 0.43056, 0, 0, 0.5], 1862 "56": [0, 0.64444, 0, 0, 0.5], 1863 "57": [0.19444, 0.43056, 0, 0, 0.5], 1864 "65": [0, 0.68333, 0, 0.19445, 0.79847], 1865 "66": [0, 0.68333, 0.03041, 0.13889, 0.65681], 1866 "67": [0, 0.68333, 0.05834, 0.13889, 0.52653], 1867 "68": [0, 0.68333, 0.02778, 0.08334, 0.77139], 1868 "69": [0, 0.68333, 0.08944, 0.11111, 0.52778], 1869 "70": [0, 0.68333, 0.09931, 0.11111, 0.71875], 1870 "71": [0.09722, 0.68333, 0.0593, 0.11111, 0.59487], 1871 "72": [0, 0.68333, 0.00965, 0.11111, 0.84452], 1872 "73": [0, 0.68333, 0.07382, 0, 0.54452], 1873 "74": [0.09722, 0.68333, 0.18472, 0.16667, 0.67778], 1874 "75": [0, 0.68333, 0.01445, 0.05556, 0.76195], 1875 "76": [0, 0.68333, 0, 0.13889, 0.68972], 1876 "77": [0, 0.68333, 0, 0.13889, 1.2009], 1877 "78": [0, 0.68333, 0.14736, 0.08334, 0.82049], 1878 "79": [0, 0.68333, 0.02778, 0.11111, 0.79611], 1879 "80": [0, 0.68333, 0.08222, 0.08334, 0.69556], 1880 "81": [0.09722, 0.68333, 0, 0.11111, 0.81667], 1881 "82": [0, 0.68333, 0, 0.08334, 0.8475], 1882 "83": [0, 0.68333, 0.075, 0.13889, 0.60556], 1883 "84": [0, 0.68333, 0.25417, 0, 0.54464], 1884 "85": [0, 0.68333, 0.09931, 0.08334, 0.62583], 1885 "86": [0, 0.68333, 0.08222, 0, 0.61278], 1886 "87": [0, 0.68333, 0.08222, 0.08334, 0.98778], 1887 "88": [0, 0.68333, 0.14643, 0.13889, 0.7133], 1888 "89": [0.09722, 0.68333, 0.08222, 0.08334, 0.66834], 1889 "90": [0, 0.68333, 0.07944, 0.13889, 0.72473] 1890 }, 1891 "Fraktur-Regular": { 1892 "33": [0, 0.69141, 0, 0, 0.29574], 1893 "34": [0, 0.69141, 0, 0, 0.21471], 1894 "38": [0, 0.69141, 0, 0, 0.73786], 1895 "39": [0, 0.69141, 0, 0, 0.21201], 1896 "40": [0.24982, 0.74947, 0, 0, 0.38865], 1897 "41": [0.24982, 0.74947, 0, 0, 0.38865], 1898 "42": [0, 0.62119, 0, 0, 0.27764], 1899 "43": [0.08319, 0.58283, 0, 0, 0.75623], 1900 "44": [0, 0.10803, 0, 0, 0.27764], 1901 "45": [0.08319, 0.58283, 0, 0, 0.75623], 1902 "46": [0, 0.10803, 0, 0, 0.27764], 1903 "47": [0.24982, 0.74947, 0, 0, 0.50181], 1904 "48": [0, 0.47534, 0, 0, 0.50181], 1905 "49": [0, 0.47534, 0, 0, 0.50181], 1906 "50": [0, 0.47534, 0, 0, 0.50181], 1907 "51": [0.18906, 0.47534, 0, 0, 0.50181], 1908 "52": [0.18906, 0.47534, 0, 0, 0.50181], 1909 "53": [0.18906, 0.47534, 0, 0, 0.50181], 1910 "54": [0, 0.69141, 0, 0, 0.50181], 1911 "55": [0.18906, 0.47534, 0, 0, 0.50181], 1912 "56": [0, 0.69141, 0, 0, 0.50181], 1913 "57": [0.18906, 0.47534, 0, 0, 0.50181], 1914 "58": [0, 0.47534, 0, 0, 0.21606], 1915 "59": [0.12604, 0.47534, 0, 0, 0.21606], 1916 "61": [-0.13099, 0.36866, 0, 0, 0.75623], 1917 "63": [0, 0.69141, 0, 0, 0.36245], 1918 "65": [0, 0.69141, 0, 0, 0.7176], 1919 "66": [0, 0.69141, 0, 0, 0.88397], 1920 "67": [0, 0.69141, 0, 0, 0.61254], 1921 "68": [0, 0.69141, 0, 0, 0.83158], 1922 "69": [0, 0.69141, 0, 0, 0.66278], 1923 "70": [0.12604, 0.69141, 0, 0, 0.61119], 1924 "71": [0, 0.69141, 0, 0, 0.78539], 1925 "72": [0.06302, 0.69141, 0, 0, 0.7203], 1926 "73": [0, 0.69141, 0, 0, 0.55448], 1927 "74": [0.12604, 0.69141, 0, 0, 0.55231], 1928 "75": [0, 0.69141, 0, 0, 0.66845], 1929 "76": [0, 0.69141, 0, 0, 0.66602], 1930 "77": [0, 0.69141, 0, 0, 1.04953], 1931 "78": [0, 0.69141, 0, 0, 0.83212], 1932 "79": [0, 0.69141, 0, 0, 0.82699], 1933 "80": [0.18906, 0.69141, 0, 0, 0.82753], 1934 "81": [0.03781, 0.69141, 0, 0, 0.82699], 1935 "82": [0, 0.69141, 0, 0, 0.82807], 1936 "83": [0, 0.69141, 0, 0, 0.82861], 1937 "84": [0, 0.69141, 0, 0, 0.66899], 1938 "85": [0, 0.69141, 0, 0, 0.64576], 1939 "86": [0, 0.69141, 0, 0, 0.83131], 1940 "87": [0, 0.69141, 0, 0, 1.04602], 1941 "88": [0, 0.69141, 0, 0, 0.71922], 1942 "89": [0.18906, 0.69141, 0, 0, 0.83293], 1943 "90": [0.12604, 0.69141, 0, 0, 0.60201], 1944 "91": [0.24982, 0.74947, 0, 0, 0.27764], 1945 "93": [0.24982, 0.74947, 0, 0, 0.27764], 1946 "94": [0, 0.69141, 0, 0, 0.49965], 1947 "97": [0, 0.47534, 0, 0, 0.50046], 1948 "98": [0, 0.69141, 0, 0, 0.51315], 1949 "99": [0, 0.47534, 0, 0, 0.38946], 1950 "100": [0, 0.62119, 0, 0, 0.49857], 1951 "101": [0, 0.47534, 0, 0, 0.40053], 1952 "102": [0.18906, 0.69141, 0, 0, 0.32626], 1953 "103": [0.18906, 0.47534, 0, 0, 0.5037], 1954 "104": [0.18906, 0.69141, 0, 0, 0.52126], 1955 "105": [0, 0.69141, 0, 0, 0.27899], 1956 "106": [0, 0.69141, 0, 0, 0.28088], 1957 "107": [0, 0.69141, 0, 0, 0.38946], 1958 "108": [0, 0.69141, 0, 0, 0.27953], 1959 "109": [0, 0.47534, 0, 0, 0.76676], 1960 "110": [0, 0.47534, 0, 0, 0.52666], 1961 "111": [0, 0.47534, 0, 0, 0.48885], 1962 "112": [0.18906, 0.52396, 0, 0, 0.50046], 1963 "113": [0.18906, 0.47534, 0, 0, 0.48912], 1964 "114": [0, 0.47534, 0, 0, 0.38919], 1965 "115": [0, 0.47534, 0, 0, 0.44266], 1966 "116": [0, 0.62119, 0, 0, 0.33301], 1967 "117": [0, 0.47534, 0, 0, 0.5172], 1968 "118": [0, 0.52396, 0, 0, 0.5118], 1969 "119": [0, 0.52396, 0, 0, 0.77351], 1970 "120": [0.18906, 0.47534, 0, 0, 0.38865], 1971 "121": [0.18906, 0.47534, 0, 0, 0.49884], 1972 "122": [0.18906, 0.47534, 0, 0, 0.39054], 1973 "8216": [0, 0.69141, 0, 0, 0.21471], 1974 "8217": [0, 0.69141, 0, 0, 0.21471], 1975 "58112": [0, 0.62119, 0, 0, 0.49749], 1976 "58113": [0, 0.62119, 0, 0, 0.4983], 1977 "58114": [0.18906, 0.69141, 0, 0, 0.33328], 1978 "58115": [0.18906, 0.69141, 0, 0, 0.32923], 1979 "58116": [0.18906, 0.47534, 0, 0, 0.50343], 1980 "58117": [0, 0.69141, 0, 0, 0.33301], 1981 "58118": [0, 0.62119, 0, 0, 0.33409], 1982 "58119": [0, 0.47534, 0, 0, 0.50073] 1983 }, 1984 "Main-Bold": { 1985 "33": [0, 0.69444, 0, 0, 0.35], 1986 "34": [0, 0.69444, 0, 0, 0.60278], 1987 "35": [0.19444, 0.69444, 0, 0, 0.95833], 1988 "36": [0.05556, 0.75, 0, 0, 0.575], 1989 "37": [0.05556, 0.75, 0, 0, 0.95833], 1990 "38": [0, 0.69444, 0, 0, 0.89444], 1991 "39": [0, 0.69444, 0, 0, 0.31944], 1992 "40": [0.25, 0.75, 0, 0, 0.44722], 1993 "41": [0.25, 0.75, 0, 0, 0.44722], 1994 "42": [0, 0.75, 0, 0, 0.575], 1995 "43": [0.13333, 0.63333, 0, 0, 0.89444], 1996 "44": [0.19444, 0.15556, 0, 0, 0.31944], 1997 "45": [0, 0.44444, 0, 0, 0.38333], 1998 "46": [0, 0.15556, 0, 0, 0.31944], 1999 "47": [0.25, 0.75, 0, 0, 0.575], 2000 "48": [0, 0.64444, 0, 0, 0.575], 2001 "49": [0, 0.64444, 0, 0, 0.575], 2002 "50": [0, 0.64444, 0, 0, 0.575], 2003 "51": [0, 0.64444, 0, 0, 0.575], 2004 "52": [0, 0.64444, 0, 0, 0.575], 2005 "53": [0, 0.64444, 0, 0, 0.575], 2006 "54": [0, 0.64444, 0, 0, 0.575], 2007 "55": [0, 0.64444, 0, 0, 0.575], 2008 "56": [0, 0.64444, 0, 0, 0.575], 2009 "57": [0, 0.64444, 0, 0, 0.575], 2010 "58": [0, 0.44444, 0, 0, 0.31944], 2011 "59": [0.19444, 0.44444, 0, 0, 0.31944], 2012 "60": [0.08556, 0.58556, 0, 0, 0.89444], 2013 "61": [-0.10889, 0.39111, 0, 0, 0.89444], 2014 "62": [0.08556, 0.58556, 0, 0, 0.89444], 2015 "63": [0, 0.69444, 0, 0, 0.54305], 2016 "64": [0, 0.69444, 0, 0, 0.89444], 2017 "65": [0, 0.68611, 0, 0, 0.86944], 2018 "66": [0, 0.68611, 0, 0, 0.81805], 2019 "67": [0, 0.68611, 0, 0, 0.83055], 2020 "68": [0, 0.68611, 0, 0, 0.88194], 2021 "69": [0, 0.68611, 0, 0, 0.75555], 2022 "70": [0, 0.68611, 0, 0, 0.72361], 2023 "71": [0, 0.68611, 0, 0, 0.90416], 2024 "72": [0, 0.68611, 0, 0, 0.9], 2025 "73": [0, 0.68611, 0, 0, 0.43611], 2026 "74": [0, 0.68611, 0, 0, 0.59444], 2027 "75": [0, 0.68611, 0, 0, 0.90138], 2028 "76": [0, 0.68611, 0, 0, 0.69166], 2029 "77": [0, 0.68611, 0, 0, 1.09166], 2030 "78": [0, 0.68611, 0, 0, 0.9], 2031 "79": [0, 0.68611, 0, 0, 0.86388], 2032 "80": [0, 0.68611, 0, 0, 0.78611], 2033 "81": [0.19444, 0.68611, 0, 0, 0.86388], 2034 "82": [0, 0.68611, 0, 0, 0.8625], 2035 "83": [0, 0.68611, 0, 0, 0.63889], 2036 "84": [0, 0.68611, 0, 0, 0.8], 2037 "85": [0, 0.68611, 0, 0, 0.88472], 2038 "86": [0, 0.68611, 0.01597, 0, 0.86944], 2039 "87": [0, 0.68611, 0.01597, 0, 1.18888], 2040 "88": [0, 0.68611, 0, 0, 0.86944], 2041 "89": [0, 0.68611, 0.02875, 0, 0.86944], 2042 "90": [0, 0.68611, 0, 0, 0.70277], 2043 "91": [0.25, 0.75, 0, 0, 0.31944], 2044 "92": [0.25, 0.75, 0, 0, 0.575], 2045 "93": [0.25, 0.75, 0, 0, 0.31944], 2046 "94": [0, 0.69444, 0, 0, 0.575], 2047 "95": [0.31, 0.13444, 0.03194, 0, 0.575], 2048 "97": [0, 0.44444, 0, 0, 0.55902], 2049 "98": [0, 0.69444, 0, 0, 0.63889], 2050 "99": [0, 0.44444, 0, 0, 0.51111], 2051 "100": [0, 0.69444, 0, 0, 0.63889], 2052 "101": [0, 0.44444, 0, 0, 0.52708], 2053 "102": [0, 0.69444, 0.10903, 0, 0.35139], 2054 "103": [0.19444, 0.44444, 0.01597, 0, 0.575], 2055 "104": [0, 0.69444, 0, 0, 0.63889], 2056 "105": [0, 0.69444, 0, 0, 0.31944], 2057 "106": [0.19444, 0.69444, 0, 0, 0.35139], 2058 "107": [0, 0.69444, 0, 0, 0.60694], 2059 "108": [0, 0.69444, 0, 0, 0.31944], 2060 "109": [0, 0.44444, 0, 0, 0.95833], 2061 "110": [0, 0.44444, 0, 0, 0.63889], 2062 "111": [0, 0.44444, 0, 0, 0.575], 2063 "112": [0.19444, 0.44444, 0, 0, 0.63889], 2064 "113": [0.19444, 0.44444, 0, 0, 0.60694], 2065 "114": [0, 0.44444, 0, 0, 0.47361], 2066 "115": [0, 0.44444, 0, 0, 0.45361], 2067 "116": [0, 0.63492, 0, 0, 0.44722], 2068 "117": [0, 0.44444, 0, 0, 0.63889], 2069 "118": [0, 0.44444, 0.01597, 0, 0.60694], 2070 "119": [0, 0.44444, 0.01597, 0, 0.83055], 2071 "120": [0, 0.44444, 0, 0, 0.60694], 2072 "121": [0.19444, 0.44444, 0.01597, 0, 0.60694], 2073 "122": [0, 0.44444, 0, 0, 0.51111], 2074 "123": [0.25, 0.75, 0, 0, 0.575], 2075 "124": [0.25, 0.75, 0, 0, 0.31944], 2076 "125": [0.25, 0.75, 0, 0, 0.575], 2077 "126": [0.35, 0.34444, 0, 0, 0.575], 2078 "168": [0, 0.69444, 0, 0, 0.575], 2079 "172": [0, 0.44444, 0, 0, 0.76666], 2080 "176": [0, 0.69444, 0, 0, 0.86944], 2081 "177": [0.13333, 0.63333, 0, 0, 0.89444], 2082 "184": [0.17014, 0, 0, 0, 0.51111], 2083 "198": [0, 0.68611, 0, 0, 1.04166], 2084 "215": [0.13333, 0.63333, 0, 0, 0.89444], 2085 "216": [0.04861, 0.73472, 0, 0, 0.89444], 2086 "223": [0, 0.69444, 0, 0, 0.59722], 2087 "230": [0, 0.44444, 0, 0, 0.83055], 2088 "247": [0.13333, 0.63333, 0, 0, 0.89444], 2089 "248": [0.09722, 0.54167, 0, 0, 0.575], 2090 "305": [0, 0.44444, 0, 0, 0.31944], 2091 "338": [0, 0.68611, 0, 0, 1.16944], 2092 "339": [0, 0.44444, 0, 0, 0.89444], 2093 "567": [0.19444, 0.44444, 0, 0, 0.35139], 2094 "710": [0, 0.69444, 0, 0, 0.575], 2095 "711": [0, 0.63194, 0, 0, 0.575], 2096 "713": [0, 0.59611, 0, 0, 0.575], 2097 "714": [0, 0.69444, 0, 0, 0.575], 2098 "715": [0, 0.69444, 0, 0, 0.575], 2099 "728": [0, 0.69444, 0, 0, 0.575], 2100 "729": [0, 0.69444, 0, 0, 0.31944], 2101 "730": [0, 0.69444, 0, 0, 0.86944], 2102 "732": [0, 0.69444, 0, 0, 0.575], 2103 "733": [0, 0.69444, 0, 0, 0.575], 2104 "915": [0, 0.68611, 0, 0, 0.69166], 2105 "916": [0, 0.68611, 0, 0, 0.95833], 2106 "920": [0, 0.68611, 0, 0, 0.89444], 2107 "923": [0, 0.68611, 0, 0, 0.80555], 2108 "926": [0, 0.68611, 0, 0, 0.76666], 2109 "928": [0, 0.68611, 0, 0, 0.9], 2110 "931": [0, 0.68611, 0, 0, 0.83055], 2111 "933": [0, 0.68611, 0, 0, 0.89444], 2112 "934": [0, 0.68611, 0, 0, 0.83055], 2113 "936": [0, 0.68611, 0, 0, 0.89444], 2114 "937": [0, 0.68611, 0, 0, 0.83055], 2115 "8211": [0, 0.44444, 0.03194, 0, 0.575], 2116 "8212": [0, 0.44444, 0.03194, 0, 1.14999], 2117 "8216": [0, 0.69444, 0, 0, 0.31944], 2118 "8217": [0, 0.69444, 0, 0, 0.31944], 2119 "8220": [0, 0.69444, 0, 0, 0.60278], 2120 "8221": [0, 0.69444, 0, 0, 0.60278], 2121 "8224": [0.19444, 0.69444, 0, 0, 0.51111], 2122 "8225": [0.19444, 0.69444, 0, 0, 0.51111], 2123 "8242": [0, 0.55556, 0, 0, 0.34444], 2124 "8407": [0, 0.72444, 0.15486, 0, 0.575], 2125 "8463": [0, 0.69444, 0, 0, 0.66759], 2126 "8465": [0, 0.69444, 0, 0, 0.83055], 2127 "8467": [0, 0.69444, 0, 0, 0.47361], 2128 "8472": [0.19444, 0.44444, 0, 0, 0.74027], 2129 "8476": [0, 0.69444, 0, 0, 0.83055], 2130 "8501": [0, 0.69444, 0, 0, 0.70277], 2131 "8592": [-0.10889, 0.39111, 0, 0, 1.14999], 2132 "8593": [0.19444, 0.69444, 0, 0, 0.575], 2133 "8594": [-0.10889, 0.39111, 0, 0, 1.14999], 2134 "8595": [0.19444, 0.69444, 0, 0, 0.575], 2135 "8596": [-0.10889, 0.39111, 0, 0, 1.14999], 2136 "8597": [0.25, 0.75, 0, 0, 0.575], 2137 "8598": [0.19444, 0.69444, 0, 0, 1.14999], 2138 "8599": [0.19444, 0.69444, 0, 0, 1.14999], 2139 "8600": [0.19444, 0.69444, 0, 0, 1.14999], 2140 "8601": [0.19444, 0.69444, 0, 0, 1.14999], 2141 "8636": [-0.10889, 0.39111, 0, 0, 1.14999], 2142 "8637": [-0.10889, 0.39111, 0, 0, 1.14999], 2143 "8640": [-0.10889, 0.39111, 0, 0, 1.14999], 2144 "8641": [-0.10889, 0.39111, 0, 0, 1.14999], 2145 "8656": [-0.10889, 0.39111, 0, 0, 1.14999], 2146 "8657": [0.19444, 0.69444, 0, 0, 0.70277], 2147 "8658": [-0.10889, 0.39111, 0, 0, 1.14999], 2148 "8659": [0.19444, 0.69444, 0, 0, 0.70277], 2149 "8660": [-0.10889, 0.39111, 0, 0, 1.14999], 2150 "8661": [0.25, 0.75, 0, 0, 0.70277], 2151 "8704": [0, 0.69444, 0, 0, 0.63889], 2152 "8706": [0, 0.69444, 0.06389, 0, 0.62847], 2153 "8707": [0, 0.69444, 0, 0, 0.63889], 2154 "8709": [0.05556, 0.75, 0, 0, 0.575], 2155 "8711": [0, 0.68611, 0, 0, 0.95833], 2156 "8712": [0.08556, 0.58556, 0, 0, 0.76666], 2157 "8715": [0.08556, 0.58556, 0, 0, 0.76666], 2158 "8722": [0.13333, 0.63333, 0, 0, 0.89444], 2159 "8723": [0.13333, 0.63333, 0, 0, 0.89444], 2160 "8725": [0.25, 0.75, 0, 0, 0.575], 2161 "8726": [0.25, 0.75, 0, 0, 0.575], 2162 "8727": [-0.02778, 0.47222, 0, 0, 0.575], 2163 "8728": [-0.02639, 0.47361, 0, 0, 0.575], 2164 "8729": [-0.02639, 0.47361, 0, 0, 0.575], 2165 "8730": [0.18, 0.82, 0, 0, 0.95833], 2166 "8733": [0, 0.44444, 0, 0, 0.89444], 2167 "8734": [0, 0.44444, 0, 0, 1.14999], 2168 "8736": [0, 0.69224, 0, 0, 0.72222], 2169 "8739": [0.25, 0.75, 0, 0, 0.31944], 2170 "8741": [0.25, 0.75, 0, 0, 0.575], 2171 "8743": [0, 0.55556, 0, 0, 0.76666], 2172 "8744": [0, 0.55556, 0, 0, 0.76666], 2173 "8745": [0, 0.55556, 0, 0, 0.76666], 2174 "8746": [0, 0.55556, 0, 0, 0.76666], 2175 "8747": [0.19444, 0.69444, 0.12778, 0, 0.56875], 2176 "8764": [-0.10889, 0.39111, 0, 0, 0.89444], 2177 "8768": [0.19444, 0.69444, 0, 0, 0.31944], 2178 "8771": [0.00222, 0.50222, 0, 0, 0.89444], 2179 "8776": [0.02444, 0.52444, 0, 0, 0.89444], 2180 "8781": [0.00222, 0.50222, 0, 0, 0.89444], 2181 "8801": [0.00222, 0.50222, 0, 0, 0.89444], 2182 "8804": [0.19667, 0.69667, 0, 0, 0.89444], 2183 "8805": [0.19667, 0.69667, 0, 0, 0.89444], 2184 "8810": [0.08556, 0.58556, 0, 0, 1.14999], 2185 "8811": [0.08556, 0.58556, 0, 0, 1.14999], 2186 "8826": [0.08556, 0.58556, 0, 0, 0.89444], 2187 "8827": [0.08556, 0.58556, 0, 0, 0.89444], 2188 "8834": [0.08556, 0.58556, 0, 0, 0.89444], 2189 "8835": [0.08556, 0.58556, 0, 0, 0.89444], 2190 "8838": [0.19667, 0.69667, 0, 0, 0.89444], 2191 "8839": [0.19667, 0.69667, 0, 0, 0.89444], 2192 "8846": [0, 0.55556, 0, 0, 0.76666], 2193 "8849": [0.19667, 0.69667, 0, 0, 0.89444], 2194 "8850": [0.19667, 0.69667, 0, 0, 0.89444], 2195 "8851": [0, 0.55556, 0, 0, 0.76666], 2196 "8852": [0, 0.55556, 0, 0, 0.76666], 2197 "8853": [0.13333, 0.63333, 0, 0, 0.89444], 2198 "8854": [0.13333, 0.63333, 0, 0, 0.89444], 2199 "8855": [0.13333, 0.63333, 0, 0, 0.89444], 2200 "8856": [0.13333, 0.63333, 0, 0, 0.89444], 2201 "8857": [0.13333, 0.63333, 0, 0, 0.89444], 2202 "8866": [0, 0.69444, 0, 0, 0.70277], 2203 "8867": [0, 0.69444, 0, 0, 0.70277], 2204 "8868": [0, 0.69444, 0, 0, 0.89444], 2205 "8869": [0, 0.69444, 0, 0, 0.89444], 2206 "8900": [-0.02639, 0.47361, 0, 0, 0.575], 2207 "8901": [-0.02639, 0.47361, 0, 0, 0.31944], 2208 "8902": [-0.02778, 0.47222, 0, 0, 0.575], 2209 "8968": [0.25, 0.75, 0, 0, 0.51111], 2210 "8969": [0.25, 0.75, 0, 0, 0.51111], 2211 "8970": [0.25, 0.75, 0, 0, 0.51111], 2212 "8971": [0.25, 0.75, 0, 0, 0.51111], 2213 "8994": [-0.13889, 0.36111, 0, 0, 1.14999], 2214 "8995": [-0.13889, 0.36111, 0, 0, 1.14999], 2215 "9651": [0.19444, 0.69444, 0, 0, 1.02222], 2216 "9657": [-0.02778, 0.47222, 0, 0, 0.575], 2217 "9661": [0.19444, 0.69444, 0, 0, 1.02222], 2218 "9667": [-0.02778, 0.47222, 0, 0, 0.575], 2219 "9711": [0.19444, 0.69444, 0, 0, 1.14999], 2220 "9824": [0.12963, 0.69444, 0, 0, 0.89444], 2221 "9825": [0.12963, 0.69444, 0, 0, 0.89444], 2222 "9826": [0.12963, 0.69444, 0, 0, 0.89444], 2223 "9827": [0.12963, 0.69444, 0, 0, 0.89444], 2224 "9837": [0, 0.75, 0, 0, 0.44722], 2225 "9838": [0.19444, 0.69444, 0, 0, 0.44722], 2226 "9839": [0.19444, 0.69444, 0, 0, 0.44722], 2227 "10216": [0.25, 0.75, 0, 0, 0.44722], 2228 "10217": [0.25, 0.75, 0, 0, 0.44722], 2229 "10815": [0, 0.68611, 0, 0, 0.9], 2230 "10927": [0.19667, 0.69667, 0, 0, 0.89444], 2231 "10928": [0.19667, 0.69667, 0, 0, 0.89444], 2232 "57376": [0.19444, 0.69444, 0, 0, 0] 2233 }, 2234 "Main-BoldItalic": { 2235 "33": [0, 0.69444, 0.11417, 0, 0.38611], 2236 "34": [0, 0.69444, 0.07939, 0, 0.62055], 2237 "35": [0.19444, 0.69444, 0.06833, 0, 0.94444], 2238 "37": [0.05556, 0.75, 0.12861, 0, 0.94444], 2239 "38": [0, 0.69444, 0.08528, 0, 0.88555], 2240 "39": [0, 0.69444, 0.12945, 0, 0.35555], 2241 "40": [0.25, 0.75, 0.15806, 0, 0.47333], 2242 "41": [0.25, 0.75, 0.03306, 0, 0.47333], 2243 "42": [0, 0.75, 0.14333, 0, 0.59111], 2244 "43": [0.10333, 0.60333, 0.03306, 0, 0.88555], 2245 "44": [0.19444, 0.14722, 0, 0, 0.35555], 2246 "45": [0, 0.44444, 0.02611, 0, 0.41444], 2247 "46": [0, 0.14722, 0, 0, 0.35555], 2248 "47": [0.25, 0.75, 0.15806, 0, 0.59111], 2249 "48": [0, 0.64444, 0.13167, 0, 0.59111], 2250 "49": [0, 0.64444, 0.13167, 0, 0.59111], 2251 "50": [0, 0.64444, 0.13167, 0, 0.59111], 2252 "51": [0, 0.64444, 0.13167, 0, 0.59111], 2253 "52": [0.19444, 0.64444, 0.13167, 0, 0.59111], 2254 "53": [0, 0.64444, 0.13167, 0, 0.59111], 2255 "54": [0, 0.64444, 0.13167, 0, 0.59111], 2256 "55": [0.19444, 0.64444, 0.13167, 0, 0.59111], 2257 "56": [0, 0.64444, 0.13167, 0, 0.59111], 2258 "57": [0, 0.64444, 0.13167, 0, 0.59111], 2259 "58": [0, 0.44444, 0.06695, 0, 0.35555], 2260 "59": [0.19444, 0.44444, 0.06695, 0, 0.35555], 2261 "61": [-0.10889, 0.39111, 0.06833, 0, 0.88555], 2262 "63": [0, 0.69444, 0.11472, 0, 0.59111], 2263 "64": [0, 0.69444, 0.09208, 0, 0.88555], 2264 "65": [0, 0.68611, 0, 0, 0.86555], 2265 "66": [0, 0.68611, 0.0992, 0, 0.81666], 2266 "67": [0, 0.68611, 0.14208, 0, 0.82666], 2267 "68": [0, 0.68611, 0.09062, 0, 0.87555], 2268 "69": [0, 0.68611, 0.11431, 0, 0.75666], 2269 "70": [0, 0.68611, 0.12903, 0, 0.72722], 2270 "71": [0, 0.68611, 0.07347, 0, 0.89527], 2271 "72": [0, 0.68611, 0.17208, 0, 0.8961], 2272 "73": [0, 0.68611, 0.15681, 0, 0.47166], 2273 "74": [0, 0.68611, 0.145, 0, 0.61055], 2274 "75": [0, 0.68611, 0.14208, 0, 0.89499], 2275 "76": [0, 0.68611, 0, 0, 0.69777], 2276 "77": [0, 0.68611, 0.17208, 0, 1.07277], 2277 "78": [0, 0.68611, 0.17208, 0, 0.8961], 2278 "79": [0, 0.68611, 0.09062, 0, 0.85499], 2279 "80": [0, 0.68611, 0.0992, 0, 0.78721], 2280 "81": [0.19444, 0.68611, 0.09062, 0, 0.85499], 2281 "82": [0, 0.68611, 0.02559, 0, 0.85944], 2282 "83": [0, 0.68611, 0.11264, 0, 0.64999], 2283 "84": [0, 0.68611, 0.12903, 0, 0.7961], 2284 "85": [0, 0.68611, 0.17208, 0, 0.88083], 2285 "86": [0, 0.68611, 0.18625, 0, 0.86555], 2286 "87": [0, 0.68611, 0.18625, 0, 1.15999], 2287 "88": [0, 0.68611, 0.15681, 0, 0.86555], 2288 "89": [0, 0.68611, 0.19803, 0, 0.86555], 2289 "90": [0, 0.68611, 0.14208, 0, 0.70888], 2290 "91": [0.25, 0.75, 0.1875, 0, 0.35611], 2291 "93": [0.25, 0.75, 0.09972, 0, 0.35611], 2292 "94": [0, 0.69444, 0.06709, 0, 0.59111], 2293 "95": [0.31, 0.13444, 0.09811, 0, 0.59111], 2294 "97": [0, 0.44444, 0.09426, 0, 0.59111], 2295 "98": [0, 0.69444, 0.07861, 0, 0.53222], 2296 "99": [0, 0.44444, 0.05222, 0, 0.53222], 2297 "100": [0, 0.69444, 0.10861, 0, 0.59111], 2298 "101": [0, 0.44444, 0.085, 0, 0.53222], 2299 "102": [0.19444, 0.69444, 0.21778, 0, 0.4], 2300 "103": [0.19444, 0.44444, 0.105, 0, 0.53222], 2301 "104": [0, 0.69444, 0.09426, 0, 0.59111], 2302 "105": [0, 0.69326, 0.11387, 0, 0.35555], 2303 "106": [0.19444, 0.69326, 0.1672, 0, 0.35555], 2304 "107": [0, 0.69444, 0.11111, 0, 0.53222], 2305 "108": [0, 0.69444, 0.10861, 0, 0.29666], 2306 "109": [0, 0.44444, 0.09426, 0, 0.94444], 2307 "110": [0, 0.44444, 0.09426, 0, 0.64999], 2308 "111": [0, 0.44444, 0.07861, 0, 0.59111], 2309 "112": [0.19444, 0.44444, 0.07861, 0, 0.59111], 2310 "113": [0.19444, 0.44444, 0.105, 0, 0.53222], 2311 "114": [0, 0.44444, 0.11111, 0, 0.50167], 2312 "115": [0, 0.44444, 0.08167, 0, 0.48694], 2313 "116": [0, 0.63492, 0.09639, 0, 0.385], 2314 "117": [0, 0.44444, 0.09426, 0, 0.62055], 2315 "118": [0, 0.44444, 0.11111, 0, 0.53222], 2316 "119": [0, 0.44444, 0.11111, 0, 0.76777], 2317 "120": [0, 0.44444, 0.12583, 0, 0.56055], 2318 "121": [0.19444, 0.44444, 0.105, 0, 0.56166], 2319 "122": [0, 0.44444, 0.13889, 0, 0.49055], 2320 "126": [0.35, 0.34444, 0.11472, 0, 0.59111], 2321 "163": [0, 0.69444, 0, 0, 0.86853], 2322 "168": [0, 0.69444, 0.11473, 0, 0.59111], 2323 "176": [0, 0.69444, 0, 0, 0.94888], 2324 "184": [0.17014, 0, 0, 0, 0.53222], 2325 "198": [0, 0.68611, 0.11431, 0, 1.02277], 2326 "216": [0.04861, 0.73472, 0.09062, 0, 0.88555], 2327 "223": [0.19444, 0.69444, 0.09736, 0, 0.665], 2328 "230": [0, 0.44444, 0.085, 0, 0.82666], 2329 "248": [0.09722, 0.54167, 0.09458, 0, 0.59111], 2330 "305": [0, 0.44444, 0.09426, 0, 0.35555], 2331 "338": [0, 0.68611, 0.11431, 0, 1.14054], 2332 "339": [0, 0.44444, 0.085, 0, 0.82666], 2333 "567": [0.19444, 0.44444, 0.04611, 0, 0.385], 2334 "710": [0, 0.69444, 0.06709, 0, 0.59111], 2335 "711": [0, 0.63194, 0.08271, 0, 0.59111], 2336 "713": [0, 0.59444, 0.10444, 0, 0.59111], 2337 "714": [0, 0.69444, 0.08528, 0, 0.59111], 2338 "715": [0, 0.69444, 0, 0, 0.59111], 2339 "728": [0, 0.69444, 0.10333, 0, 0.59111], 2340 "729": [0, 0.69444, 0.12945, 0, 0.35555], 2341 "730": [0, 0.69444, 0, 0, 0.94888], 2342 "732": [0, 0.69444, 0.11472, 0, 0.59111], 2343 "733": [0, 0.69444, 0.11472, 0, 0.59111], 2344 "915": [0, 0.68611, 0.12903, 0, 0.69777], 2345 "916": [0, 0.68611, 0, 0, 0.94444], 2346 "920": [0, 0.68611, 0.09062, 0, 0.88555], 2347 "923": [0, 0.68611, 0, 0, 0.80666], 2348 "926": [0, 0.68611, 0.15092, 0, 0.76777], 2349 "928": [0, 0.68611, 0.17208, 0, 0.8961], 2350 "931": [0, 0.68611, 0.11431, 0, 0.82666], 2351 "933": [0, 0.68611, 0.10778, 0, 0.88555], 2352 "934": [0, 0.68611, 0.05632, 0, 0.82666], 2353 "936": [0, 0.68611, 0.10778, 0, 0.88555], 2354 "937": [0, 0.68611, 0.0992, 0, 0.82666], 2355 "8211": [0, 0.44444, 0.09811, 0, 0.59111], 2356 "8212": [0, 0.44444, 0.09811, 0, 1.18221], 2357 "8216": [0, 0.69444, 0.12945, 0, 0.35555], 2358 "8217": [0, 0.69444, 0.12945, 0, 0.35555], 2359 "8220": [0, 0.69444, 0.16772, 0, 0.62055], 2360 "8221": [0, 0.69444, 0.07939, 0, 0.62055] 2361 }, 2362 "Main-Italic": { 2363 "33": [0, 0.69444, 0.12417, 0, 0.30667], 2364 "34": [0, 0.69444, 0.06961, 0, 0.51444], 2365 "35": [0.19444, 0.69444, 0.06616, 0, 0.81777], 2366 "37": [0.05556, 0.75, 0.13639, 0, 0.81777], 2367 "38": [0, 0.69444, 0.09694, 0, 0.76666], 2368 "39": [0, 0.69444, 0.12417, 0, 0.30667], 2369 "40": [0.25, 0.75, 0.16194, 0, 0.40889], 2370 "41": [0.25, 0.75, 0.03694, 0, 0.40889], 2371 "42": [0, 0.75, 0.14917, 0, 0.51111], 2372 "43": [0.05667, 0.56167, 0.03694, 0, 0.76666], 2373 "44": [0.19444, 0.10556, 0, 0, 0.30667], 2374 "45": [0, 0.43056, 0.02826, 0, 0.35778], 2375 "46": [0, 0.10556, 0, 0, 0.30667], 2376 "47": [0.25, 0.75, 0.16194, 0, 0.51111], 2377 "48": [0, 0.64444, 0.13556, 0, 0.51111], 2378 "49": [0, 0.64444, 0.13556, 0, 0.51111], 2379 "50": [0, 0.64444, 0.13556, 0, 0.51111], 2380 "51": [0, 0.64444, 0.13556, 0, 0.51111], 2381 "52": [0.19444, 0.64444, 0.13556, 0, 0.51111], 2382 "53": [0, 0.64444, 0.13556, 0, 0.51111], 2383 "54": [0, 0.64444, 0.13556, 0, 0.51111], 2384 "55": [0.19444, 0.64444, 0.13556, 0, 0.51111], 2385 "56": [0, 0.64444, 0.13556, 0, 0.51111], 2386 "57": [0, 0.64444, 0.13556, 0, 0.51111], 2387 "58": [0, 0.43056, 0.0582, 0, 0.30667], 2388 "59": [0.19444, 0.43056, 0.0582, 0, 0.30667], 2389 "61": [-0.13313, 0.36687, 0.06616, 0, 0.76666], 2390 "63": [0, 0.69444, 0.1225, 0, 0.51111], 2391 "64": [0, 0.69444, 0.09597, 0, 0.76666], 2392 "65": [0, 0.68333, 0, 0, 0.74333], 2393 "66": [0, 0.68333, 0.10257, 0, 0.70389], 2394 "67": [0, 0.68333, 0.14528, 0, 0.71555], 2395 "68": [0, 0.68333, 0.09403, 0, 0.755], 2396 "69": [0, 0.68333, 0.12028, 0, 0.67833], 2397 "70": [0, 0.68333, 0.13305, 0, 0.65277], 2398 "71": [0, 0.68333, 0.08722, 0, 0.77361], 2399 "72": [0, 0.68333, 0.16389, 0, 0.74333], 2400 "73": [0, 0.68333, 0.15806, 0, 0.38555], 2401 "74": [0, 0.68333, 0.14028, 0, 0.525], 2402 "75": [0, 0.68333, 0.14528, 0, 0.76888], 2403 "76": [0, 0.68333, 0, 0, 0.62722], 2404 "77": [0, 0.68333, 0.16389, 0, 0.89666], 2405 "78": [0, 0.68333, 0.16389, 0, 0.74333], 2406 "79": [0, 0.68333, 0.09403, 0, 0.76666], 2407 "80": [0, 0.68333, 0.10257, 0, 0.67833], 2408 "81": [0.19444, 0.68333, 0.09403, 0, 0.76666], 2409 "82": [0, 0.68333, 0.03868, 0, 0.72944], 2410 "83": [0, 0.68333, 0.11972, 0, 0.56222], 2411 "84": [0, 0.68333, 0.13305, 0, 0.71555], 2412 "85": [0, 0.68333, 0.16389, 0, 0.74333], 2413 "86": [0, 0.68333, 0.18361, 0, 0.74333], 2414 "87": [0, 0.68333, 0.18361, 0, 0.99888], 2415 "88": [0, 0.68333, 0.15806, 0, 0.74333], 2416 "89": [0, 0.68333, 0.19383, 0, 0.74333], 2417 "90": [0, 0.68333, 0.14528, 0, 0.61333], 2418 "91": [0.25, 0.75, 0.1875, 0, 0.30667], 2419 "93": [0.25, 0.75, 0.10528, 0, 0.30667], 2420 "94": [0, 0.69444, 0.06646, 0, 0.51111], 2421 "95": [0.31, 0.12056, 0.09208, 0, 0.51111], 2422 "97": [0, 0.43056, 0.07671, 0, 0.51111], 2423 "98": [0, 0.69444, 0.06312, 0, 0.46], 2424 "99": [0, 0.43056, 0.05653, 0, 0.46], 2425 "100": [0, 0.69444, 0.10333, 0, 0.51111], 2426 "101": [0, 0.43056, 0.07514, 0, 0.46], 2427 "102": [0.19444, 0.69444, 0.21194, 0, 0.30667], 2428 "103": [0.19444, 0.43056, 0.08847, 0, 0.46], 2429 "104": [0, 0.69444, 0.07671, 0, 0.51111], 2430 "105": [0, 0.65536, 0.1019, 0, 0.30667], 2431 "106": [0.19444, 0.65536, 0.14467, 0, 0.30667], 2432 "107": [0, 0.69444, 0.10764, 0, 0.46], 2433 "108": [0, 0.69444, 0.10333, 0, 0.25555], 2434 "109": [0, 0.43056, 0.07671, 0, 0.81777], 2435 "110": [0, 0.43056, 0.07671, 0, 0.56222], 2436 "111": [0, 0.43056, 0.06312, 0, 0.51111], 2437 "112": [0.19444, 0.43056, 0.06312, 0, 0.51111], 2438 "113": [0.19444, 0.43056, 0.08847, 0, 0.46], 2439 "114": [0, 0.43056, 0.10764, 0, 0.42166], 2440 "115": [0, 0.43056, 0.08208, 0, 0.40889], 2441 "116": [0, 0.61508, 0.09486, 0, 0.33222], 2442 "117": [0, 0.43056, 0.07671, 0, 0.53666], 2443 "118": [0, 0.43056, 0.10764, 0, 0.46], 2444 "119": [0, 0.43056, 0.10764, 0, 0.66444], 2445 "120": [0, 0.43056, 0.12042, 0, 0.46389], 2446 "121": [0.19444, 0.43056, 0.08847, 0, 0.48555], 2447 "122": [0, 0.43056, 0.12292, 0, 0.40889], 2448 "126": [0.35, 0.31786, 0.11585, 0, 0.51111], 2449 "163": [0, 0.69444, 0, 0, 0.76909], 2450 "168": [0, 0.66786, 0.10474, 0, 0.51111], 2451 "176": [0, 0.69444, 0, 0, 0.83129], 2452 "184": [0.17014, 0, 0, 0, 0.46], 2453 "198": [0, 0.68333, 0.12028, 0, 0.88277], 2454 "216": [0.04861, 0.73194, 0.09403, 0, 0.76666], 2455 "223": [0.19444, 0.69444, 0.10514, 0, 0.53666], 2456 "230": [0, 0.43056, 0.07514, 0, 0.71555], 2457 "248": [0.09722, 0.52778, 0.09194, 0, 0.51111], 2458 "305": [0, 0.43056, 0, 0.02778, 0.32246], 2459 "338": [0, 0.68333, 0.12028, 0, 0.98499], 2460 "339": [0, 0.43056, 0.07514, 0, 0.71555], 2461 "567": [0.19444, 0.43056, 0, 0.08334, 0.38403], 2462 "710": [0, 0.69444, 0.06646, 0, 0.51111], 2463 "711": [0, 0.62847, 0.08295, 0, 0.51111], 2464 "713": [0, 0.56167, 0.10333, 0, 0.51111], 2465 "714": [0, 0.69444, 0.09694, 0, 0.51111], 2466 "715": [0, 0.69444, 0, 0, 0.51111], 2467 "728": [0, 0.69444, 0.10806, 0, 0.51111], 2468 "729": [0, 0.66786, 0.11752, 0, 0.30667], 2469 "730": [0, 0.69444, 0, 0, 0.83129], 2470 "732": [0, 0.66786, 0.11585, 0, 0.51111], 2471 "733": [0, 0.69444, 0.1225, 0, 0.51111], 2472 "915": [0, 0.68333, 0.13305, 0, 0.62722], 2473 "916": [0, 0.68333, 0, 0, 0.81777], 2474 "920": [0, 0.68333, 0.09403, 0, 0.76666], 2475 "923": [0, 0.68333, 0, 0, 0.69222], 2476 "926": [0, 0.68333, 0.15294, 0, 0.66444], 2477 "928": [0, 0.68333, 0.16389, 0, 0.74333], 2478 "931": [0, 0.68333, 0.12028, 0, 0.71555], 2479 "933": [0, 0.68333, 0.11111, 0, 0.76666], 2480 "934": [0, 0.68333, 0.05986, 0, 0.71555], 2481 "936": [0, 0.68333, 0.11111, 0, 0.76666], 2482 "937": [0, 0.68333, 0.10257, 0, 0.71555], 2483 "8211": [0, 0.43056, 0.09208, 0, 0.51111], 2484 "8212": [0, 0.43056, 0.09208, 0, 1.02222], 2485 "8216": [0, 0.69444, 0.12417, 0, 0.30667], 2486 "8217": [0, 0.69444, 0.12417, 0, 0.30667], 2487 "8220": [0, 0.69444, 0.1685, 0, 0.51444], 2488 "8221": [0, 0.69444, 0.06961, 0, 0.51444], 2489 "8463": [0, 0.68889, 0, 0, 0.54028] 2490 }, 2491 "Main-Regular": { 2492 "32": [0, 0, 0, 0, 0.25], 2493 "33": [0, 0.69444, 0, 0, 0.27778], 2494 "34": [0, 0.69444, 0, 0, 0.5], 2495 "35": [0.19444, 0.69444, 0, 0, 0.83334], 2496 "36": [0.05556, 0.75, 0, 0, 0.5], 2497 "37": [0.05556, 0.75, 0, 0, 0.83334], 2498 "38": [0, 0.69444, 0, 0, 0.77778], 2499 "39": [0, 0.69444, 0, 0, 0.27778], 2500 "40": [0.25, 0.75, 0, 0, 0.38889], 2501 "41": [0.25, 0.75, 0, 0, 0.38889], 2502 "42": [0, 0.75, 0, 0, 0.5], 2503 "43": [0.08333, 0.58333, 0, 0, 0.77778], 2504 "44": [0.19444, 0.10556, 0, 0, 0.27778], 2505 "45": [0, 0.43056, 0, 0, 0.33333], 2506 "46": [0, 0.10556, 0, 0, 0.27778], 2507 "47": [0.25, 0.75, 0, 0, 0.5], 2508 "48": [0, 0.64444, 0, 0, 0.5], 2509 "49": [0, 0.64444, 0, 0, 0.5], 2510 "50": [0, 0.64444, 0, 0, 0.5], 2511 "51": [0, 0.64444, 0, 0, 0.5], 2512 "52": [0, 0.64444, 0, 0, 0.5], 2513 "53": [0, 0.64444, 0, 0, 0.5], 2514 "54": [0, 0.64444, 0, 0, 0.5], 2515 "55": [0, 0.64444, 0, 0, 0.5], 2516 "56": [0, 0.64444, 0, 0, 0.5], 2517 "57": [0, 0.64444, 0, 0, 0.5], 2518 "58": [0, 0.43056, 0, 0, 0.27778], 2519 "59": [0.19444, 0.43056, 0, 0, 0.27778], 2520 "60": [0.0391, 0.5391, 0, 0, 0.77778], 2521 "61": [-0.13313, 0.36687, 0, 0, 0.77778], 2522 "62": [0.0391, 0.5391, 0, 0, 0.77778], 2523 "63": [0, 0.69444, 0, 0, 0.47222], 2524 "64": [0, 0.69444, 0, 0, 0.77778], 2525 "65": [0, 0.68333, 0, 0, 0.75], 2526 "66": [0, 0.68333, 0, 0, 0.70834], 2527 "67": [0, 0.68333, 0, 0, 0.72222], 2528 "68": [0, 0.68333, 0, 0, 0.76389], 2529 "69": [0, 0.68333, 0, 0, 0.68056], 2530 "70": [0, 0.68333, 0, 0, 0.65278], 2531 "71": [0, 0.68333, 0, 0, 0.78472], 2532 "72": [0, 0.68333, 0, 0, 0.75], 2533 "73": [0, 0.68333, 0, 0, 0.36111], 2534 "74": [0, 0.68333, 0, 0, 0.51389], 2535 "75": [0, 0.68333, 0, 0, 0.77778], 2536 "76": [0, 0.68333, 0, 0, 0.625], 2537 "77": [0, 0.68333, 0, 0, 0.91667], 2538 "78": [0, 0.68333, 0, 0, 0.75], 2539 "79": [0, 0.68333, 0, 0, 0.77778], 2540 "80": [0, 0.68333, 0, 0, 0.68056], 2541 "81": [0.19444, 0.68333, 0, 0, 0.77778], 2542 "82": [0, 0.68333, 0, 0, 0.73611], 2543 "83": [0, 0.68333, 0, 0, 0.55556], 2544 "84": [0, 0.68333, 0, 0, 0.72222], 2545 "85": [0, 0.68333, 0, 0, 0.75], 2546 "86": [0, 0.68333, 0.01389, 0, 0.75], 2547 "87": [0, 0.68333, 0.01389, 0, 1.02778], 2548 "88": [0, 0.68333, 0, 0, 0.75], 2549 "89": [0, 0.68333, 0.025, 0, 0.75], 2550 "90": [0, 0.68333, 0, 0, 0.61111], 2551 "91": [0.25, 0.75, 0, 0, 0.27778], 2552 "92": [0.25, 0.75, 0, 0, 0.5], 2553 "93": [0.25, 0.75, 0, 0, 0.27778], 2554 "94": [0, 0.69444, 0, 0, 0.5], 2555 "95": [0.31, 0.12056, 0.02778, 0, 0.5], 2556 "97": [0, 0.43056, 0, 0, 0.5], 2557 "98": [0, 0.69444, 0, 0, 0.55556], 2558 "99": [0, 0.43056, 0, 0, 0.44445], 2559 "100": [0, 0.69444, 0, 0, 0.55556], 2560 "101": [0, 0.43056, 0, 0, 0.44445], 2561 "102": [0, 0.69444, 0.07778, 0, 0.30556], 2562 "103": [0.19444, 0.43056, 0.01389, 0, 0.5], 2563 "104": [0, 0.69444, 0, 0, 0.55556], 2564 "105": [0, 0.66786, 0, 0, 0.27778], 2565 "106": [0.19444, 0.66786, 0, 0, 0.30556], 2566 "107": [0, 0.69444, 0, 0, 0.52778], 2567 "108": [0, 0.69444, 0, 0, 0.27778], 2568 "109": [0, 0.43056, 0, 0, 0.83334], 2569 "110": [0, 0.43056, 0, 0, 0.55556], 2570 "111": [0, 0.43056, 0, 0, 0.5], 2571 "112": [0.19444, 0.43056, 0, 0, 0.55556], 2572 "113": [0.19444, 0.43056, 0, 0, 0.52778], 2573 "114": [0, 0.43056, 0, 0, 0.39167], 2574 "115": [0, 0.43056, 0, 0, 0.39445], 2575 "116": [0, 0.61508, 0, 0, 0.38889], 2576 "117": [0, 0.43056, 0, 0, 0.55556], 2577 "118": [0, 0.43056, 0.01389, 0, 0.52778], 2578 "119": [0, 0.43056, 0.01389, 0, 0.72222], 2579 "120": [0, 0.43056, 0, 0, 0.52778], 2580 "121": [0.19444, 0.43056, 0.01389, 0, 0.52778], 2581 "122": [0, 0.43056, 0, 0, 0.44445], 2582 "123": [0.25, 0.75, 0, 0, 0.5], 2583 "124": [0.25, 0.75, 0, 0, 0.27778], 2584 "125": [0.25, 0.75, 0, 0, 0.5], 2585 "126": [0.35, 0.31786, 0, 0, 0.5], 2586 "160": [0, 0, 0, 0, 0.25], 2587 "167": [0.19444, 0.69444, 0, 0, 0.44445], 2588 "168": [0, 0.66786, 0, 0, 0.5], 2589 "172": [0, 0.43056, 0, 0, 0.66667], 2590 "176": [0, 0.69444, 0, 0, 0.75], 2591 "177": [0.08333, 0.58333, 0, 0, 0.77778], 2592 "182": [0.19444, 0.69444, 0, 0, 0.61111], 2593 "184": [0.17014, 0, 0, 0, 0.44445], 2594 "198": [0, 0.68333, 0, 0, 0.90278], 2595 "215": [0.08333, 0.58333, 0, 0, 0.77778], 2596 "216": [0.04861, 0.73194, 0, 0, 0.77778], 2597 "223": [0, 0.69444, 0, 0, 0.5], 2598 "230": [0, 0.43056, 0, 0, 0.72222], 2599 "247": [0.08333, 0.58333, 0, 0, 0.77778], 2600 "248": [0.09722, 0.52778, 0, 0, 0.5], 2601 "305": [0, 0.43056, 0, 0, 0.27778], 2602 "338": [0, 0.68333, 0, 0, 1.01389], 2603 "339": [0, 0.43056, 0, 0, 0.77778], 2604 "567": [0.19444, 0.43056, 0, 0, 0.30556], 2605 "710": [0, 0.69444, 0, 0, 0.5], 2606 "711": [0, 0.62847, 0, 0, 0.5], 2607 "713": [0, 0.56778, 0, 0, 0.5], 2608 "714": [0, 0.69444, 0, 0, 0.5], 2609 "715": [0, 0.69444, 0, 0, 0.5], 2610 "728": [0, 0.69444, 0, 0, 0.5], 2611 "729": [0, 0.66786, 0, 0, 0.27778], 2612 "730": [0, 0.69444, 0, 0, 0.75], 2613 "732": [0, 0.66786, 0, 0, 0.5], 2614 "733": [0, 0.69444, 0, 0, 0.5], 2615 "915": [0, 0.68333, 0, 0, 0.625], 2616 "916": [0, 0.68333, 0, 0, 0.83334], 2617 "920": [0, 0.68333, 0, 0, 0.77778], 2618 "923": [0, 0.68333, 0, 0, 0.69445], 2619 "926": [0, 0.68333, 0, 0, 0.66667], 2620 "928": [0, 0.68333, 0, 0, 0.75], 2621 "931": [0, 0.68333, 0, 0, 0.72222], 2622 "933": [0, 0.68333, 0, 0, 0.77778], 2623 "934": [0, 0.68333, 0, 0, 0.72222], 2624 "936": [0, 0.68333, 0, 0, 0.77778], 2625 "937": [0, 0.68333, 0, 0, 0.72222], 2626 "8211": [0, 0.43056, 0.02778, 0, 0.5], 2627 "8212": [0, 0.43056, 0.02778, 0, 1.0], 2628 "8216": [0, 0.69444, 0, 0, 0.27778], 2629 "8217": [0, 0.69444, 0, 0, 0.27778], 2630 "8220": [0, 0.69444, 0, 0, 0.5], 2631 "8221": [0, 0.69444, 0, 0, 0.5], 2632 "8224": [0.19444, 0.69444, 0, 0, 0.44445], 2633 "8225": [0.19444, 0.69444, 0, 0, 0.44445], 2634 "8230": [0, 0.12, 0, 0, 1.172], 2635 "8242": [0, 0.55556, 0, 0, 0.275], 2636 "8407": [0, 0.71444, 0.15382, 0, 0.5], 2637 "8463": [0, 0.68889, 0, 0, 0.54028], 2638 "8465": [0, 0.69444, 0, 0, 0.72222], 2639 "8467": [0, 0.69444, 0, 0.11111, 0.41667], 2640 "8472": [0.19444, 0.43056, 0, 0.11111, 0.63646], 2641 "8476": [0, 0.69444, 0, 0, 0.72222], 2642 "8501": [0, 0.69444, 0, 0, 0.61111], 2643 "8592": [-0.13313, 0.36687, 0, 0, 1.0], 2644 "8593": [0.19444, 0.69444, 0, 0, 0.5], 2645 "8594": [-0.13313, 0.36687, 0, 0, 1.0], 2646 "8595": [0.19444, 0.69444, 0, 0, 0.5], 2647 "8596": [-0.13313, 0.36687, 0, 0, 1.0], 2648 "8597": [0.25, 0.75, 0, 0, 0.5], 2649 "8598": [0.19444, 0.69444, 0, 0, 1.0], 2650 "8599": [0.19444, 0.69444, 0, 0, 1.0], 2651 "8600": [0.19444, 0.69444, 0, 0, 1.0], 2652 "8601": [0.19444, 0.69444, 0, 0, 1.0], 2653 "8614": [0.011, 0.511, 0, 0, 1.0], 2654 "8617": [0.011, 0.511, 0, 0, 1.126], 2655 "8618": [0.011, 0.511, 0, 0, 1.126], 2656 "8636": [-0.13313, 0.36687, 0, 0, 1.0], 2657 "8637": [-0.13313, 0.36687, 0, 0, 1.0], 2658 "8640": [-0.13313, 0.36687, 0, 0, 1.0], 2659 "8641": [-0.13313, 0.36687, 0, 0, 1.0], 2660 "8652": [0.011, 0.671, 0, 0, 1.0], 2661 "8656": [-0.13313, 0.36687, 0, 0, 1.0], 2662 "8657": [0.19444, 0.69444, 0, 0, 0.61111], 2663 "8658": [-0.13313, 0.36687, 0, 0, 1.0], 2664 "8659": [0.19444, 0.69444, 0, 0, 0.61111], 2665 "8660": [-0.13313, 0.36687, 0, 0, 1.0], 2666 "8661": [0.25, 0.75, 0, 0, 0.61111], 2667 "8704": [0, 0.69444, 0, 0, 0.55556], 2668 "8706": [0, 0.69444, 0.05556, 0.08334, 0.5309], 2669 "8707": [0, 0.69444, 0, 0, 0.55556], 2670 "8709": [0.05556, 0.75, 0, 0, 0.5], 2671 "8711": [0, 0.68333, 0, 0, 0.83334], 2672 "8712": [0.0391, 0.5391, 0, 0, 0.66667], 2673 "8715": [0.0391, 0.5391, 0, 0, 0.66667], 2674 "8722": [0.08333, 0.58333, 0, 0, 0.77778], 2675 "8723": [0.08333, 0.58333, 0, 0, 0.77778], 2676 "8725": [0.25, 0.75, 0, 0, 0.5], 2677 "8726": [0.25, 0.75, 0, 0, 0.5], 2678 "8727": [-0.03472, 0.46528, 0, 0, 0.5], 2679 "8728": [-0.05555, 0.44445, 0, 0, 0.5], 2680 "8729": [-0.05555, 0.44445, 0, 0, 0.5], 2681 "8730": [0.2, 0.8, 0, 0, 0.83334], 2682 "8733": [0, 0.43056, 0, 0, 0.77778], 2683 "8734": [0, 0.43056, 0, 0, 1.0], 2684 "8736": [0, 0.69224, 0, 0, 0.72222], 2685 "8739": [0.25, 0.75, 0, 0, 0.27778], 2686 "8741": [0.25, 0.75, 0, 0, 0.5], 2687 "8743": [0, 0.55556, 0, 0, 0.66667], 2688 "8744": [0, 0.55556, 0, 0, 0.66667], 2689 "8745": [0, 0.55556, 0, 0, 0.66667], 2690 "8746": [0, 0.55556, 0, 0, 0.66667], 2691 "8747": [0.19444, 0.69444, 0.11111, 0, 0.41667], 2692 "8764": [-0.13313, 0.36687, 0, 0, 0.77778], 2693 "8768": [0.19444, 0.69444, 0, 0, 0.27778], 2694 "8771": [-0.03625, 0.46375, 0, 0, 0.77778], 2695 "8773": [-0.022, 0.589, 0, 0, 1.0], 2696 "8776": [-0.01688, 0.48312, 0, 0, 0.77778], 2697 "8781": [-0.03625, 0.46375, 0, 0, 0.77778], 2698 "8784": [-0.133, 0.67, 0, 0, 0.778], 2699 "8801": [-0.03625, 0.46375, 0, 0, 0.77778], 2700 "8804": [0.13597, 0.63597, 0, 0, 0.77778], 2701 "8805": [0.13597, 0.63597, 0, 0, 0.77778], 2702 "8810": [0.0391, 0.5391, 0, 0, 1.0], 2703 "8811": [0.0391, 0.5391, 0, 0, 1.0], 2704 "8826": [0.0391, 0.5391, 0, 0, 0.77778], 2705 "8827": [0.0391, 0.5391, 0, 0, 0.77778], 2706 "8834": [0.0391, 0.5391, 0, 0, 0.77778], 2707 "8835": [0.0391, 0.5391, 0, 0, 0.77778], 2708 "8838": [0.13597, 0.63597, 0, 0, 0.77778], 2709 "8839": [0.13597, 0.63597, 0, 0, 0.77778], 2710 "8846": [0, 0.55556, 0, 0, 0.66667], 2711 "8849": [0.13597, 0.63597, 0, 0, 0.77778], 2712 "8850": [0.13597, 0.63597, 0, 0, 0.77778], 2713 "8851": [0, 0.55556, 0, 0, 0.66667], 2714 "8852": [0, 0.55556, 0, 0, 0.66667], 2715 "8853": [0.08333, 0.58333, 0, 0, 0.77778], 2716 "8854": [0.08333, 0.58333, 0, 0, 0.77778], 2717 "8855": [0.08333, 0.58333, 0, 0, 0.77778], 2718 "8856": [0.08333, 0.58333, 0, 0, 0.77778], 2719 "8857": [0.08333, 0.58333, 0, 0, 0.77778], 2720 "8866": [0, 0.69444, 0, 0, 0.61111], 2721 "8867": [0, 0.69444, 0, 0, 0.61111], 2722 "8868": [0, 0.69444, 0, 0, 0.77778], 2723 "8869": [0, 0.69444, 0, 0, 0.77778], 2724 "8872": [0.249, 0.75, 0, 0, 0.867], 2725 "8900": [-0.05555, 0.44445, 0, 0, 0.5], 2726 "8901": [-0.05555, 0.44445, 0, 0, 0.27778], 2727 "8902": [-0.03472, 0.46528, 0, 0, 0.5], 2728 "8904": [0.005, 0.505, 0, 0, 0.9], 2729 "8942": [0.03, 0.9, 0, 0, 0.278], 2730 "8943": [-0.19, 0.31, 0, 0, 1.172], 2731 "8945": [-0.1, 0.82, 0, 0, 1.282], 2732 "8968": [0.25, 0.75, 0, 0, 0.44445], 2733 "8969": [0.25, 0.75, 0, 0, 0.44445], 2734 "8970": [0.25, 0.75, 0, 0, 0.44445], 2735 "8971": [0.25, 0.75, 0, 0, 0.44445], 2736 "8994": [-0.14236, 0.35764, 0, 0, 1.0], 2737 "8995": [-0.14236, 0.35764, 0, 0, 1.0], 2738 "9136": [0.244, 0.744, 0, 0, 0.412], 2739 "9137": [0.244, 0.744, 0, 0, 0.412], 2740 "9651": [0.19444, 0.69444, 0, 0, 0.88889], 2741 "9657": [-0.03472, 0.46528, 0, 0, 0.5], 2742 "9661": [0.19444, 0.69444, 0, 0, 0.88889], 2743 "9667": [-0.03472, 0.46528, 0, 0, 0.5], 2744 "9711": [0.19444, 0.69444, 0, 0, 1.0], 2745 "9824": [0.12963, 0.69444, 0, 0, 0.77778], 2746 "9825": [0.12963, 0.69444, 0, 0, 0.77778], 2747 "9826": [0.12963, 0.69444, 0, 0, 0.77778], 2748 "9827": [0.12963, 0.69444, 0, 0, 0.77778], 2749 "9837": [0, 0.75, 0, 0, 0.38889], 2750 "9838": [0.19444, 0.69444, 0, 0, 0.38889], 2751 "9839": [0.19444, 0.69444, 0, 0, 0.38889], 2752 "10216": [0.25, 0.75, 0, 0, 0.38889], 2753 "10217": [0.25, 0.75, 0, 0, 0.38889], 2754 "10222": [0.244, 0.744, 0, 0, 0.412], 2755 "10223": [0.244, 0.744, 0, 0, 0.412], 2756 "10229": [0.011, 0.511, 0, 0, 1.609], 2757 "10230": [0.011, 0.511, 0, 0, 1.638], 2758 "10231": [0.011, 0.511, 0, 0, 1.859], 2759 "10232": [0.024, 0.525, 0, 0, 1.609], 2760 "10233": [0.024, 0.525, 0, 0, 1.638], 2761 "10234": [0.024, 0.525, 0, 0, 1.858], 2762 "10236": [0.011, 0.511, 0, 0, 1.638], 2763 "10815": [0, 0.68333, 0, 0, 0.75], 2764 "10927": [0.13597, 0.63597, 0, 0, 0.77778], 2765 "10928": [0.13597, 0.63597, 0, 0, 0.77778], 2766 "57376": [0.19444, 0.69444, 0, 0, 0] 2767 }, 2768 "Math-BoldItalic": { 2769 "65": [0, 0.68611, 0, 0, 0.86944], 2770 "66": [0, 0.68611, 0.04835, 0, 0.8664], 2771 "67": [0, 0.68611, 0.06979, 0, 0.81694], 2772 "68": [0, 0.68611, 0.03194, 0, 0.93812], 2773 "69": [0, 0.68611, 0.05451, 0, 0.81007], 2774 "70": [0, 0.68611, 0.15972, 0, 0.68889], 2775 "71": [0, 0.68611, 0, 0, 0.88673], 2776 "72": [0, 0.68611, 0.08229, 0, 0.98229], 2777 "73": [0, 0.68611, 0.07778, 0, 0.51111], 2778 "74": [0, 0.68611, 0.10069, 0, 0.63125], 2779 "75": [0, 0.68611, 0.06979, 0, 0.97118], 2780 "76": [0, 0.68611, 0, 0, 0.75555], 2781 "77": [0, 0.68611, 0.11424, 0, 1.14201], 2782 "78": [0, 0.68611, 0.11424, 0, 0.95034], 2783 "79": [0, 0.68611, 0.03194, 0, 0.83666], 2784 "80": [0, 0.68611, 0.15972, 0, 0.72309], 2785 "81": [0.19444, 0.68611, 0, 0, 0.86861], 2786 "82": [0, 0.68611, 0.00421, 0, 0.87235], 2787 "83": [0, 0.68611, 0.05382, 0, 0.69271], 2788 "84": [0, 0.68611, 0.15972, 0, 0.63663], 2789 "85": [0, 0.68611, 0.11424, 0, 0.80027], 2790 "86": [0, 0.68611, 0.25555, 0, 0.67778], 2791 "87": [0, 0.68611, 0.15972, 0, 1.09305], 2792 "88": [0, 0.68611, 0.07778, 0, 0.94722], 2793 "89": [0, 0.68611, 0.25555, 0, 0.67458], 2794 "90": [0, 0.68611, 0.06979, 0, 0.77257], 2795 "97": [0, 0.44444, 0, 0, 0.63287], 2796 "98": [0, 0.69444, 0, 0, 0.52083], 2797 "99": [0, 0.44444, 0, 0, 0.51342], 2798 "100": [0, 0.69444, 0, 0, 0.60972], 2799 "101": [0, 0.44444, 0, 0, 0.55361], 2800 "102": [0.19444, 0.69444, 0.11042, 0, 0.56806], 2801 "103": [0.19444, 0.44444, 0.03704, 0, 0.5449], 2802 "104": [0, 0.69444, 0, 0, 0.66759], 2803 "105": [0, 0.69326, 0, 0, 0.4048], 2804 "106": [0.19444, 0.69326, 0.0622, 0, 0.47083], 2805 "107": [0, 0.69444, 0.01852, 0, 0.6037], 2806 "108": [0, 0.69444, 0.0088, 0, 0.34815], 2807 "109": [0, 0.44444, 0, 0, 1.0324], 2808 "110": [0, 0.44444, 0, 0, 0.71296], 2809 "111": [0, 0.44444, 0, 0, 0.58472], 2810 "112": [0.19444, 0.44444, 0, 0, 0.60092], 2811 "113": [0.19444, 0.44444, 0.03704, 0, 0.54213], 2812 "114": [0, 0.44444, 0.03194, 0, 0.5287], 2813 "115": [0, 0.44444, 0, 0, 0.53125], 2814 "116": [0, 0.63492, 0, 0, 0.41528], 2815 "117": [0, 0.44444, 0, 0, 0.68102], 2816 "118": [0, 0.44444, 0.03704, 0, 0.56666], 2817 "119": [0, 0.44444, 0.02778, 0, 0.83148], 2818 "120": [0, 0.44444, 0, 0, 0.65903], 2819 "121": [0.19444, 0.44444, 0.03704, 0, 0.59028], 2820 "122": [0, 0.44444, 0.04213, 0, 0.55509], 2821 "915": [0, 0.68611, 0.15972, 0, 0.65694], 2822 "916": [0, 0.68611, 0, 0, 0.95833], 2823 "920": [0, 0.68611, 0.03194, 0, 0.86722], 2824 "923": [0, 0.68611, 0, 0, 0.80555], 2825 "926": [0, 0.68611, 0.07458, 0, 0.84125], 2826 "928": [0, 0.68611, 0.08229, 0, 0.98229], 2827 "931": [0, 0.68611, 0.05451, 0, 0.88507], 2828 "933": [0, 0.68611, 0.15972, 0, 0.67083], 2829 "934": [0, 0.68611, 0, 0, 0.76666], 2830 "936": [0, 0.68611, 0.11653, 0, 0.71402], 2831 "937": [0, 0.68611, 0.04835, 0, 0.8789], 2832 "945": [0, 0.44444, 0, 0, 0.76064], 2833 "946": [0.19444, 0.69444, 0.03403, 0, 0.65972], 2834 "947": [0.19444, 0.44444, 0.06389, 0, 0.59003], 2835 "948": [0, 0.69444, 0.03819, 0, 0.52222], 2836 "949": [0, 0.44444, 0, 0, 0.52882], 2837 "950": [0.19444, 0.69444, 0.06215, 0, 0.50833], 2838 "951": [0.19444, 0.44444, 0.03704, 0, 0.6], 2839 "952": [0, 0.69444, 0.03194, 0, 0.5618], 2840 "953": [0, 0.44444, 0, 0, 0.41204], 2841 "954": [0, 0.44444, 0, 0, 0.66759], 2842 "955": [0, 0.69444, 0, 0, 0.67083], 2843 "956": [0.19444, 0.44444, 0, 0, 0.70787], 2844 "957": [0, 0.44444, 0.06898, 0, 0.57685], 2845 "958": [0.19444, 0.69444, 0.03021, 0, 0.50833], 2846 "959": [0, 0.44444, 0, 0, 0.58472], 2847 "960": [0, 0.44444, 0.03704, 0, 0.68241], 2848 "961": [0.19444, 0.44444, 0, 0, 0.6118], 2849 "962": [0.09722, 0.44444, 0.07917, 0, 0.42361], 2850 "963": [0, 0.44444, 0.03704, 0, 0.68588], 2851 "964": [0, 0.44444, 0.13472, 0, 0.52083], 2852 "965": [0, 0.44444, 0.03704, 0, 0.63055], 2853 "966": [0.19444, 0.44444, 0, 0, 0.74722], 2854 "967": [0.19444, 0.44444, 0, 0, 0.71805], 2855 "968": [0.19444, 0.69444, 0.03704, 0, 0.75833], 2856 "969": [0, 0.44444, 0.03704, 0, 0.71782], 2857 "977": [0, 0.69444, 0, 0, 0.69155], 2858 "981": [0.19444, 0.69444, 0, 0, 0.7125], 2859 "982": [0, 0.44444, 0.03194, 0, 0.975], 2860 "1009": [0.19444, 0.44444, 0, 0, 0.6118], 2861 "1013": [0, 0.44444, 0, 0, 0.48333] 2862 }, 2863 "Math-Italic": { 2864 "65": [0, 0.68333, 0, 0.13889, 0.75], 2865 "66": [0, 0.68333, 0.05017, 0.08334, 0.75851], 2866 "67": [0, 0.68333, 0.07153, 0.08334, 0.71472], 2867 "68": [0, 0.68333, 0.02778, 0.05556, 0.82792], 2868 "69": [0, 0.68333, 0.05764, 0.08334, 0.7382], 2869 "70": [0, 0.68333, 0.13889, 0.08334, 0.64306], 2870 "71": [0, 0.68333, 0, 0.08334, 0.78625], 2871 "72": [0, 0.68333, 0.08125, 0.05556, 0.83125], 2872 "73": [0, 0.68333, 0.07847, 0.11111, 0.43958], 2873 "74": [0, 0.68333, 0.09618, 0.16667, 0.55451], 2874 "75": [0, 0.68333, 0.07153, 0.05556, 0.84931], 2875 "76": [0, 0.68333, 0, 0.02778, 0.68056], 2876 "77": [0, 0.68333, 0.10903, 0.08334, 0.97014], 2877 "78": [0, 0.68333, 0.10903, 0.08334, 0.80347], 2878 "79": [0, 0.68333, 0.02778, 0.08334, 0.76278], 2879 "80": [0, 0.68333, 0.13889, 0.08334, 0.64201], 2880 "81": [0.19444, 0.68333, 0, 0.08334, 0.79056], 2881 "82": [0, 0.68333, 0.00773, 0.08334, 0.75929], 2882 "83": [0, 0.68333, 0.05764, 0.08334, 0.6132], 2883 "84": [0, 0.68333, 0.13889, 0.08334, 0.58438], 2884 "85": [0, 0.68333, 0.10903, 0.02778, 0.68278], 2885 "86": [0, 0.68333, 0.22222, 0, 0.58333], 2886 "87": [0, 0.68333, 0.13889, 0, 0.94445], 2887 "88": [0, 0.68333, 0.07847, 0.08334, 0.82847], 2888 "89": [0, 0.68333, 0.22222, 0, 0.58056], 2889 "90": [0, 0.68333, 0.07153, 0.08334, 0.68264], 2890 "97": [0, 0.43056, 0, 0, 0.52859], 2891 "98": [0, 0.69444, 0, 0, 0.42917], 2892 "99": [0, 0.43056, 0, 0.05556, 0.43276], 2893 "100": [0, 0.69444, 0, 0.16667, 0.52049], 2894 "101": [0, 0.43056, 0, 0.05556, 0.46563], 2895 "102": [0.19444, 0.69444, 0.10764, 0.16667, 0.48959], 2896 "103": [0.19444, 0.43056, 0.03588, 0.02778, 0.47697], 2897 "104": [0, 0.69444, 0, 0, 0.57616], 2898 "105": [0, 0.65952, 0, 0, 0.34451], 2899 "106": [0.19444, 0.65952, 0.05724, 0, 0.41181], 2900 "107": [0, 0.69444, 0.03148, 0, 0.5206], 2901 "108": [0, 0.69444, 0.01968, 0.08334, 0.29838], 2902 "109": [0, 0.43056, 0, 0, 0.87801], 2903 "110": [0, 0.43056, 0, 0, 0.60023], 2904 "111": [0, 0.43056, 0, 0.05556, 0.48472], 2905 "112": [0.19444, 0.43056, 0, 0.08334, 0.50313], 2906 "113": [0.19444, 0.43056, 0.03588, 0.08334, 0.44641], 2907 "114": [0, 0.43056, 0.02778, 0.05556, 0.45116], 2908 "115": [0, 0.43056, 0, 0.05556, 0.46875], 2909 "116": [0, 0.61508, 0, 0.08334, 0.36111], 2910 "117": [0, 0.43056, 0, 0.02778, 0.57246], 2911 "118": [0, 0.43056, 0.03588, 0.02778, 0.48472], 2912 "119": [0, 0.43056, 0.02691, 0.08334, 0.71592], 2913 "120": [0, 0.43056, 0, 0.02778, 0.57153], 2914 "121": [0.19444, 0.43056, 0.03588, 0.05556, 0.49028], 2915 "122": [0, 0.43056, 0.04398, 0.05556, 0.46505], 2916 "915": [0, 0.68333, 0.13889, 0.08334, 0.61528], 2917 "916": [0, 0.68333, 0, 0.16667, 0.83334], 2918 "920": [0, 0.68333, 0.02778, 0.08334, 0.76278], 2919 "923": [0, 0.68333, 0, 0.16667, 0.69445], 2920 "926": [0, 0.68333, 0.07569, 0.08334, 0.74236], 2921 "928": [0, 0.68333, 0.08125, 0.05556, 0.83125], 2922 "931": [0, 0.68333, 0.05764, 0.08334, 0.77986], 2923 "933": [0, 0.68333, 0.13889, 0.05556, 0.58333], 2924 "934": [0, 0.68333, 0, 0.08334, 0.66667], 2925 "936": [0, 0.68333, 0.11, 0.05556, 0.61222], 2926 "937": [0, 0.68333, 0.05017, 0.08334, 0.7724], 2927 "945": [0, 0.43056, 0.0037, 0.02778, 0.6397], 2928 "946": [0.19444, 0.69444, 0.05278, 0.08334, 0.56563], 2929 "947": [0.19444, 0.43056, 0.05556, 0, 0.51773], 2930 "948": [0, 0.69444, 0.03785, 0.05556, 0.44444], 2931 "949": [0, 0.43056, 0, 0.08334, 0.46632], 2932 "950": [0.19444, 0.69444, 0.07378, 0.08334, 0.4375], 2933 "951": [0.19444, 0.43056, 0.03588, 0.05556, 0.49653], 2934 "952": [0, 0.69444, 0.02778, 0.08334, 0.46944], 2935 "953": [0, 0.43056, 0, 0.05556, 0.35394], 2936 "954": [0, 0.43056, 0, 0, 0.57616], 2937 "955": [0, 0.69444, 0, 0, 0.58334], 2938 "956": [0.19444, 0.43056, 0, 0.02778, 0.60255], 2939 "957": [0, 0.43056, 0.06366, 0.02778, 0.49398], 2940 "958": [0.19444, 0.69444, 0.04601, 0.11111, 0.4375], 2941 "959": [0, 0.43056, 0, 0.05556, 0.48472], 2942 "960": [0, 0.43056, 0.03588, 0, 0.57003], 2943 "961": [0.19444, 0.43056, 0, 0.08334, 0.51702], 2944 "962": [0.09722, 0.43056, 0.07986, 0.08334, 0.36285], 2945 "963": [0, 0.43056, 0.03588, 0, 0.57141], 2946 "964": [0, 0.43056, 0.1132, 0.02778, 0.43715], 2947 "965": [0, 0.43056, 0.03588, 0.02778, 0.54028], 2948 "966": [0.19444, 0.43056, 0, 0.08334, 0.65417], 2949 "967": [0.19444, 0.43056, 0, 0.05556, 0.62569], 2950 "968": [0.19444, 0.69444, 0.03588, 0.11111, 0.65139], 2951 "969": [0, 0.43056, 0.03588, 0, 0.62245], 2952 "977": [0, 0.69444, 0, 0.08334, 0.59144], 2953 "981": [0.19444, 0.69444, 0, 0.08334, 0.59583], 2954 "982": [0, 0.43056, 0.02778, 0, 0.82813], 2955 "1009": [0.19444, 0.43056, 0, 0.08334, 0.51702], 2956 "1013": [0, 0.43056, 0, 0.05556, 0.4059] 2957 }, 2958 "Math-Regular": { 2959 "65": [0, 0.68333, 0, 0.13889, 0.75], 2960 "66": [0, 0.68333, 0.05017, 0.08334, 0.75851], 2961 "67": [0, 0.68333, 0.07153, 0.08334, 0.71472], 2962 "68": [0, 0.68333, 0.02778, 0.05556, 0.82792], 2963 "69": [0, 0.68333, 0.05764, 0.08334, 0.7382], 2964 "70": [0, 0.68333, 0.13889, 0.08334, 0.64306], 2965 "71": [0, 0.68333, 0, 0.08334, 0.78625], 2966 "72": [0, 0.68333, 0.08125, 0.05556, 0.83125], 2967 "73": [0, 0.68333, 0.07847, 0.11111, 0.43958], 2968 "74": [0, 0.68333, 0.09618, 0.16667, 0.55451], 2969 "75": [0, 0.68333, 0.07153, 0.05556, 0.84931], 2970 "76": [0, 0.68333, 0, 0.02778, 0.68056], 2971 "77": [0, 0.68333, 0.10903, 0.08334, 0.97014], 2972 "78": [0, 0.68333, 0.10903, 0.08334, 0.80347], 2973 "79": [0, 0.68333, 0.02778, 0.08334, 0.76278], 2974 "80": [0, 0.68333, 0.13889, 0.08334, 0.64201], 2975 "81": [0.19444, 0.68333, 0, 0.08334, 0.79056], 2976 "82": [0, 0.68333, 0.00773, 0.08334, 0.75929], 2977 "83": [0, 0.68333, 0.05764, 0.08334, 0.6132], 2978 "84": [0, 0.68333, 0.13889, 0.08334, 0.58438], 2979 "85": [0, 0.68333, 0.10903, 0.02778, 0.68278], 2980 "86": [0, 0.68333, 0.22222, 0, 0.58333], 2981 "87": [0, 0.68333, 0.13889, 0, 0.94445], 2982 "88": [0, 0.68333, 0.07847, 0.08334, 0.82847], 2983 "89": [0, 0.68333, 0.22222, 0, 0.58056], 2984 "90": [0, 0.68333, 0.07153, 0.08334, 0.68264], 2985 "97": [0, 0.43056, 0, 0, 0.52859], 2986 "98": [0, 0.69444, 0, 0, 0.42917], 2987 "99": [0, 0.43056, 0, 0.05556, 0.43276], 2988 "100": [0, 0.69444, 0, 0.16667, 0.52049], 2989 "101": [0, 0.43056, 0, 0.05556, 0.46563], 2990 "102": [0.19444, 0.69444, 0.10764, 0.16667, 0.48959], 2991 "103": [0.19444, 0.43056, 0.03588, 0.02778, 0.47697], 2992 "104": [0, 0.69444, 0, 0, 0.57616], 2993 "105": [0, 0.65952, 0, 0, 0.34451], 2994 "106": [0.19444, 0.65952, 0.05724, 0, 0.41181], 2995 "107": [0, 0.69444, 0.03148, 0, 0.5206], 2996 "108": [0, 0.69444, 0.01968, 0.08334, 0.29838], 2997 "109": [0, 0.43056, 0, 0, 0.87801], 2998 "110": [0, 0.43056, 0, 0, 0.60023], 2999 "111": [0, 0.43056, 0, 0.05556, 0.48472], 3000 "112": [0.19444, 0.43056, 0, 0.08334, 0.50313], 3001 "113": [0.19444, 0.43056, 0.03588, 0.08334, 0.44641], 3002 "114": [0, 0.43056, 0.02778, 0.05556, 0.45116], 3003 "115": [0, 0.43056, 0, 0.05556, 0.46875], 3004 "116": [0, 0.61508, 0, 0.08334, 0.36111], 3005 "117": [0, 0.43056, 0, 0.02778, 0.57246], 3006 "118": [0, 0.43056, 0.03588, 0.02778, 0.48472], 3007 "119": [0, 0.43056, 0.02691, 0.08334, 0.71592], 3008 "120": [0, 0.43056, 0, 0.02778, 0.57153], 3009 "121": [0.19444, 0.43056, 0.03588, 0.05556, 0.49028], 3010 "122": [0, 0.43056, 0.04398, 0.05556, 0.46505], 3011 "915": [0, 0.68333, 0.13889, 0.08334, 0.61528], 3012 "916": [0, 0.68333, 0, 0.16667, 0.83334], 3013 "920": [0, 0.68333, 0.02778, 0.08334, 0.76278], 3014 "923": [0, 0.68333, 0, 0.16667, 0.69445], 3015 "926": [0, 0.68333, 0.07569, 0.08334, 0.74236], 3016 "928": [0, 0.68333, 0.08125, 0.05556, 0.83125], 3017 "931": [0, 0.68333, 0.05764, 0.08334, 0.77986], 3018 "933": [0, 0.68333, 0.13889, 0.05556, 0.58333], 3019 "934": [0, 0.68333, 0, 0.08334, 0.66667], 3020 "936": [0, 0.68333, 0.11, 0.05556, 0.61222], 3021 "937": [0, 0.68333, 0.05017, 0.08334, 0.7724], 3022 "945": [0, 0.43056, 0.0037, 0.02778, 0.6397], 3023 "946": [0.19444, 0.69444, 0.05278, 0.08334, 0.56563], 3024 "947": [0.19444, 0.43056, 0.05556, 0, 0.51773], 3025 "948": [0, 0.69444, 0.03785, 0.05556, 0.44444], 3026 "949": [0, 0.43056, 0, 0.08334, 0.46632], 3027 "950": [0.19444, 0.69444, 0.07378, 0.08334, 0.4375], 3028 "951": [0.19444, 0.43056, 0.03588, 0.05556, 0.49653], 3029 "952": [0, 0.69444, 0.02778, 0.08334, 0.46944], 3030 "953": [0, 0.43056, 0, 0.05556, 0.35394], 3031 "954": [0, 0.43056, 0, 0, 0.57616], 3032 "955": [0, 0.69444, 0, 0, 0.58334], 3033 "956": [0.19444, 0.43056, 0, 0.02778, 0.60255], 3034 "957": [0, 0.43056, 0.06366, 0.02778, 0.49398], 3035 "958": [0.19444, 0.69444, 0.04601, 0.11111, 0.4375], 3036 "959": [0, 0.43056, 0, 0.05556, 0.48472], 3037 "960": [0, 0.43056, 0.03588, 0, 0.57003], 3038 "961": [0.19444, 0.43056, 0, 0.08334, 0.51702], 3039 "962": [0.09722, 0.43056, 0.07986, 0.08334, 0.36285], 3040 "963": [0, 0.43056, 0.03588, 0, 0.57141], 3041 "964": [0, 0.43056, 0.1132, 0.02778, 0.43715], 3042 "965": [0, 0.43056, 0.03588, 0.02778, 0.54028], 3043 "966": [0.19444, 0.43056, 0, 0.08334, 0.65417], 3044 "967": [0.19444, 0.43056, 0, 0.05556, 0.62569], 3045 "968": [0.19444, 0.69444, 0.03588, 0.11111, 0.65139], 3046 "969": [0, 0.43056, 0.03588, 0, 0.62245], 3047 "977": [0, 0.69444, 0, 0.08334, 0.59144], 3048 "981": [0.19444, 0.69444, 0, 0.08334, 0.59583], 3049 "982": [0, 0.43056, 0.02778, 0, 0.82813], 3050 "1009": [0.19444, 0.43056, 0, 0.08334, 0.51702], 3051 "1013": [0, 0.43056, 0, 0.05556, 0.4059] 3052 }, 3053 "SansSerif-Bold": { 3054 "33": [0, 0.69444, 0, 0, 0.36667], 3055 "34": [0, 0.69444, 0, 0, 0.55834], 3056 "35": [0.19444, 0.69444, 0, 0, 0.91667], 3057 "36": [0.05556, 0.75, 0, 0, 0.55], 3058 "37": [0.05556, 0.75, 0, 0, 1.02912], 3059 "38": [0, 0.69444, 0, 0, 0.83056], 3060 "39": [0, 0.69444, 0, 0, 0.30556], 3061 "40": [0.25, 0.75, 0, 0, 0.42778], 3062 "41": [0.25, 0.75, 0, 0, 0.42778], 3063 "42": [0, 0.75, 0, 0, 0.55], 3064 "43": [0.11667, 0.61667, 0, 0, 0.85556], 3065 "44": [0.10556, 0.13056, 0, 0, 0.30556], 3066 "45": [0, 0.45833, 0, 0, 0.36667], 3067 "46": [0, 0.13056, 0, 0, 0.30556], 3068 "47": [0.25, 0.75, 0, 0, 0.55], 3069 "48": [0, 0.69444, 0, 0, 0.55], 3070 "49": [0, 0.69444, 0, 0, 0.55], 3071 "50": [0, 0.69444, 0, 0, 0.55], 3072 "51": [0, 0.69444, 0, 0, 0.55], 3073 "52": [0, 0.69444, 0, 0, 0.55], 3074 "53": [0, 0.69444, 0, 0, 0.55], 3075 "54": [0, 0.69444, 0, 0, 0.55], 3076 "55": [0, 0.69444, 0, 0, 0.55], 3077 "56": [0, 0.69444, 0, 0, 0.55], 3078 "57": [0, 0.69444, 0, 0, 0.55], 3079 "58": [0, 0.45833, 0, 0, 0.30556], 3080 "59": [0.10556, 0.45833, 0, 0, 0.30556], 3081 "61": [-0.09375, 0.40625, 0, 0, 0.85556], 3082 "63": [0, 0.69444, 0, 0, 0.51945], 3083 "64": [0, 0.69444, 0, 0, 0.73334], 3084 "65": [0, 0.69444, 0, 0, 0.73334], 3085 "66": [0, 0.69444, 0, 0, 0.73334], 3086 "67": [0, 0.69444, 0, 0, 0.70278], 3087 "68": [0, 0.69444, 0, 0, 0.79445], 3088 "69": [0, 0.69444, 0, 0, 0.64167], 3089 "70": [0, 0.69444, 0, 0, 0.61111], 3090 "71": [0, 0.69444, 0, 0, 0.73334], 3091 "72": [0, 0.69444, 0, 0, 0.79445], 3092 "73": [0, 0.69444, 0, 0, 0.33056], 3093 "74": [0, 0.69444, 0, 0, 0.51945], 3094 "75": [0, 0.69444, 0, 0, 0.76389], 3095 "76": [0, 0.69444, 0, 0, 0.58056], 3096 "77": [0, 0.69444, 0, 0, 0.97778], 3097 "78": [0, 0.69444, 0, 0, 0.79445], 3098 "79": [0, 0.69444, 0, 0, 0.79445], 3099 "80": [0, 0.69444, 0, 0, 0.70278], 3100 "81": [0.10556, 0.69444, 0, 0, 0.79445], 3101 "82": [0, 0.69444, 0, 0, 0.70278], 3102 "83": [0, 0.69444, 0, 0, 0.61111], 3103 "84": [0, 0.69444, 0, 0, 0.73334], 3104 "85": [0, 0.69444, 0, 0, 0.76389], 3105 "86": [0, 0.69444, 0.01528, 0, 0.73334], 3106 "87": [0, 0.69444, 0.01528, 0, 1.03889], 3107 "88": [0, 0.69444, 0, 0, 0.73334], 3108 "89": [0, 0.69444, 0.0275, 0, 0.73334], 3109 "90": [0, 0.69444, 0, 0, 0.67223], 3110 "91": [0.25, 0.75, 0, 0, 0.34306], 3111 "93": [0.25, 0.75, 0, 0, 0.34306], 3112 "94": [0, 0.69444, 0, 0, 0.55], 3113 "95": [0.35, 0.10833, 0.03056, 0, 0.55], 3114 "97": [0, 0.45833, 0, 0, 0.525], 3115 "98": [0, 0.69444, 0, 0, 0.56111], 3116 "99": [0, 0.45833, 0, 0, 0.48889], 3117 "100": [0, 0.69444, 0, 0, 0.56111], 3118 "101": [0, 0.45833, 0, 0, 0.51111], 3119 "102": [0, 0.69444, 0.07639, 0, 0.33611], 3120 "103": [0.19444, 0.45833, 0.01528, 0, 0.55], 3121 "104": [0, 0.69444, 0, 0, 0.56111], 3122 "105": [0, 0.69444, 0, 0, 0.25556], 3123 "106": [0.19444, 0.69444, 0, 0, 0.28611], 3124 "107": [0, 0.69444, 0, 0, 0.53056], 3125 "108": [0, 0.69444, 0, 0, 0.25556], 3126 "109": [0, 0.45833, 0, 0, 0.86667], 3127 "110": [0, 0.45833, 0, 0, 0.56111], 3128 "111": [0, 0.45833, 0, 0, 0.55], 3129 "112": [0.19444, 0.45833, 0, 0, 0.56111], 3130 "113": [0.19444, 0.45833, 0, 0, 0.56111], 3131 "114": [0, 0.45833, 0.01528, 0, 0.37222], 3132 "115": [0, 0.45833, 0, 0, 0.42167], 3133 "116": [0, 0.58929, 0, 0, 0.40417], 3134 "117": [0, 0.45833, 0, 0, 0.56111], 3135 "118": [0, 0.45833, 0.01528, 0, 0.5], 3136 "119": [0, 0.45833, 0.01528, 0, 0.74445], 3137 "120": [0, 0.45833, 0, 0, 0.5], 3138 "121": [0.19444, 0.45833, 0.01528, 0, 0.5], 3139 "122": [0, 0.45833, 0, 0, 0.47639], 3140 "126": [0.35, 0.34444, 0, 0, 0.55], 3141 "168": [0, 0.69444, 0, 0, 0.55], 3142 "176": [0, 0.69444, 0, 0, 0.73334], 3143 "180": [0, 0.69444, 0, 0, 0.55], 3144 "184": [0.17014, 0, 0, 0, 0.48889], 3145 "305": [0, 0.45833, 0, 0, 0.25556], 3146 "567": [0.19444, 0.45833, 0, 0, 0.28611], 3147 "710": [0, 0.69444, 0, 0, 0.55], 3148 "711": [0, 0.63542, 0, 0, 0.55], 3149 "713": [0, 0.63778, 0, 0, 0.55], 3150 "728": [0, 0.69444, 0, 0, 0.55], 3151 "729": [0, 0.69444, 0, 0, 0.30556], 3152 "730": [0, 0.69444, 0, 0, 0.73334], 3153 "732": [0, 0.69444, 0, 0, 0.55], 3154 "733": [0, 0.69444, 0, 0, 0.55], 3155 "915": [0, 0.69444, 0, 0, 0.58056], 3156 "916": [0, 0.69444, 0, 0, 0.91667], 3157 "920": [0, 0.69444, 0, 0, 0.85556], 3158 "923": [0, 0.69444, 0, 0, 0.67223], 3159 "926": [0, 0.69444, 0, 0, 0.73334], 3160 "928": [0, 0.69444, 0, 0, 0.79445], 3161 "931": [0, 0.69444, 0, 0, 0.79445], 3162 "933": [0, 0.69444, 0, 0, 0.85556], 3163 "934": [0, 0.69444, 0, 0, 0.79445], 3164 "936": [0, 0.69444, 0, 0, 0.85556], 3165 "937": [0, 0.69444, 0, 0, 0.79445], 3166 "8211": [0, 0.45833, 0.03056, 0, 0.55], 3167 "8212": [0, 0.45833, 0.03056, 0, 1.10001], 3168 "8216": [0, 0.69444, 0, 0, 0.30556], 3169 "8217": [0, 0.69444, 0, 0, 0.30556], 3170 "8220": [0, 0.69444, 0, 0, 0.55834], 3171 "8221": [0, 0.69444, 0, 0, 0.55834] 3172 }, 3173 "SansSerif-Italic": { 3174 "33": [0, 0.69444, 0.05733, 0, 0.31945], 3175 "34": [0, 0.69444, 0.00316, 0, 0.5], 3176 "35": [0.19444, 0.69444, 0.05087, 0, 0.83334], 3177 "36": [0.05556, 0.75, 0.11156, 0, 0.5], 3178 "37": [0.05556, 0.75, 0.03126, 0, 0.83334], 3179 "38": [0, 0.69444, 0.03058, 0, 0.75834], 3180 "39": [0, 0.69444, 0.07816, 0, 0.27778], 3181 "40": [0.25, 0.75, 0.13164, 0, 0.38889], 3182 "41": [0.25, 0.75, 0.02536, 0, 0.38889], 3183 "42": [0, 0.75, 0.11775, 0, 0.5], 3184 "43": [0.08333, 0.58333, 0.02536, 0, 0.77778], 3185 "44": [0.125, 0.08333, 0, 0, 0.27778], 3186 "45": [0, 0.44444, 0.01946, 0, 0.33333], 3187 "46": [0, 0.08333, 0, 0, 0.27778], 3188 "47": [0.25, 0.75, 0.13164, 0, 0.5], 3189 "48": [0, 0.65556, 0.11156, 0, 0.5], 3190 "49": [0, 0.65556, 0.11156, 0, 0.5], 3191 "50": [0, 0.65556, 0.11156, 0, 0.5], 3192 "51": [0, 0.65556, 0.11156, 0, 0.5], 3193 "52": [0, 0.65556, 0.11156, 0, 0.5], 3194 "53": [0, 0.65556, 0.11156, 0, 0.5], 3195 "54": [0, 0.65556, 0.11156, 0, 0.5], 3196 "55": [0, 0.65556, 0.11156, 0, 0.5], 3197 "56": [0, 0.65556, 0.11156, 0, 0.5], 3198 "57": [0, 0.65556, 0.11156, 0, 0.5], 3199 "58": [0, 0.44444, 0.02502, 0, 0.27778], 3200 "59": [0.125, 0.44444, 0.02502, 0, 0.27778], 3201 "61": [-0.13, 0.37, 0.05087, 0, 0.77778], 3202 "63": [0, 0.69444, 0.11809, 0, 0.47222], 3203 "64": [0, 0.69444, 0.07555, 0, 0.66667], 3204 "65": [0, 0.69444, 0, 0, 0.66667], 3205 "66": [0, 0.69444, 0.08293, 0, 0.66667], 3206 "67": [0, 0.69444, 0.11983, 0, 0.63889], 3207 "68": [0, 0.69444, 0.07555, 0, 0.72223], 3208 "69": [0, 0.69444, 0.11983, 0, 0.59722], 3209 "70": [0, 0.69444, 0.13372, 0, 0.56945], 3210 "71": [0, 0.69444, 0.11983, 0, 0.66667], 3211 "72": [0, 0.69444, 0.08094, 0, 0.70834], 3212 "73": [0, 0.69444, 0.13372, 0, 0.27778], 3213 "74": [0, 0.69444, 0.08094, 0, 0.47222], 3214 "75": [0, 0.69444, 0.11983, 0, 0.69445], 3215 "76": [0, 0.69444, 0, 0, 0.54167], 3216 "77": [0, 0.69444, 0.08094, 0, 0.875], 3217 "78": [0, 0.69444, 0.08094, 0, 0.70834], 3218 "79": [0, 0.69444, 0.07555, 0, 0.73611], 3219 "80": [0, 0.69444, 0.08293, 0, 0.63889], 3220 "81": [0.125, 0.69444, 0.07555, 0, 0.73611], 3221 "82": [0, 0.69444, 0.08293, 0, 0.64584], 3222 "83": [0, 0.69444, 0.09205, 0, 0.55556], 3223 "84": [0, 0.69444, 0.13372, 0, 0.68056], 3224 "85": [0, 0.69444, 0.08094, 0, 0.6875], 3225 "86": [0, 0.69444, 0.1615, 0, 0.66667], 3226 "87": [0, 0.69444, 0.1615, 0, 0.94445], 3227 "88": [0, 0.69444, 0.13372, 0, 0.66667], 3228 "89": [0, 0.69444, 0.17261, 0, 0.66667], 3229 "90": [0, 0.69444, 0.11983, 0, 0.61111], 3230 "91": [0.25, 0.75, 0.15942, 0, 0.28889], 3231 "93": [0.25, 0.75, 0.08719, 0, 0.28889], 3232 "94": [0, 0.69444, 0.0799, 0, 0.5], 3233 "95": [0.35, 0.09444, 0.08616, 0, 0.5], 3234 "97": [0, 0.44444, 0.00981, 0, 0.48056], 3235 "98": [0, 0.69444, 0.03057, 0, 0.51667], 3236 "99": [0, 0.44444, 0.08336, 0, 0.44445], 3237 "100": [0, 0.69444, 0.09483, 0, 0.51667], 3238 "101": [0, 0.44444, 0.06778, 0, 0.44445], 3239 "102": [0, 0.69444, 0.21705, 0, 0.30556], 3240 "103": [0.19444, 0.44444, 0.10836, 0, 0.5], 3241 "104": [0, 0.69444, 0.01778, 0, 0.51667], 3242 "105": [0, 0.67937, 0.09718, 0, 0.23889], 3243 "106": [0.19444, 0.67937, 0.09162, 0, 0.26667], 3244 "107": [0, 0.69444, 0.08336, 0, 0.48889], 3245 "108": [0, 0.69444, 0.09483, 0, 0.23889], 3246 "109": [0, 0.44444, 0.01778, 0, 0.79445], 3247 "110": [0, 0.44444, 0.01778, 0, 0.51667], 3248 "111": [0, 0.44444, 0.06613, 0, 0.5], 3249 "112": [0.19444, 0.44444, 0.0389, 0, 0.51667], 3250 "113": [0.19444, 0.44444, 0.04169, 0, 0.51667], 3251 "114": [0, 0.44444, 0.10836, 0, 0.34167], 3252 "115": [0, 0.44444, 0.0778, 0, 0.38333], 3253 "116": [0, 0.57143, 0.07225, 0, 0.36111], 3254 "117": [0, 0.44444, 0.04169, 0, 0.51667], 3255 "118": [0, 0.44444, 0.10836, 0, 0.46111], 3256 "119": [0, 0.44444, 0.10836, 0, 0.68334], 3257 "120": [0, 0.44444, 0.09169, 0, 0.46111], 3258 "121": [0.19444, 0.44444, 0.10836, 0, 0.46111], 3259 "122": [0, 0.44444, 0.08752, 0, 0.43472], 3260 "126": [0.35, 0.32659, 0.08826, 0, 0.5], 3261 "168": [0, 0.67937, 0.06385, 0, 0.5], 3262 "176": [0, 0.69444, 0, 0, 0.73752], 3263 "184": [0.17014, 0, 0, 0, 0.44445], 3264 "305": [0, 0.44444, 0.04169, 0, 0.23889], 3265 "567": [0.19444, 0.44444, 0.04169, 0, 0.26667], 3266 "710": [0, 0.69444, 0.0799, 0, 0.5], 3267 "711": [0, 0.63194, 0.08432, 0, 0.5], 3268 "713": [0, 0.60889, 0.08776, 0, 0.5], 3269 "714": [0, 0.69444, 0.09205, 0, 0.5], 3270 "715": [0, 0.69444, 0, 0, 0.5], 3271 "728": [0, 0.69444, 0.09483, 0, 0.5], 3272 "729": [0, 0.67937, 0.07774, 0, 0.27778], 3273 "730": [0, 0.69444, 0, 0, 0.73752], 3274 "732": [0, 0.67659, 0.08826, 0, 0.5], 3275 "733": [0, 0.69444, 0.09205, 0, 0.5], 3276 "915": [0, 0.69444, 0.13372, 0, 0.54167], 3277 "916": [0, 0.69444, 0, 0, 0.83334], 3278 "920": [0, 0.69444, 0.07555, 0, 0.77778], 3279 "923": [0, 0.69444, 0, 0, 0.61111], 3280 "926": [0, 0.69444, 0.12816, 0, 0.66667], 3281 "928": [0, 0.69444, 0.08094, 0, 0.70834], 3282 "931": [0, 0.69444, 0.11983, 0, 0.72222], 3283 "933": [0, 0.69444, 0.09031, 0, 0.77778], 3284 "934": [0, 0.69444, 0.04603, 0, 0.72222], 3285 "936": [0, 0.69444, 0.09031, 0, 0.77778], 3286 "937": [0, 0.69444, 0.08293, 0, 0.72222], 3287 "8211": [0, 0.44444, 0.08616, 0, 0.5], 3288 "8212": [0, 0.44444, 0.08616, 0, 1.0], 3289 "8216": [0, 0.69444, 0.07816, 0, 0.27778], 3290 "8217": [0, 0.69444, 0.07816, 0, 0.27778], 3291 "8220": [0, 0.69444, 0.14205, 0, 0.5], 3292 "8221": [0, 0.69444, 0.00316, 0, 0.5] 3293 }, 3294 "SansSerif-Regular": { 3295 "33": [0, 0.69444, 0, 0, 0.31945], 3296 "34": [0, 0.69444, 0, 0, 0.5], 3297 "35": [0.19444, 0.69444, 0, 0, 0.83334], 3298 "36": [0.05556, 0.75, 0, 0, 0.5], 3299 "37": [0.05556, 0.75, 0, 0, 0.83334], 3300 "38": [0, 0.69444, 0, 0, 0.75834], 3301 "39": [0, 0.69444, 0, 0, 0.27778], 3302 "40": [0.25, 0.75, 0, 0, 0.38889], 3303 "41": [0.25, 0.75, 0, 0, 0.38889], 3304 "42": [0, 0.75, 0, 0, 0.5], 3305 "43": [0.08333, 0.58333, 0, 0, 0.77778], 3306 "44": [0.125, 0.08333, 0, 0, 0.27778], 3307 "45": [0, 0.44444, 0, 0, 0.33333], 3308 "46": [0, 0.08333, 0, 0, 0.27778], 3309 "47": [0.25, 0.75, 0, 0, 0.5], 3310 "48": [0, 0.65556, 0, 0, 0.5], 3311 "49": [0, 0.65556, 0, 0, 0.5], 3312 "50": [0, 0.65556, 0, 0, 0.5], 3313 "51": [0, 0.65556, 0, 0, 0.5], 3314 "52": [0, 0.65556, 0, 0, 0.5], 3315 "53": [0, 0.65556, 0, 0, 0.5], 3316 "54": [0, 0.65556, 0, 0, 0.5], 3317 "55": [0, 0.65556, 0, 0, 0.5], 3318 "56": [0, 0.65556, 0, 0, 0.5], 3319 "57": [0, 0.65556, 0, 0, 0.5], 3320 "58": [0, 0.44444, 0, 0, 0.27778], 3321 "59": [0.125, 0.44444, 0, 0, 0.27778], 3322 "61": [-0.13, 0.37, 0, 0, 0.77778], 3323 "63": [0, 0.69444, 0, 0, 0.47222], 3324 "64": [0, 0.69444, 0, 0, 0.66667], 3325 "65": [0, 0.69444, 0, 0, 0.66667], 3326 "66": [0, 0.69444, 0, 0, 0.66667], 3327 "67": [0, 0.69444, 0, 0, 0.63889], 3328 "68": [0, 0.69444, 0, 0, 0.72223], 3329 "69": [0, 0.69444, 0, 0, 0.59722], 3330 "70": [0, 0.69444, 0, 0, 0.56945], 3331 "71": [0, 0.69444, 0, 0, 0.66667], 3332 "72": [0, 0.69444, 0, 0, 0.70834], 3333 "73": [0, 0.69444, 0, 0, 0.27778], 3334 "74": [0, 0.69444, 0, 0, 0.47222], 3335 "75": [0, 0.69444, 0, 0, 0.69445], 3336 "76": [0, 0.69444, 0, 0, 0.54167], 3337 "77": [0, 0.69444, 0, 0, 0.875], 3338 "78": [0, 0.69444, 0, 0, 0.70834], 3339 "79": [0, 0.69444, 0, 0, 0.73611], 3340 "80": [0, 0.69444, 0, 0, 0.63889], 3341 "81": [0.125, 0.69444, 0, 0, 0.73611], 3342 "82": [0, 0.69444, 0, 0, 0.64584], 3343 "83": [0, 0.69444, 0, 0, 0.55556], 3344 "84": [0, 0.69444, 0, 0, 0.68056], 3345 "85": [0, 0.69444, 0, 0, 0.6875], 3346 "86": [0, 0.69444, 0.01389, 0, 0.66667], 3347 "87": [0, 0.69444, 0.01389, 0, 0.94445], 3348 "88": [0, 0.69444, 0, 0, 0.66667], 3349 "89": [0, 0.69444, 0.025, 0, 0.66667], 3350 "90": [0, 0.69444, 0, 0, 0.61111], 3351 "91": [0.25, 0.75, 0, 0, 0.28889], 3352 "93": [0.25, 0.75, 0, 0, 0.28889], 3353 "94": [0, 0.69444, 0, 0, 0.5], 3354 "95": [0.35, 0.09444, 0.02778, 0, 0.5], 3355 "97": [0, 0.44444, 0, 0, 0.48056], 3356 "98": [0, 0.69444, 0, 0, 0.51667], 3357 "99": [0, 0.44444, 0, 0, 0.44445], 3358 "100": [0, 0.69444, 0, 0, 0.51667], 3359 "101": [0, 0.44444, 0, 0, 0.44445], 3360 "102": [0, 0.69444, 0.06944, 0, 0.30556], 3361 "103": [0.19444, 0.44444, 0.01389, 0, 0.5], 3362 "104": [0, 0.69444, 0, 0, 0.51667], 3363 "105": [0, 0.67937, 0, 0, 0.23889], 3364 "106": [0.19444, 0.67937, 0, 0, 0.26667], 3365 "107": [0, 0.69444, 0, 0, 0.48889], 3366 "108": [0, 0.69444, 0, 0, 0.23889], 3367 "109": [0, 0.44444, 0, 0, 0.79445], 3368 "110": [0, 0.44444, 0, 0, 0.51667], 3369 "111": [0, 0.44444, 0, 0, 0.5], 3370 "112": [0.19444, 0.44444, 0, 0, 0.51667], 3371 "113": [0.19444, 0.44444, 0, 0, 0.51667], 3372 "114": [0, 0.44444, 0.01389, 0, 0.34167], 3373 "115": [0, 0.44444, 0, 0, 0.38333], 3374 "116": [0, 0.57143, 0, 0, 0.36111], 3375 "117": [0, 0.44444, 0, 0, 0.51667], 3376 "118": [0, 0.44444, 0.01389, 0, 0.46111], 3377 "119": [0, 0.44444, 0.01389, 0, 0.68334], 3378 "120": [0, 0.44444, 0, 0, 0.46111], 3379 "121": [0.19444, 0.44444, 0.01389, 0, 0.46111], 3380 "122": [0, 0.44444, 0, 0, 0.43472], 3381 "126": [0.35, 0.32659, 0, 0, 0.5], 3382 "168": [0, 0.67937, 0, 0, 0.5], 3383 "176": [0, 0.69444, 0, 0, 0.66667], 3384 "184": [0.17014, 0, 0, 0, 0.44445], 3385 "305": [0, 0.44444, 0, 0, 0.23889], 3386 "567": [0.19444, 0.44444, 0, 0, 0.26667], 3387 "710": [0, 0.69444, 0, 0, 0.5], 3388 "711": [0, 0.63194, 0, 0, 0.5], 3389 "713": [0, 0.60889, 0, 0, 0.5], 3390 "714": [0, 0.69444, 0, 0, 0.5], 3391 "715": [0, 0.69444, 0, 0, 0.5], 3392 "728": [0, 0.69444, 0, 0, 0.5], 3393 "729": [0, 0.67937, 0, 0, 0.27778], 3394 "730": [0, 0.69444, 0, 0, 0.66667], 3395 "732": [0, 0.67659, 0, 0, 0.5], 3396 "733": [0, 0.69444, 0, 0, 0.5], 3397 "915": [0, 0.69444, 0, 0, 0.54167], 3398 "916": [0, 0.69444, 0, 0, 0.83334], 3399 "920": [0, 0.69444, 0, 0, 0.77778], 3400 "923": [0, 0.69444, 0, 0, 0.61111], 3401 "926": [0, 0.69444, 0, 0, 0.66667], 3402 "928": [0, 0.69444, 0, 0, 0.70834], 3403 "931": [0, 0.69444, 0, 0, 0.72222], 3404 "933": [0, 0.69444, 0, 0, 0.77778], 3405 "934": [0, 0.69444, 0, 0, 0.72222], 3406 "936": [0, 0.69444, 0, 0, 0.77778], 3407 "937": [0, 0.69444, 0, 0, 0.72222], 3408 "8211": [0, 0.44444, 0.02778, 0, 0.5], 3409 "8212": [0, 0.44444, 0.02778, 0, 1.0], 3410 "8216": [0, 0.69444, 0, 0, 0.27778], 3411 "8217": [0, 0.69444, 0, 0, 0.27778], 3412 "8220": [0, 0.69444, 0, 0, 0.5], 3413 "8221": [0, 0.69444, 0, 0, 0.5] 3414 }, 3415 "Script-Regular": { 3416 "65": [0, 0.7, 0.22925, 0, 0.80253], 3417 "66": [0, 0.7, 0.04087, 0, 0.90757], 3418 "67": [0, 0.7, 0.1689, 0, 0.66619], 3419 "68": [0, 0.7, 0.09371, 0, 0.77443], 3420 "69": [0, 0.7, 0.18583, 0, 0.56162], 3421 "70": [0, 0.7, 0.13634, 0, 0.89544], 3422 "71": [0, 0.7, 0.17322, 0, 0.60961], 3423 "72": [0, 0.7, 0.29694, 0, 0.96919], 3424 "73": [0, 0.7, 0.19189, 0, 0.80907], 3425 "74": [0.27778, 0.7, 0.19189, 0, 1.05159], 3426 "75": [0, 0.7, 0.31259, 0, 0.91364], 3427 "76": [0, 0.7, 0.19189, 0, 0.87373], 3428 "77": [0, 0.7, 0.15981, 0, 1.08031], 3429 "78": [0, 0.7, 0.3525, 0, 0.9015], 3430 "79": [0, 0.7, 0.08078, 0, 0.73787], 3431 "80": [0, 0.7, 0.08078, 0, 1.01262], 3432 "81": [0, 0.7, 0.03305, 0, 0.88282], 3433 "82": [0, 0.7, 0.06259, 0, 0.85], 3434 "83": [0, 0.7, 0.19189, 0, 0.86767], 3435 "84": [0, 0.7, 0.29087, 0, 0.74697], 3436 "85": [0, 0.7, 0.25815, 0, 0.79996], 3437 "86": [0, 0.7, 0.27523, 0, 0.62204], 3438 "87": [0, 0.7, 0.27523, 0, 0.80532], 3439 "88": [0, 0.7, 0.26006, 0, 0.94445], 3440 "89": [0, 0.7, 0.2939, 0, 0.70961], 3441 "90": [0, 0.7, 0.24037, 0, 0.8212] 3442 }, 3443 "Size1-Regular": { 3444 "40": [0.35001, 0.85, 0, 0, 0.45834], 3445 "41": [0.35001, 0.85, 0, 0, 0.45834], 3446 "47": [0.35001, 0.85, 0, 0, 0.57778], 3447 "91": [0.35001, 0.85, 0, 0, 0.41667], 3448 "92": [0.35001, 0.85, 0, 0, 0.57778], 3449 "93": [0.35001, 0.85, 0, 0, 0.41667], 3450 "123": [0.35001, 0.85, 0, 0, 0.58334], 3451 "125": [0.35001, 0.85, 0, 0, 0.58334], 3452 "710": [0, 0.72222, 0, 0, 0.55556], 3453 "732": [0, 0.72222, 0, 0, 0.55556], 3454 "770": [0, 0.72222, 0, 0, 0.55556], 3455 "771": [0, 0.72222, 0, 0, 0.55556], 3456 "8214": [-0.00099, 0.601, 0, 0, 0.77778], 3457 "8593": [1e-05, 0.6, 0, 0, 0.66667], 3458 "8595": [1e-05, 0.6, 0, 0, 0.66667], 3459 "8657": [1e-05, 0.6, 0, 0, 0.77778], 3460 "8659": [1e-05, 0.6, 0, 0, 0.77778], 3461 "8719": [0.25001, 0.75, 0, 0, 0.94445], 3462 "8720": [0.25001, 0.75, 0, 0, 0.94445], 3463 "8721": [0.25001, 0.75, 0, 0, 1.05556], 3464 "8730": [0.35001, 0.85, 0, 0, 1.0], 3465 "8739": [-0.00599, 0.606, 0, 0, 0.33333], 3466 "8741": [-0.00599, 0.606, 0, 0, 0.55556], 3467 "8747": [0.30612, 0.805, 0.19445, 0, 0.47222], 3468 "8748": [0.306, 0.805, 0.19445, 0, 0.47222], 3469 "8749": [0.306, 0.805, 0.19445, 0, 0.47222], 3470 "8750": [0.30612, 0.805, 0.19445, 0, 0.47222], 3471 "8896": [0.25001, 0.75, 0, 0, 0.83334], 3472 "8897": [0.25001, 0.75, 0, 0, 0.83334], 3473 "8898": [0.25001, 0.75, 0, 0, 0.83334], 3474 "8899": [0.25001, 0.75, 0, 0, 0.83334], 3475 "8968": [0.35001, 0.85, 0, 0, 0.47222], 3476 "8969": [0.35001, 0.85, 0, 0, 0.47222], 3477 "8970": [0.35001, 0.85, 0, 0, 0.47222], 3478 "8971": [0.35001, 0.85, 0, 0, 0.47222], 3479 "9168": [-0.00099, 0.601, 0, 0, 0.66667], 3480 "10216": [0.35001, 0.85, 0, 0, 0.47222], 3481 "10217": [0.35001, 0.85, 0, 0, 0.47222], 3482 "10752": [0.25001, 0.75, 0, 0, 1.11111], 3483 "10753": [0.25001, 0.75, 0, 0, 1.11111], 3484 "10754": [0.25001, 0.75, 0, 0, 1.11111], 3485 "10756": [0.25001, 0.75, 0, 0, 0.83334], 3486 "10758": [0.25001, 0.75, 0, 0, 0.83334] 3487 }, 3488 "Size2-Regular": { 3489 "40": [0.65002, 1.15, 0, 0, 0.59722], 3490 "41": [0.65002, 1.15, 0, 0, 0.59722], 3491 "47": [0.65002, 1.15, 0, 0, 0.81111], 3492 "91": [0.65002, 1.15, 0, 0, 0.47222], 3493 "92": [0.65002, 1.15, 0, 0, 0.81111], 3494 "93": [0.65002, 1.15, 0, 0, 0.47222], 3495 "123": [0.65002, 1.15, 0, 0, 0.66667], 3496 "125": [0.65002, 1.15, 0, 0, 0.66667], 3497 "710": [0, 0.75, 0, 0, 1.0], 3498 "732": [0, 0.75, 0, 0, 1.0], 3499 "770": [0, 0.75, 0, 0, 1.0], 3500 "771": [0, 0.75, 0, 0, 1.0], 3501 "8719": [0.55001, 1.05, 0, 0, 1.27778], 3502 "8720": [0.55001, 1.05, 0, 0, 1.27778], 3503 "8721": [0.55001, 1.05, 0, 0, 1.44445], 3504 "8730": [0.65002, 1.15, 0, 0, 1.0], 3505 "8747": [0.86225, 1.36, 0.44445, 0, 0.55556], 3506 "8748": [0.862, 1.36, 0.44445, 0, 0.55556], 3507 "8749": [0.862, 1.36, 0.44445, 0, 0.55556], 3508 "8750": [0.86225, 1.36, 0.44445, 0, 0.55556], 3509 "8896": [0.55001, 1.05, 0, 0, 1.11111], 3510 "8897": [0.55001, 1.05, 0, 0, 1.11111], 3511 "8898": [0.55001, 1.05, 0, 0, 1.11111], 3512 "8899": [0.55001, 1.05, 0, 0, 1.11111], 3513 "8968": [0.65002, 1.15, 0, 0, 0.52778], 3514 "8969": [0.65002, 1.15, 0, 0, 0.52778], 3515 "8970": [0.65002, 1.15, 0, 0, 0.52778], 3516 "8971": [0.65002, 1.15, 0, 0, 0.52778], 3517 "10216": [0.65002, 1.15, 0, 0, 0.61111], 3518 "10217": [0.65002, 1.15, 0, 0, 0.61111], 3519 "10752": [0.55001, 1.05, 0, 0, 1.51112], 3520 "10753": [0.55001, 1.05, 0, 0, 1.51112], 3521 "10754": [0.55001, 1.05, 0, 0, 1.51112], 3522 "10756": [0.55001, 1.05, 0, 0, 1.11111], 3523 "10758": [0.55001, 1.05, 0, 0, 1.11111] 3524 }, 3525 "Size3-Regular": { 3526 "40": [0.95003, 1.45, 0, 0, 0.73611], 3527 "41": [0.95003, 1.45, 0, 0, 0.73611], 3528 "47": [0.95003, 1.45, 0, 0, 1.04445], 3529 "91": [0.95003, 1.45, 0, 0, 0.52778], 3530 "92": [0.95003, 1.45, 0, 0, 1.04445], 3531 "93": [0.95003, 1.45, 0, 0, 0.52778], 3532 "123": [0.95003, 1.45, 0, 0, 0.75], 3533 "125": [0.95003, 1.45, 0, 0, 0.75], 3534 "710": [0, 0.75, 0, 0, 1.44445], 3535 "732": [0, 0.75, 0, 0, 1.44445], 3536 "770": [0, 0.75, 0, 0, 1.44445], 3537 "771": [0, 0.75, 0, 0, 1.44445], 3538 "8730": [0.95003, 1.45, 0, 0, 1.0], 3539 "8968": [0.95003, 1.45, 0, 0, 0.58334], 3540 "8969": [0.95003, 1.45, 0, 0, 0.58334], 3541 "8970": [0.95003, 1.45, 0, 0, 0.58334], 3542 "8971": [0.95003, 1.45, 0, 0, 0.58334], 3543 "10216": [0.95003, 1.45, 0, 0, 0.75], 3544 "10217": [0.95003, 1.45, 0, 0, 0.75] 3545 }, 3546 "Size4-Regular": { 3547 "40": [1.25003, 1.75, 0, 0, 0.79167], 3548 "41": [1.25003, 1.75, 0, 0, 0.79167], 3549 "47": [1.25003, 1.75, 0, 0, 1.27778], 3550 "91": [1.25003, 1.75, 0, 0, 0.58334], 3551 "92": [1.25003, 1.75, 0, 0, 1.27778], 3552 "93": [1.25003, 1.75, 0, 0, 0.58334], 3553 "123": [1.25003, 1.75, 0, 0, 0.80556], 3554 "125": [1.25003, 1.75, 0, 0, 0.80556], 3555 "710": [0, 0.825, 0, 0, 1.8889], 3556 "732": [0, 0.825, 0, 0, 1.8889], 3557 "770": [0, 0.825, 0, 0, 1.8889], 3558 "771": [0, 0.825, 0, 0, 1.8889], 3559 "8730": [1.25003, 1.75, 0, 0, 1.0], 3560 "8968": [1.25003, 1.75, 0, 0, 0.63889], 3561 "8969": [1.25003, 1.75, 0, 0, 0.63889], 3562 "8970": [1.25003, 1.75, 0, 0, 0.63889], 3563 "8971": [1.25003, 1.75, 0, 0, 0.63889], 3564 "9115": [0.64502, 1.155, 0, 0, 0.875], 3565 "9116": [1e-05, 0.6, 0, 0, 0.875], 3566 "9117": [0.64502, 1.155, 0, 0, 0.875], 3567 "9118": [0.64502, 1.155, 0, 0, 0.875], 3568 "9119": [1e-05, 0.6, 0, 0, 0.875], 3569 "9120": [0.64502, 1.155, 0, 0, 0.875], 3570 "9121": [0.64502, 1.155, 0, 0, 0.66667], 3571 "9122": [-0.00099, 0.601, 0, 0, 0.66667], 3572 "9123": [0.64502, 1.155, 0, 0, 0.66667], 3573 "9124": [0.64502, 1.155, 0, 0, 0.66667], 3574 "9125": [-0.00099, 0.601, 0, 0, 0.66667], 3575 "9126": [0.64502, 1.155, 0, 0, 0.66667], 3576 "9127": [1e-05, 0.9, 0, 0, 0.88889], 3577 "9128": [0.65002, 1.15, 0, 0, 0.88889], 3578 "9129": [0.90001, 0, 0, 0, 0.88889], 3579 "9130": [0, 0.3, 0, 0, 0.88889], 3580 "9131": [1e-05, 0.9, 0, 0, 0.88889], 3581 "9132": [0.65002, 1.15, 0, 0, 0.88889], 3582 "9133": [0.90001, 0, 0, 0, 0.88889], 3583 "9143": [0.88502, 0.915, 0, 0, 1.05556], 3584 "10216": [1.25003, 1.75, 0, 0, 0.80556], 3585 "10217": [1.25003, 1.75, 0, 0, 0.80556], 3586 "57344": [-0.00499, 0.605, 0, 0, 1.05556], 3587 "57345": [-0.00499, 0.605, 0, 0, 1.05556], 3588 "57680": [0, 0.12, 0, 0, 0.45], 3589 "57681": [0, 0.12, 0, 0, 0.45], 3590 "57682": [0, 0.12, 0, 0, 0.45], 3591 "57683": [0, 0.12, 0, 0, 0.45] 3592 }, 3593 "Typewriter-Regular": { 3594 "32": [0, 0, 0, 0, 0.525], 3595 "33": [0, 0.61111, 0, 0, 0.525], 3596 "34": [0, 0.61111, 0, 0, 0.525], 3597 "35": [0, 0.61111, 0, 0, 0.525], 3598 "36": [0.08333, 0.69444, 0, 0, 0.525], 3599 "37": [0.08333, 0.69444, 0, 0, 0.525], 3600 "38": [0, 0.61111, 0, 0, 0.525], 3601 "39": [0, 0.61111, 0, 0, 0.525], 3602 "40": [0.08333, 0.69444, 0, 0, 0.525], 3603 "41": [0.08333, 0.69444, 0, 0, 0.525], 3604 "42": [0, 0.52083, 0, 0, 0.525], 3605 "43": [-0.08056, 0.53055, 0, 0, 0.525], 3606 "44": [0.13889, 0.125, 0, 0, 0.525], 3607 "45": [-0.08056, 0.53055, 0, 0, 0.525], 3608 "46": [0, 0.125, 0, 0, 0.525], 3609 "47": [0.08333, 0.69444, 0, 0, 0.525], 3610 "48": [0, 0.61111, 0, 0, 0.525], 3611 "49": [0, 0.61111, 0, 0, 0.525], 3612 "50": [0, 0.61111, 0, 0, 0.525], 3613 "51": [0, 0.61111, 0, 0, 0.525], 3614 "52": [0, 0.61111, 0, 0, 0.525], 3615 "53": [0, 0.61111, 0, 0, 0.525], 3616 "54": [0, 0.61111, 0, 0, 0.525], 3617 "55": [0, 0.61111, 0, 0, 0.525], 3618 "56": [0, 0.61111, 0, 0, 0.525], 3619 "57": [0, 0.61111, 0, 0, 0.525], 3620 "58": [0, 0.43056, 0, 0, 0.525], 3621 "59": [0.13889, 0.43056, 0, 0, 0.525], 3622 "60": [-0.05556, 0.55556, 0, 0, 0.525], 3623 "61": [-0.19549, 0.41562, 0, 0, 0.525], 3624 "62": [-0.05556, 0.55556, 0, 0, 0.525], 3625 "63": [0, 0.61111, 0, 0, 0.525], 3626 "64": [0, 0.61111, 0, 0, 0.525], 3627 "65": [0, 0.61111, 0, 0, 0.525], 3628 "66": [0, 0.61111, 0, 0, 0.525], 3629 "67": [0, 0.61111, 0, 0, 0.525], 3630 "68": [0, 0.61111, 0, 0, 0.525], 3631 "69": [0, 0.61111, 0, 0, 0.525], 3632 "70": [0, 0.61111, 0, 0, 0.525], 3633 "71": [0, 0.61111, 0, 0, 0.525], 3634 "72": [0, 0.61111, 0, 0, 0.525], 3635 "73": [0, 0.61111, 0, 0, 0.525], 3636 "74": [0, 0.61111, 0, 0, 0.525], 3637 "75": [0, 0.61111, 0, 0, 0.525], 3638 "76": [0, 0.61111, 0, 0, 0.525], 3639 "77": [0, 0.61111, 0, 0, 0.525], 3640 "78": [0, 0.61111, 0, 0, 0.525], 3641 "79": [0, 0.61111, 0, 0, 0.525], 3642 "80": [0, 0.61111, 0, 0, 0.525], 3643 "81": [0.13889, 0.61111, 0, 0, 0.525], 3644 "82": [0, 0.61111, 0, 0, 0.525], 3645 "83": [0, 0.61111, 0, 0, 0.525], 3646 "84": [0, 0.61111, 0, 0, 0.525], 3647 "85": [0, 0.61111, 0, 0, 0.525], 3648 "86": [0, 0.61111, 0, 0, 0.525], 3649 "87": [0, 0.61111, 0, 0, 0.525], 3650 "88": [0, 0.61111, 0, 0, 0.525], 3651 "89": [0, 0.61111, 0, 0, 0.525], 3652 "90": [0, 0.61111, 0, 0, 0.525], 3653 "91": [0.08333, 0.69444, 0, 0, 0.525], 3654 "92": [0.08333, 0.69444, 0, 0, 0.525], 3655 "93": [0.08333, 0.69444, 0, 0, 0.525], 3656 "94": [0, 0.61111, 0, 0, 0.525], 3657 "95": [0.09514, 0, 0, 0, 0.525], 3658 "96": [0, 0.61111, 0, 0, 0.525], 3659 "97": [0, 0.43056, 0, 0, 0.525], 3660 "98": [0, 0.61111, 0, 0, 0.525], 3661 "99": [0, 0.43056, 0, 0, 0.525], 3662 "100": [0, 0.61111, 0, 0, 0.525], 3663 "101": [0, 0.43056, 0, 0, 0.525], 3664 "102": [0, 0.61111, 0, 0, 0.525], 3665 "103": [0.22222, 0.43056, 0, 0, 0.525], 3666 "104": [0, 0.61111, 0, 0, 0.525], 3667 "105": [0, 0.61111, 0, 0, 0.525], 3668 "106": [0.22222, 0.61111, 0, 0, 0.525], 3669 "107": [0, 0.61111, 0, 0, 0.525], 3670 "108": [0, 0.61111, 0, 0, 0.525], 3671 "109": [0, 0.43056, 0, 0, 0.525], 3672 "110": [0, 0.43056, 0, 0, 0.525], 3673 "111": [0, 0.43056, 0, 0, 0.525], 3674 "112": [0.22222, 0.43056, 0, 0, 0.525], 3675 "113": [0.22222, 0.43056, 0, 0, 0.525], 3676 "114": [0, 0.43056, 0, 0, 0.525], 3677 "115": [0, 0.43056, 0, 0, 0.525], 3678 "116": [0, 0.55358, 0, 0, 0.525], 3679 "117": [0, 0.43056, 0, 0, 0.525], 3680 "118": [0, 0.43056, 0, 0, 0.525], 3681 "119": [0, 0.43056, 0, 0, 0.525], 3682 "120": [0, 0.43056, 0, 0, 0.525], 3683 "121": [0.22222, 0.43056, 0, 0, 0.525], 3684 "122": [0, 0.43056, 0, 0, 0.525], 3685 "123": [0.08333, 0.69444, 0, 0, 0.525], 3686 "124": [0.08333, 0.69444, 0, 0, 0.525], 3687 "125": [0.08333, 0.69444, 0, 0, 0.525], 3688 "126": [0, 0.61111, 0, 0, 0.525], 3689 "127": [0, 0.61111, 0, 0, 0.525], 3690 "160": [0, 0, 0, 0, 0.525], 3691 "176": [0, 0.61111, 0, 0, 0.525], 3692 "184": [0.19445, 0, 0, 0, 0.525], 3693 "305": [0, 0.43056, 0, 0, 0.525], 3694 "567": [0.22222, 0.43056, 0, 0, 0.525], 3695 "711": [0, 0.56597, 0, 0, 0.525], 3696 "713": [0, 0.56555, 0, 0, 0.525], 3697 "714": [0, 0.61111, 0, 0, 0.525], 3698 "715": [0, 0.61111, 0, 0, 0.525], 3699 "728": [0, 0.61111, 0, 0, 0.525], 3700 "730": [0, 0.61111, 0, 0, 0.525], 3701 "770": [0, 0.61111, 0, 0, 0.525], 3702 "771": [0, 0.61111, 0, 0, 0.525], 3703 "776": [0, 0.61111, 0, 0, 0.525], 3704 "915": [0, 0.61111, 0, 0, 0.525], 3705 "916": [0, 0.61111, 0, 0, 0.525], 3706 "920": [0, 0.61111, 0, 0, 0.525], 3707 "923": [0, 0.61111, 0, 0, 0.525], 3708 "926": [0, 0.61111, 0, 0, 0.525], 3709 "928": [0, 0.61111, 0, 0, 0.525], 3710 "931": [0, 0.61111, 0, 0, 0.525], 3711 "933": [0, 0.61111, 0, 0, 0.525], 3712 "934": [0, 0.61111, 0, 0, 0.525], 3713 "936": [0, 0.61111, 0, 0, 0.525], 3714 "937": [0, 0.61111, 0, 0, 0.525], 3715 "8216": [0, 0.61111, 0, 0, 0.525], 3716 "8217": [0, 0.61111, 0, 0, 0.525], 3717 "8242": [0, 0.61111, 0, 0, 0.525], 3718 "9251": [0.11111, 0.21944, 0, 0, 0.525] 3719 } 3720}; 3721 3722/** 3723 * This file contains metrics regarding fonts and individual symbols. The sigma 3724 * and xi variables, as well as the metricMap map contain data extracted from 3725 * TeX, TeX font metrics, and the TTF files. These data are then exposed via the 3726 * `metrics` variable and the getCharacterMetrics function. 3727 */ 3728// In TeX, there are actually three sets of dimensions, one for each of 3729// textstyle (size index 5 and higher: >=9pt), scriptstyle (size index 3 and 4: 3730// 7-8pt), and scriptscriptstyle (size index 1 and 2: 5-6pt). These are 3731// provided in the the arrays below, in that order. 3732// 3733// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively. 3734// This was determined by running the following script: 3735// 3736// latex -interaction=nonstopmode \ 3737// '\documentclass{article}\usepackage{amsmath}\begin{document}' \ 3738// '$a$ \expandafter\show\the\textfont2' \ 3739// '\expandafter\show\the\scriptfont2' \ 3740// '\expandafter\show\the\scriptscriptfont2' \ 3741// '\stop' 3742// 3743// The metrics themselves were retreived using the following commands: 3744// 3745// tftopl cmsy10 3746// tftopl cmsy7 3747// tftopl cmsy5 3748// 3749// The output of each of these commands is quite lengthy. The only part we 3750// care about is the FONTDIMEN section. Each value is measured in EMs. 3751const sigmasAndXis = { 3752 slant: [0.250, 0.250, 0.250], 3753 // sigma1 3754 space: [0.000, 0.000, 0.000], 3755 // sigma2 3756 stretch: [0.000, 0.000, 0.000], 3757 // sigma3 3758 shrink: [0.000, 0.000, 0.000], 3759 // sigma4 3760 xHeight: [0.431, 0.431, 0.431], 3761 // sigma5 3762 quad: [1.000, 1.171, 1.472], 3763 // sigma6 3764 extraSpace: [0.000, 0.000, 0.000], 3765 // sigma7 3766 num1: [0.677, 0.732, 0.925], 3767 // sigma8 3768 num2: [0.394, 0.384, 0.387], 3769 // sigma9 3770 num3: [0.444, 0.471, 0.504], 3771 // sigma10 3772 denom1: [0.686, 0.752, 1.025], 3773 // sigma11 3774 denom2: [0.345, 0.344, 0.532], 3775 // sigma12 3776 sup1: [0.413, 0.503, 0.504], 3777 // sigma13 3778 sup2: [0.363, 0.431, 0.404], 3779 // sigma14 3780 sup3: [0.289, 0.286, 0.294], 3781 // sigma15 3782 sub1: [0.150, 0.143, 0.200], 3783 // sigma16 3784 sub2: [0.247, 0.286, 0.400], 3785 // sigma17 3786 supDrop: [0.386, 0.353, 0.494], 3787 // sigma18 3788 subDrop: [0.050, 0.071, 0.100], 3789 // sigma19 3790 delim1: [2.390, 1.700, 1.980], 3791 // sigma20 3792 delim2: [1.010, 1.157, 1.420], 3793 // sigma21 3794 axisHeight: [0.250, 0.250, 0.250], 3795 // sigma22 3796 // These font metrics are extracted from TeX by using tftopl on cmex10.tfm; 3797 // they correspond to the font parameters of the extension fonts (family 3). 3798 // See the TeXbook, page 441. In AMSTeX, the extension fonts scale; to 3799 // match cmex7, we'd use cmex7.tfm values for script and scriptscript 3800 // values. 3801 defaultRuleThickness: [0.04, 0.049, 0.049], 3802 // xi8; cmex7: 0.049 3803 bigOpSpacing1: [0.111, 0.111, 0.111], 3804 // xi9 3805 bigOpSpacing2: [0.166, 0.166, 0.166], 3806 // xi10 3807 bigOpSpacing3: [0.2, 0.2, 0.2], 3808 // xi11 3809 bigOpSpacing4: [0.6, 0.611, 0.611], 3810 // xi12; cmex7: 0.611 3811 bigOpSpacing5: [0.1, 0.143, 0.143], 3812 // xi13; cmex7: 0.143 3813 // The \sqrt rule width is taken from the height of the surd character. 3814 // Since we use the same font at all sizes, this thickness doesn't scale. 3815 sqrtRuleThickness: [0.04, 0.04, 0.04], 3816 // This value determines how large a pt is, for metrics which are defined 3817 // in terms of pts. 3818 // This value is also used in katex.less; if you change it make sure the 3819 // values match. 3820 ptPerEm: [10.0, 10.0, 10.0], 3821 // The space between adjacent `|` columns in an array definition. From 3822 // `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm. 3823 doubleRuleSep: [0.2, 0.2, 0.2], 3824 // The width of separator lines in {array} environments. From 3825 // `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm. 3826 arrayRuleWidth: [0.04, 0.04, 0.04], 3827 // Two values from LaTeX source2e: 3828 fboxsep: [0.3, 0.3, 0.3], 3829 // 3 pt / ptPerEm 3830 fboxrule: [0.04, 0.04, 0.04] // 0.4 pt / ptPerEm 3831 3832}; // This map contains a mapping from font name and character code to character 3833// should have Latin-1 and Cyrillic characters, but may not depending on the 3834// operating system. The metrics do not account for extra height from the 3835// accents. In the case of Cyrillic characters which have both ascenders and 3836// descenders we prefer approximations with ascenders, primarily to prevent 3837// the fraction bar or root line from intersecting the glyph. 3838// TODO(kevinb) allow union of multiple glyph metrics for better accuracy. 3839 3840const extraCharacterMap = { 3841 // Latin-1 3842 'Å': 'A', 3843 'Ç': 'C', 3844 'Ð': 'D', 3845 'Þ': 'o', 3846 'å': 'a', 3847 'ç': 'c', 3848 'ð': 'd', 3849 'þ': 'o', 3850 // Cyrillic 3851 'А': 'A', 3852 'Б': 'B', 3853 'В': 'B', 3854 'Г': 'F', 3855 'Д': 'A', 3856 'Е': 'E', 3857 'Ж': 'K', 3858 'З': '3', 3859 'И': 'N', 3860 'Й': 'N', 3861 'К': 'K', 3862 'Л': 'N', 3863 'М': 'M', 3864 'Н': 'H', 3865 'О': 'O', 3866 'П': 'N', 3867 'Р': 'P', 3868 'С': 'C', 3869 'Т': 'T', 3870 'У': 'y', 3871 'Ф': 'O', 3872 'Х': 'X', 3873 'Ц': 'U', 3874 'Ч': 'h', 3875 'Ш': 'W', 3876 'Щ': 'W', 3877 'Ъ': 'B', 3878 'Ы': 'X', 3879 'Ь': 'B', 3880 'Э': '3', 3881 'Ю': 'X', 3882 'Я': 'R', 3883 'а': 'a', 3884 'б': 'b', 3885 'в': 'a', 3886 'г': 'r', 3887 'д': 'y', 3888 'е': 'e', 3889 'ж': 'm', 3890 'з': 'e', 3891 'и': 'n', 3892 'й': 'n', 3893 'к': 'n', 3894 'л': 'n', 3895 'м': 'm', 3896 'н': 'n', 3897 'о': 'o', 3898 'п': 'n', 3899 'р': 'p', 3900 'с': 'c', 3901 'т': 'o', 3902 'у': 'y', 3903 'ф': 'b', 3904 'х': 'x', 3905 'ц': 'n', 3906 'ч': 'n', 3907 'ш': 'w', 3908 'щ': 'w', 3909 'ъ': 'a', 3910 'ы': 'm', 3911 'ь': 'a', 3912 'э': 'e', 3913 'ю': 'm', 3914 'я': 'r' 3915}; 3916 3917/** 3918 * This function adds new font metrics to default metricMap 3919 * It can also override existing metrics 3920 */ 3921function setFontMetrics(fontName, metrics) { 3922 metricMap[fontName] = metrics; 3923} 3924/** 3925 * This function is a convenience function for looking up information in the 3926 * metricMap table. It takes a character as a string, and a font. 3927 * 3928 * Note: the `width` property may be undefined if fontMetricsData.js wasn't 3929 * built using `Make extended_metrics`. 3930 */ 3931 3932function getCharacterMetrics(character, font, mode) { 3933 if (!metricMap[font]) { 3934 throw new Error(`Font metrics not found for font: ${font}.`); 3935 } 3936 3937 let ch = character.charCodeAt(0); 3938 let metrics = metricMap[font][ch]; 3939 3940 if (!metrics && character[0] in extraCharacterMap) { 3941 ch = extraCharacterMap[character[0]].charCodeAt(0); 3942 metrics = metricMap[font][ch]; 3943 } 3944 3945 if (!metrics && mode === 'text') { 3946 // We don't typically have font metrics for Asian scripts. 3947 // But since we support them in text mode, we need to return 3948 // some sort of metrics. 3949 // So if the character is in a script we support but we 3950 // don't have metrics for it, just use the metrics for 3951 // the Latin capital letter M. This is close enough because 3952 // we (currently) only care about the height of the glpyh 3953 // not its width. 3954 if (supportedCodepoint(ch)) { 3955 metrics = metricMap[font][77]; // 77 is the charcode for 'M' 3956 } 3957 } 3958 3959 if (metrics) { 3960 return { 3961 depth: metrics[0], 3962 height: metrics[1], 3963 italic: metrics[2], 3964 skew: metrics[3], 3965 width: metrics[4] 3966 }; 3967 } 3968} 3969const fontMetricsBySizeIndex = {}; 3970/** 3971 * Get the font metrics for a given size. 3972 */ 3973 3974function getGlobalMetrics(size) { 3975 let sizeIndex; 3976 3977 if (size >= 5) { 3978 sizeIndex = 0; 3979 } else if (size >= 3) { 3980 sizeIndex = 1; 3981 } else { 3982 sizeIndex = 2; 3983 } 3984 3985 if (!fontMetricsBySizeIndex[sizeIndex]) { 3986 const metrics = fontMetricsBySizeIndex[sizeIndex] = { 3987 cssEmPerMu: sigmasAndXis.quad[sizeIndex] / 18 3988 }; 3989 3990 for (const key in sigmasAndXis) { 3991 if (sigmasAndXis.hasOwnProperty(key)) { 3992 metrics[key] = sigmasAndXis[key][sizeIndex]; 3993 } 3994 } 3995 } 3996 3997 return fontMetricsBySizeIndex[sizeIndex]; 3998} 3999 4000/** 4001 * This file holds a list of all no-argument functions and single-character 4002 * symbols (like 'a' or ';'). 4003 * 4004 * For each of the symbols, there are three properties they can have: 4005 * - font (required): the font to be used for this symbol. Either "main" (the 4006 normal font), or "ams" (the ams fonts). 4007 * - group (required): the ParseNode group type the symbol should have (i.e. 4008 "textord", "mathord", etc). 4009 See https://github.com/KaTeX/KaTeX/wiki/Examining-TeX#group-types 4010 * - replace: the character that this symbol or function should be 4011 * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi 4012 * character in the main font). 4013 * 4014 * The outermost map in the table indicates what mode the symbols should be 4015 * accepted in (e.g. "math" or "text"). 4016 */ 4017// Some of these have a "-token" suffix since these are also used as `ParseNode` 4018// types for raw text tokens, and we want to avoid conflicts with higher-level 4019// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by 4020// looking up the `symbols` map. 4021const ATOMS = { 4022 "bin": 1, 4023 "close": 1, 4024 "inner": 1, 4025 "open": 1, 4026 "punct": 1, 4027 "rel": 1 4028}; 4029const NON_ATOMS = { 4030 "accent-token": 1, 4031 "mathord": 1, 4032 "op-token": 1, 4033 "spacing": 1, 4034 "textord": 1 4035}; 4036const symbols = { 4037 "math": {}, 4038 "text": {} 4039}; 4040/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ 4041 4042function defineSymbol(mode, font, group, replace, name, acceptUnicodeChar) { 4043 symbols[mode][name] = { 4044 font, 4045 group, 4046 replace 4047 }; 4048 4049 if (acceptUnicodeChar && replace) { 4050 symbols[mode][replace] = symbols[mode][name]; 4051 } 4052} // Some abbreviations for commonly used strings. 4053// This helps minify the code, and also spotting typos using jshint. 4054// modes: 4055 4056const math = "math"; 4057const text$1 = "text"; // fonts: 4058 4059const main = "main"; 4060const ams = "ams"; // groups: 4061 4062const accent = "accent-token"; 4063const bin = "bin"; 4064const close = "close"; 4065const inner = "inner"; 4066const mathord = "mathord"; 4067const op = "op-token"; 4068const open = "open"; 4069const punct = "punct"; 4070const rel = "rel"; 4071const spacing = "spacing"; 4072const textord = "textord"; // Now comes the symbol table 4073// Relation Symbols 4074 4075defineSymbol(math, main, rel, "\u2261", "\\equiv", true); 4076defineSymbol(math, main, rel, "\u227a", "\\prec", true); 4077defineSymbol(math, main, rel, "\u227b", "\\succ", true); 4078defineSymbol(math, main, rel, "\u223c", "\\sim", true); 4079defineSymbol(math, main, rel, "\u22a5", "\\perp"); 4080defineSymbol(math, main, rel, "\u2aaf", "\\preceq", true); 4081defineSymbol(math, main, rel, "\u2ab0", "\\succeq", true); 4082defineSymbol(math, main, rel, "\u2243", "\\simeq", true); 4083defineSymbol(math, main, rel, "\u2223", "\\mid", true); 4084defineSymbol(math, main, rel, "\u226a", "\\ll", true); 4085defineSymbol(math, main, rel, "\u226b", "\\gg", true); 4086defineSymbol(math, main, rel, "\u224d", "\\asymp", true); 4087defineSymbol(math, main, rel, "\u2225", "\\parallel"); 4088defineSymbol(math, main, rel, "\u22c8", "\\bowtie", true); 4089defineSymbol(math, main, rel, "\u2323", "\\smile", true); 4090defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq", true); 4091defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq", true); 4092defineSymbol(math, main, rel, "\u2250", "\\doteq", true); 4093defineSymbol(math, main, rel, "\u2322", "\\frown", true); 4094defineSymbol(math, main, rel, "\u220b", "\\ni", true); 4095defineSymbol(math, main, rel, "\u221d", "\\propto", true); 4096defineSymbol(math, main, rel, "\u22a2", "\\vdash", true); 4097defineSymbol(math, main, rel, "\u22a3", "\\dashv", true); 4098defineSymbol(math, main, rel, "\u220b", "\\owns"); // Punctuation 4099 4100defineSymbol(math, main, punct, "\u002e", "\\ldotp"); 4101defineSymbol(math, main, punct, "\u22c5", "\\cdotp"); // Misc Symbols 4102 4103defineSymbol(math, main, textord, "\u0023", "\\#"); 4104defineSymbol(text$1, main, textord, "\u0023", "\\#"); 4105defineSymbol(math, main, textord, "\u0026", "\\&"); 4106defineSymbol(text$1, main, textord, "\u0026", "\\&"); 4107defineSymbol(math, main, textord, "\u2135", "\\aleph", true); 4108defineSymbol(math, main, textord, "\u2200", "\\forall", true); 4109defineSymbol(math, main, textord, "\u210f", "\\hbar", true); 4110defineSymbol(math, main, textord, "\u2203", "\\exists", true); 4111defineSymbol(math, main, textord, "\u2207", "\\nabla", true); 4112defineSymbol(math, main, textord, "\u266d", "\\flat", true); 4113defineSymbol(math, main, textord, "\u2113", "\\ell", true); 4114defineSymbol(math, main, textord, "\u266e", "\\natural", true); 4115defineSymbol(math, main, textord, "\u2663", "\\clubsuit", true); 4116defineSymbol(math, main, textord, "\u2118", "\\wp", true); 4117defineSymbol(math, main, textord, "\u266f", "\\sharp", true); 4118defineSymbol(math, main, textord, "\u2662", "\\diamondsuit", true); 4119defineSymbol(math, main, textord, "\u211c", "\\Re", true); 4120defineSymbol(math, main, textord, "\u2661", "\\heartsuit", true); 4121defineSymbol(math, main, textord, "\u2111", "\\Im", true); 4122defineSymbol(math, main, textord, "\u2660", "\\spadesuit", true); 4123defineSymbol(text$1, main, textord, "\u00a7", "\\S", true); 4124defineSymbol(text$1, main, textord, "\u00b6", "\\P", true); // Math and Text 4125 4126defineSymbol(math, main, textord, "\u2020", "\\dag"); 4127defineSymbol(text$1, main, textord, "\u2020", "\\dag"); 4128defineSymbol(text$1, main, textord, "\u2020", "\\textdagger"); 4129defineSymbol(math, main, textord, "\u2021", "\\ddag"); 4130defineSymbol(text$1, main, textord, "\u2021", "\\ddag"); 4131defineSymbol(text$1, main, textord, "\u2021", "\\textdaggerdbl"); // Large Delimiters 4132 4133defineSymbol(math, main, close, "\u23b1", "\\rmoustache", true); 4134defineSymbol(math, main, open, "\u23b0", "\\lmoustache", true); 4135defineSymbol(math, main, close, "\u27ef", "\\rgroup", true); 4136defineSymbol(math, main, open, "\u27ee", "\\lgroup", true); // Binary Operators 4137 4138defineSymbol(math, main, bin, "\u2213", "\\mp", true); 4139defineSymbol(math, main, bin, "\u2296", "\\ominus", true); 4140defineSymbol(math, main, bin, "\u228e", "\\uplus", true); 4141defineSymbol(math, main, bin, "\u2293", "\\sqcap", true); 4142defineSymbol(math, main, bin, "\u2217", "\\ast"); 4143defineSymbol(math, main, bin, "\u2294", "\\sqcup", true); 4144defineSymbol(math, main, bin, "\u25ef", "\\bigcirc"); 4145defineSymbol(math, main, bin, "\u2219", "\\bullet"); 4146defineSymbol(math, main, bin, "\u2021", "\\ddagger"); 4147defineSymbol(math, main, bin, "\u2240", "\\wr", true); 4148defineSymbol(math, main, bin, "\u2a3f", "\\amalg"); 4149defineSymbol(math, main, bin, "\u0026", "\\And"); // from amsmath 4150// Arrow Symbols 4151 4152defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow", true); 4153defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow", true); 4154defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow", true); 4155defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow", true); 4156defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow", true); 4157defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow", true); 4158defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow", true); 4159defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow", true); 4160defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow", true); 4161defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow", true); 4162defineSymbol(math, main, rel, "\u21a6", "\\mapsto", true); 4163defineSymbol(math, main, rel, "\u27fc", "\\longmapsto", true); 4164defineSymbol(math, main, rel, "\u2197", "\\nearrow", true); 4165defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow", true); 4166defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow", true); 4167defineSymbol(math, main, rel, "\u2198", "\\searrow", true); 4168defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup", true); 4169defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup", true); 4170defineSymbol(math, main, rel, "\u2199", "\\swarrow", true); 4171defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown", true); 4172defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown", true); 4173defineSymbol(math, main, rel, "\u2196", "\\nwarrow", true); 4174defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons", true); // AMS Negated Binary Relations 4175 4176defineSymbol(math, ams, rel, "\u226e", "\\nless", true); // Symbol names preceeded by "@" each have a corresponding macro. 4177 4178defineSymbol(math, ams, rel, "\ue010", "\\@nleqslant"); 4179defineSymbol(math, ams, rel, "\ue011", "\\@nleqq"); 4180defineSymbol(math, ams, rel, "\u2a87", "\\lneq", true); 4181defineSymbol(math, ams, rel, "\u2268", "\\lneqq", true); 4182defineSymbol(math, ams, rel, "\ue00c", "\\@lvertneqq"); 4183defineSymbol(math, ams, rel, "\u22e6", "\\lnsim", true); 4184defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox", true); 4185defineSymbol(math, ams, rel, "\u2280", "\\nprec", true); // unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. 4186 4187defineSymbol(math, ams, rel, "\u22e0", "\\npreceq", true); 4188defineSymbol(math, ams, rel, "\u22e8", "\\precnsim", true); 4189defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox", true); 4190defineSymbol(math, ams, rel, "\u2241", "\\nsim", true); 4191defineSymbol(math, ams, rel, "\ue006", "\\@nshortmid"); 4192defineSymbol(math, ams, rel, "\u2224", "\\nmid", true); 4193defineSymbol(math, ams, rel, "\u22ac", "\\nvdash", true); 4194defineSymbol(math, ams, rel, "\u22ad", "\\nvDash", true); 4195defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft"); 4196defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq", true); 4197defineSymbol(math, ams, rel, "\u228a", "\\subsetneq", true); 4198defineSymbol(math, ams, rel, "\ue01a", "\\@varsubsetneq"); 4199defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq", true); 4200defineSymbol(math, ams, rel, "\ue017", "\\@varsubsetneqq"); 4201defineSymbol(math, ams, rel, "\u226f", "\\ngtr", true); 4202defineSymbol(math, ams, rel, "\ue00f", "\\@ngeqslant"); 4203defineSymbol(math, ams, rel, "\ue00e", "\\@ngeqq"); 4204defineSymbol(math, ams, rel, "\u2a88", "\\gneq", true); 4205defineSymbol(math, ams, rel, "\u2269", "\\gneqq", true); 4206defineSymbol(math, ams, rel, "\ue00d", "\\@gvertneqq"); 4207defineSymbol(math, ams, rel, "\u22e7", "\\gnsim", true); 4208defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox", true); 4209defineSymbol(math, ams, rel, "\u2281", "\\nsucc", true); // unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. 4210 4211defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq", true); 4212defineSymbol(math, ams, rel, "\u22e9", "\\succnsim", true); 4213defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox", true); // unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. 4214 4215defineSymbol(math, ams, rel, "\u2246", "\\ncong", true); 4216defineSymbol(math, ams, rel, "\ue007", "\\@nshortparallel"); 4217defineSymbol(math, ams, rel, "\u2226", "\\nparallel", true); 4218defineSymbol(math, ams, rel, "\u22af", "\\nVDash", true); 4219defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright"); 4220defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq", true); 4221defineSymbol(math, ams, rel, "\ue018", "\\@nsupseteqq"); 4222defineSymbol(math, ams, rel, "\u228b", "\\supsetneq", true); 4223defineSymbol(math, ams, rel, "\ue01b", "\\@varsupsetneq"); 4224defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq", true); 4225defineSymbol(math, ams, rel, "\ue019", "\\@varsupsetneqq"); 4226defineSymbol(math, ams, rel, "\u22ae", "\\nVdash", true); 4227defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq", true); 4228defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq", true); 4229defineSymbol(math, ams, rel, "\ue016", "\\@nsubseteqq"); 4230defineSymbol(math, ams, bin, "\u22b4", "\\unlhd"); 4231defineSymbol(math, ams, bin, "\u22b5", "\\unrhd"); // AMS Negated Arrows 4232 4233defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow", true); 4234defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow", true); 4235defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow", true); 4236defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow", true); 4237defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow", true); 4238defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow", true); // AMS Misc 4239 4240defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle"); 4241defineSymbol(math, ams, textord, "\u210f", "\\hslash"); 4242defineSymbol(math, ams, textord, "\u25bd", "\\triangledown"); 4243defineSymbol(math, ams, textord, "\u25ca", "\\lozenge"); 4244defineSymbol(math, ams, textord, "\u24c8", "\\circledS"); 4245defineSymbol(math, ams, textord, "\u00ae", "\\circledR"); 4246defineSymbol(text$1, ams, textord, "\u00ae", "\\circledR"); 4247defineSymbol(math, ams, textord, "\u2221", "\\measuredangle", true); 4248defineSymbol(math, ams, textord, "\u2204", "\\nexists"); 4249defineSymbol(math, ams, textord, "\u2127", "\\mho"); 4250defineSymbol(math, ams, textord, "\u2132", "\\Finv", true); 4251defineSymbol(math, ams, textord, "\u2141", "\\Game", true); 4252defineSymbol(math, ams, textord, "\u2035", "\\backprime"); 4253defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle"); 4254defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown"); 4255defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare"); 4256defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge"); 4257defineSymbol(math, ams, textord, "\u2605", "\\bigstar"); 4258defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle", true); 4259defineSymbol(math, ams, textord, "\u2201", "\\complement", true); // unicode-math maps U+F0 (ð) to \matheth. We map to AMS function \eth 4260 4261defineSymbol(math, ams, textord, "\u00f0", "\\eth", true); 4262defineSymbol(math, ams, textord, "\u2571", "\\diagup"); 4263defineSymbol(math, ams, textord, "\u2572", "\\diagdown"); 4264defineSymbol(math, ams, textord, "\u25a1", "\\square"); 4265defineSymbol(math, ams, textord, "\u25a1", "\\Box"); 4266defineSymbol(math, ams, textord, "\u25ca", "\\Diamond"); // unicode-math maps U+A5 to \mathyen. We map to AMS function \yen 4267 4268defineSymbol(math, ams, textord, "\u00a5", "\\yen", true); 4269defineSymbol(text$1, ams, textord, "\u00a5", "\\yen", true); 4270defineSymbol(math, ams, textord, "\u2713", "\\checkmark", true); 4271defineSymbol(text$1, ams, textord, "\u2713", "\\checkmark"); // AMS Hebrew 4272 4273defineSymbol(math, ams, textord, "\u2136", "\\beth", true); 4274defineSymbol(math, ams, textord, "\u2138", "\\daleth", true); 4275defineSymbol(math, ams, textord, "\u2137", "\\gimel", true); // AMS Greek 4276 4277defineSymbol(math, ams, textord, "\u03dd", "\\digamma", true); 4278defineSymbol(math, ams, textord, "\u03f0", "\\varkappa"); // AMS Delimiters 4279 4280defineSymbol(math, ams, open, "\u250c", "\\ulcorner", true); 4281defineSymbol(math, ams, close, "\u2510", "\\urcorner", true); 4282defineSymbol(math, ams, open, "\u2514", "\\llcorner", true); 4283defineSymbol(math, ams, close, "\u2518", "\\lrcorner", true); // AMS Binary Relations 4284 4285defineSymbol(math, ams, rel, "\u2266", "\\leqq", true); 4286defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant", true); 4287defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless", true); 4288defineSymbol(math, ams, rel, "\u2272", "\\lesssim", true); 4289defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox", true); 4290defineSymbol(math, ams, rel, "\u224a", "\\approxeq", true); 4291defineSymbol(math, ams, bin, "\u22d6", "\\lessdot"); 4292defineSymbol(math, ams, rel, "\u22d8", "\\lll", true); 4293defineSymbol(math, ams, rel, "\u2276", "\\lessgtr", true); 4294defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr", true); 4295defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr", true); 4296defineSymbol(math, ams, rel, "\u2251", "\\doteqdot"); 4297defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq", true); 4298defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq", true); 4299defineSymbol(math, ams, rel, "\u223d", "\\backsim", true); 4300defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq", true); 4301defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq", true); 4302defineSymbol(math, ams, rel, "\u22d0", "\\Subset", true); 4303defineSymbol(math, ams, rel, "\u228f", "\\sqsubset", true); 4304defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq", true); 4305defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec", true); 4306defineSymbol(math, ams, rel, "\u227e", "\\precsim", true); 4307defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox", true); 4308defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft"); 4309defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq"); 4310defineSymbol(math, ams, rel, "\u22a8", "\\vDash", true); 4311defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash", true); 4312defineSymbol(math, ams, rel, "\u2323", "\\smallsmile"); 4313defineSymbol(math, ams, rel, "\u2322", "\\smallfrown"); 4314defineSymbol(math, ams, rel, "\u224f", "\\bumpeq", true); 4315defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq", true); 4316defineSymbol(math, ams, rel, "\u2267", "\\geqq", true); 4317defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant", true); 4318defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr", true); 4319defineSymbol(math, ams, rel, "\u2273", "\\gtrsim", true); 4320defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox", true); 4321defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot"); 4322defineSymbol(math, ams, rel, "\u22d9", "\\ggg", true); 4323defineSymbol(math, ams, rel, "\u2277", "\\gtrless", true); 4324defineSymbol(math, ams, rel, "\u22db", "\\gtreqless", true); 4325defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless", true); 4326defineSymbol(math, ams, rel, "\u2256", "\\eqcirc", true); 4327defineSymbol(math, ams, rel, "\u2257", "\\circeq", true); 4328defineSymbol(math, ams, rel, "\u225c", "\\triangleq", true); 4329defineSymbol(math, ams, rel, "\u223c", "\\thicksim"); 4330defineSymbol(math, ams, rel, "\u2248", "\\thickapprox"); 4331defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq", true); 4332defineSymbol(math, ams, rel, "\u22d1", "\\Supset", true); 4333defineSymbol(math, ams, rel, "\u2290", "\\sqsupset", true); 4334defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq", true); 4335defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc", true); 4336defineSymbol(math, ams, rel, "\u227f", "\\succsim", true); 4337defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox", true); 4338defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright"); 4339defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq"); 4340defineSymbol(math, ams, rel, "\u22a9", "\\Vdash", true); 4341defineSymbol(math, ams, rel, "\u2223", "\\shortmid"); 4342defineSymbol(math, ams, rel, "\u2225", "\\shortparallel"); 4343defineSymbol(math, ams, rel, "\u226c", "\\between", true); 4344defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork", true); 4345defineSymbol(math, ams, rel, "\u221d", "\\varpropto"); 4346defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft"); // unicode-math says that \therefore is a mathord atom. 4347// We kept the amssymb atom type, which is rel. 4348 4349defineSymbol(math, ams, rel, "\u2234", "\\therefore", true); 4350defineSymbol(math, ams, rel, "\u220d", "\\backepsilon"); 4351defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright"); // unicode-math says that \because is a mathord atom. 4352// We kept the amssymb atom type, which is rel. 4353 4354defineSymbol(math, ams, rel, "\u2235", "\\because", true); 4355defineSymbol(math, ams, rel, "\u22d8", "\\llless"); 4356defineSymbol(math, ams, rel, "\u22d9", "\\gggtr"); 4357defineSymbol(math, ams, bin, "\u22b2", "\\lhd"); 4358defineSymbol(math, ams, bin, "\u22b3", "\\rhd"); 4359defineSymbol(math, ams, rel, "\u2242", "\\eqsim", true); 4360defineSymbol(math, main, rel, "\u22c8", "\\Join"); 4361defineSymbol(math, ams, rel, "\u2251", "\\Doteq", true); // AMS Binary Operators 4362 4363defineSymbol(math, ams, bin, "\u2214", "\\dotplus", true); 4364defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus"); 4365defineSymbol(math, ams, bin, "\u22d2", "\\Cap", true); 4366defineSymbol(math, ams, bin, "\u22d3", "\\Cup", true); 4367defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge", true); 4368defineSymbol(math, ams, bin, "\u229f", "\\boxminus", true); 4369defineSymbol(math, ams, bin, "\u229e", "\\boxplus", true); 4370defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes", true); 4371defineSymbol(math, ams, bin, "\u22c9", "\\ltimes", true); 4372defineSymbol(math, ams, bin, "\u22ca", "\\rtimes", true); 4373defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes", true); 4374defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes", true); 4375defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge", true); 4376defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee", true); 4377defineSymbol(math, ams, bin, "\u229d", "\\circleddash", true); 4378defineSymbol(math, ams, bin, "\u229b", "\\circledast", true); 4379defineSymbol(math, ams, bin, "\u22c5", "\\centerdot"); 4380defineSymbol(math, ams, bin, "\u22ba", "\\intercal", true); 4381defineSymbol(math, ams, bin, "\u22d2", "\\doublecap"); 4382defineSymbol(math, ams, bin, "\u22d3", "\\doublecup"); 4383defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes", true); // AMS Arrows 4384// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. 4385// We'll map it to AMS function \dashrightarrow. It produces the same atom. 4386 4387defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow", true); // unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. 4388 4389defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow", true); 4390defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows", true); 4391defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows", true); 4392defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow", true); 4393defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow", true); 4394defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail", true); 4395defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft", true); 4396defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons", true); 4397defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft", true); // unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. 4398 4399defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft", true); 4400defineSymbol(math, ams, rel, "\u21b0", "\\Lsh", true); 4401defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows", true); 4402defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft", true); 4403defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft", true); 4404defineSymbol(math, ams, rel, "\u22b8", "\\multimap", true); 4405defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow", true); 4406defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows", true); 4407defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows", true); 4408defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow", true); 4409defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail", true); 4410defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright", true); 4411defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright", true); // unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. 4412 4413defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright", true); 4414defineSymbol(math, ams, rel, "\u21b1", "\\Rsh", true); 4415defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows", true); 4416defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright", true); 4417defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright", true); 4418defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow", true); 4419defineSymbol(math, ams, rel, "\u21dd", "\\leadsto"); 4420defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow", true); 4421defineSymbol(math, ams, rel, "\u21be", "\\restriction"); 4422defineSymbol(math, main, textord, "\u2018", "`"); 4423defineSymbol(math, main, textord, "$", "\\$"); 4424defineSymbol(text$1, main, textord, "$", "\\$"); 4425defineSymbol(text$1, main, textord, "$", "\\textdollar"); 4426defineSymbol(math, main, textord, "%", "\\%"); 4427defineSymbol(text$1, main, textord, "%", "\\%"); 4428defineSymbol(math, main, textord, "_", "\\_"); 4429defineSymbol(text$1, main, textord, "_", "\\_"); 4430defineSymbol(text$1, main, textord, "_", "\\textunderscore"); 4431defineSymbol(math, main, textord, "\u2220", "\\angle", true); 4432defineSymbol(math, main, textord, "\u221e", "\\infty", true); 4433defineSymbol(math, main, textord, "\u2032", "\\prime"); 4434defineSymbol(math, main, textord, "\u25b3", "\\triangle"); 4435defineSymbol(math, main, textord, "\u0393", "\\Gamma", true); 4436defineSymbol(math, main, textord, "\u0394", "\\Delta", true); 4437defineSymbol(math, main, textord, "\u0398", "\\Theta", true); 4438defineSymbol(math, main, textord, "\u039b", "\\Lambda", true); 4439defineSymbol(math, main, textord, "\u039e", "\\Xi", true); 4440defineSymbol(math, main, textord, "\u03a0", "\\Pi", true); 4441defineSymbol(math, main, textord, "\u03a3", "\\Sigma", true); 4442defineSymbol(math, main, textord, "\u03a5", "\\Upsilon", true); 4443defineSymbol(math, main, textord, "\u03a6", "\\Phi", true); 4444defineSymbol(math, main, textord, "\u03a8", "\\Psi", true); 4445defineSymbol(math, main, textord, "\u03a9", "\\Omega", true); 4446defineSymbol(math, main, textord, "A", "\u0391"); 4447defineSymbol(math, main, textord, "B", "\u0392"); 4448defineSymbol(math, main, textord, "E", "\u0395"); 4449defineSymbol(math, main, textord, "Z", "\u0396"); 4450defineSymbol(math, main, textord, "H", "\u0397"); 4451defineSymbol(math, main, textord, "I", "\u0399"); 4452defineSymbol(math, main, textord, "K", "\u039A"); 4453defineSymbol(math, main, textord, "M", "\u039C"); 4454defineSymbol(math, main, textord, "N", "\u039D"); 4455defineSymbol(math, main, textord, "O", "\u039F"); 4456defineSymbol(math, main, textord, "P", "\u03A1"); 4457defineSymbol(math, main, textord, "T", "\u03A4"); 4458defineSymbol(math, main, textord, "X", "\u03A7"); 4459defineSymbol(math, main, textord, "\u00ac", "\\neg", true); 4460defineSymbol(math, main, textord, "\u00ac", "\\lnot"); 4461defineSymbol(math, main, textord, "\u22a4", "\\top"); 4462defineSymbol(math, main, textord, "\u22a5", "\\bot"); 4463defineSymbol(math, main, textord, "\u2205", "\\emptyset"); 4464defineSymbol(math, ams, textord, "\u2205", "\\varnothing"); 4465defineSymbol(math, main, mathord, "\u03b1", "\\alpha", true); 4466defineSymbol(math, main, mathord, "\u03b2", "\\beta", true); 4467defineSymbol(math, main, mathord, "\u03b3", "\\gamma", true); 4468defineSymbol(math, main, mathord, "\u03b4", "\\delta", true); 4469defineSymbol(math, main, mathord, "\u03f5", "\\epsilon", true); 4470defineSymbol(math, main, mathord, "\u03b6", "\\zeta", true); 4471defineSymbol(math, main, mathord, "\u03b7", "\\eta", true); 4472defineSymbol(math, main, mathord, "\u03b8", "\\theta", true); 4473defineSymbol(math, main, mathord, "\u03b9", "\\iota", true); 4474defineSymbol(math, main, mathord, "\u03ba", "\\kappa", true); 4475defineSymbol(math, main, mathord, "\u03bb", "\\lambda", true); 4476defineSymbol(math, main, mathord, "\u03bc", "\\mu", true); 4477defineSymbol(math, main, mathord, "\u03bd", "\\nu", true); 4478defineSymbol(math, main, mathord, "\u03be", "\\xi", true); 4479defineSymbol(math, main, mathord, "\u03bf", "\\omicron", true); 4480defineSymbol(math, main, mathord, "\u03c0", "\\pi", true); 4481defineSymbol(math, main, mathord, "\u03c1", "\\rho", true); 4482defineSymbol(math, main, mathord, "\u03c3", "\\sigma", true); 4483defineSymbol(math, main, mathord, "\u03c4", "\\tau", true); 4484defineSymbol(math, main, mathord, "\u03c5", "\\upsilon", true); 4485defineSymbol(math, main, mathord, "\u03d5", "\\phi", true); 4486defineSymbol(math, main, mathord, "\u03c7", "\\chi", true); 4487defineSymbol(math, main, mathord, "\u03c8", "\\psi", true); 4488defineSymbol(math, main, mathord, "\u03c9", "\\omega", true); 4489defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon", true); 4490defineSymbol(math, main, mathord, "\u03d1", "\\vartheta", true); 4491defineSymbol(math, main, mathord, "\u03d6", "\\varpi", true); 4492defineSymbol(math, main, mathord, "\u03f1", "\\varrho", true); 4493defineSymbol(math, main, mathord, "\u03c2", "\\varsigma", true); 4494defineSymbol(math, main, mathord, "\u03c6", "\\varphi", true); 4495defineSymbol(math, main, bin, "\u2217", "*"); 4496defineSymbol(math, main, bin, "+", "+"); 4497defineSymbol(math, main, bin, "\u2212", "-"); 4498defineSymbol(math, main, bin, "\u22c5", "\\cdot", true); 4499defineSymbol(math, main, bin, "\u2218", "\\circ"); 4500defineSymbol(math, main, bin, "\u00f7", "\\div", true); 4501defineSymbol(math, main, bin, "\u00b1", "\\pm", true); 4502defineSymbol(math, main, bin, "\u00d7", "\\times", true); 4503defineSymbol(math, main, bin, "\u2229", "\\cap", true); 4504defineSymbol(math, main, bin, "\u222a", "\\cup", true); 4505defineSymbol(math, main, bin, "\u2216", "\\setminus"); 4506defineSymbol(math, main, bin, "\u2227", "\\land"); 4507defineSymbol(math, main, bin, "\u2228", "\\lor"); 4508defineSymbol(math, main, bin, "\u2227", "\\wedge", true); 4509defineSymbol(math, main, bin, "\u2228", "\\vee", true); 4510defineSymbol(math, main, textord, "\u221a", "\\surd"); 4511defineSymbol(math, main, open, "(", "("); 4512defineSymbol(math, main, open, "[", "["); 4513defineSymbol(math, main, open, "\u27e8", "\\langle", true); 4514defineSymbol(math, main, open, "\u2223", "\\lvert"); 4515defineSymbol(math, main, open, "\u2225", "\\lVert"); 4516defineSymbol(math, main, close, ")", ")"); 4517defineSymbol(math, main, close, "]", "]"); 4518defineSymbol(math, main, close, "?", "?"); 4519defineSymbol(math, main, close, "!", "!"); 4520defineSymbol(math, main, close, "\u27e9", "\\rangle", true); 4521defineSymbol(math, main, close, "\u2223", "\\rvert"); 4522defineSymbol(math, main, close, "\u2225", "\\rVert"); 4523defineSymbol(math, main, rel, "=", "="); 4524defineSymbol(math, main, rel, "<", "<"); 4525defineSymbol(math, main, rel, ">", ">"); 4526defineSymbol(math, main, rel, ":", ":"); 4527defineSymbol(math, main, rel, "\u2248", "\\approx", true); 4528defineSymbol(math, main, rel, "\u2245", "\\cong", true); 4529defineSymbol(math, main, rel, "\u2265", "\\ge"); 4530defineSymbol(math, main, rel, "\u2265", "\\geq", true); 4531defineSymbol(math, main, rel, "\u2190", "\\gets"); 4532defineSymbol(math, main, rel, ">", "\\gt"); 4533defineSymbol(math, main, rel, "\u2208", "\\in", true); 4534defineSymbol(math, main, rel, "\ue020", "\\@not"); 4535defineSymbol(math, main, rel, "\u2282", "\\subset", true); 4536defineSymbol(math, main, rel, "\u2283", "\\supset", true); 4537defineSymbol(math, main, rel, "\u2286", "\\subseteq", true); 4538defineSymbol(math, main, rel, "\u2287", "\\supseteq", true); 4539defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq", true); 4540defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq", true); 4541defineSymbol(math, main, rel, "\u22a8", "\\models"); 4542defineSymbol(math, main, rel, "\u2190", "\\leftarrow", true); 4543defineSymbol(math, main, rel, "\u2264", "\\le"); 4544defineSymbol(math, main, rel, "\u2264", "\\leq", true); 4545defineSymbol(math, main, rel, "<", "\\lt"); 4546defineSymbol(math, main, rel, "\u2192", "\\rightarrow", true); 4547defineSymbol(math, main, rel, "\u2192", "\\to"); 4548defineSymbol(math, ams, rel, "\u2271", "\\ngeq", true); 4549defineSymbol(math, ams, rel, "\u2270", "\\nleq", true); 4550defineSymbol(math, main, spacing, "\u00a0", "\\ "); 4551defineSymbol(math, main, spacing, "\u00a0", "~"); 4552defineSymbol(math, main, spacing, "\u00a0", "\\space"); // Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% 4553 4554defineSymbol(math, main, spacing, "\u00a0", "\\nobreakspace"); 4555defineSymbol(text$1, main, spacing, "\u00a0", "\\ "); 4556defineSymbol(text$1, main, spacing, "\u00a0", "~"); 4557defineSymbol(text$1, main, spacing, "\u00a0", "\\space"); 4558defineSymbol(text$1, main, spacing, "\u00a0", "\\nobreakspace"); 4559defineSymbol(math, main, spacing, null, "\\nobreak"); 4560defineSymbol(math, main, spacing, null, "\\allowbreak"); 4561defineSymbol(math, main, punct, ",", ","); 4562defineSymbol(math, main, punct, ";", ";"); 4563defineSymbol(math, ams, bin, "\u22bc", "\\barwedge", true); 4564defineSymbol(math, ams, bin, "\u22bb", "\\veebar", true); 4565defineSymbol(math, main, bin, "\u2299", "\\odot", true); 4566defineSymbol(math, main, bin, "\u2295", "\\oplus", true); 4567defineSymbol(math, main, bin, "\u2297", "\\otimes", true); 4568defineSymbol(math, main, textord, "\u2202", "\\partial", true); 4569defineSymbol(math, main, bin, "\u2298", "\\oslash", true); 4570defineSymbol(math, ams, bin, "\u229a", "\\circledcirc", true); 4571defineSymbol(math, ams, bin, "\u22a1", "\\boxdot", true); 4572defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup"); 4573defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown"); 4574defineSymbol(math, main, bin, "\u2020", "\\dagger"); 4575defineSymbol(math, main, bin, "\u22c4", "\\diamond"); 4576defineSymbol(math, main, bin, "\u22c6", "\\star"); 4577defineSymbol(math, main, bin, "\u25c3", "\\triangleleft"); 4578defineSymbol(math, main, bin, "\u25b9", "\\triangleright"); 4579defineSymbol(math, main, open, "{", "\\{"); 4580defineSymbol(text$1, main, textord, "{", "\\{"); 4581defineSymbol(text$1, main, textord, "{", "\\textbraceleft"); 4582defineSymbol(math, main, close, "}", "\\}"); 4583defineSymbol(text$1, main, textord, "}", "\\}"); 4584defineSymbol(text$1, main, textord, "}", "\\textbraceright"); 4585defineSymbol(math, main, open, "{", "\\lbrace"); 4586defineSymbol(math, main, close, "}", "\\rbrace"); 4587defineSymbol(math, main, open, "[", "\\lbrack"); 4588defineSymbol(text$1, main, textord, "[", "\\lbrack"); 4589defineSymbol(math, main, close, "]", "\\rbrack"); 4590defineSymbol(text$1, main, textord, "]", "\\rbrack"); 4591defineSymbol(math, main, open, "(", "\\lparen"); 4592defineSymbol(math, main, close, ")", "\\rparen"); 4593defineSymbol(text$1, main, textord, "<", "\\textless"); // in T1 fontenc 4594 4595defineSymbol(text$1, main, textord, ">", "\\textgreater"); // in T1 fontenc 4596 4597defineSymbol(math, main, open, "\u230a", "\\lfloor", true); 4598defineSymbol(math, main, close, "\u230b", "\\rfloor", true); 4599defineSymbol(math, main, open, "\u2308", "\\lceil", true); 4600defineSymbol(math, main, close, "\u2309", "\\rceil", true); 4601defineSymbol(math, main, textord, "\\", "\\backslash"); 4602defineSymbol(math, main, textord, "\u2223", "|"); 4603defineSymbol(math, main, textord, "\u2223", "\\vert"); 4604defineSymbol(text$1, main, textord, "|", "\\textbar"); // in T1 fontenc 4605 4606defineSymbol(math, main, textord, "\u2225", "\\|"); 4607defineSymbol(math, main, textord, "\u2225", "\\Vert"); 4608defineSymbol(text$1, main, textord, "\u2225", "\\textbardbl"); 4609defineSymbol(text$1, main, textord, "~", "\\textasciitilde"); 4610defineSymbol(text$1, main, textord, "\\", "\\textbackslash"); 4611defineSymbol(text$1, main, textord, "^", "\\textasciicircum"); 4612defineSymbol(math, main, rel, "\u2191", "\\uparrow", true); 4613defineSymbol(math, main, rel, "\u21d1", "\\Uparrow", true); 4614defineSymbol(math, main, rel, "\u2193", "\\downarrow", true); 4615defineSymbol(math, main, rel, "\u21d3", "\\Downarrow", true); 4616defineSymbol(math, main, rel, "\u2195", "\\updownarrow", true); 4617defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow", true); 4618defineSymbol(math, main, op, "\u2210", "\\coprod"); 4619defineSymbol(math, main, op, "\u22c1", "\\bigvee"); 4620defineSymbol(math, main, op, "\u22c0", "\\bigwedge"); 4621defineSymbol(math, main, op, "\u2a04", "\\biguplus"); 4622defineSymbol(math, main, op, "\u22c2", "\\bigcap"); 4623defineSymbol(math, main, op, "\u22c3", "\\bigcup"); 4624defineSymbol(math, main, op, "\u222b", "\\int"); 4625defineSymbol(math, main, op, "\u222b", "\\intop"); 4626defineSymbol(math, main, op, "\u222c", "\\iint"); 4627defineSymbol(math, main, op, "\u222d", "\\iiint"); 4628defineSymbol(math, main, op, "\u220f", "\\prod"); 4629defineSymbol(math, main, op, "\u2211", "\\sum"); 4630defineSymbol(math, main, op, "\u2a02", "\\bigotimes"); 4631defineSymbol(math, main, op, "\u2a01", "\\bigoplus"); 4632defineSymbol(math, main, op, "\u2a00", "\\bigodot"); 4633defineSymbol(math, main, op, "\u222e", "\\oint"); 4634defineSymbol(math, main, op, "\u222f", "\\oiint"); 4635defineSymbol(math, main, op, "\u2230", "\\oiiint"); 4636defineSymbol(math, main, op, "\u2a06", "\\bigsqcup"); 4637defineSymbol(math, main, op, "\u222b", "\\smallint"); 4638defineSymbol(text$1, main, inner, "\u2026", "\\textellipsis"); 4639defineSymbol(math, main, inner, "\u2026", "\\mathellipsis"); 4640defineSymbol(text$1, main, inner, "\u2026", "\\ldots", true); 4641defineSymbol(math, main, inner, "\u2026", "\\ldots", true); 4642defineSymbol(math, main, inner, "\u22ef", "\\@cdots", true); 4643defineSymbol(math, main, inner, "\u22f1", "\\ddots", true); 4644defineSymbol(math, main, textord, "\u22ee", "\\varvdots"); // \vdots is a macro 4645 4646defineSymbol(math, main, accent, "\u02ca", "\\acute"); 4647defineSymbol(math, main, accent, "\u02cb", "\\grave"); 4648defineSymbol(math, main, accent, "\u00a8", "\\ddot"); 4649defineSymbol(math, main, accent, "\u007e", "\\tilde"); 4650defineSymbol(math, main, accent, "\u02c9", "\\bar"); 4651defineSymbol(math, main, accent, "\u02d8", "\\breve"); 4652defineSymbol(math, main, accent, "\u02c7", "\\check"); 4653defineSymbol(math, main, accent, "\u005e", "\\hat"); 4654defineSymbol(math, main, accent, "\u20d7", "\\vec"); 4655defineSymbol(math, main, accent, "\u02d9", "\\dot"); 4656defineSymbol(math, main, accent, "\u02da", "\\mathring"); 4657defineSymbol(math, main, mathord, "\u0131", "\\imath", true); 4658defineSymbol(math, main, mathord, "\u0237", "\\jmath", true); 4659defineSymbol(text$1, main, textord, "\u0131", "\\i", true); 4660defineSymbol(text$1, main, textord, "\u0237", "\\j", true); 4661defineSymbol(text$1, main, textord, "\u00df", "\\ss", true); 4662defineSymbol(text$1, main, textord, "\u00e6", "\\ae", true); 4663defineSymbol(text$1, main, textord, "\u00e6", "\\ae", true); 4664defineSymbol(text$1, main, textord, "\u0153", "\\oe", true); 4665defineSymbol(text$1, main, textord, "\u00f8", "\\o", true); 4666defineSymbol(text$1, main, textord, "\u00c6", "\\AE", true); 4667defineSymbol(text$1, main, textord, "\u0152", "\\OE", true); 4668defineSymbol(text$1, main, textord, "\u00d8", "\\O", true); 4669defineSymbol(text$1, main, accent, "\u02ca", "\\'"); // acute 4670 4671defineSymbol(text$1, main, accent, "\u02cb", "\\`"); // grave 4672 4673defineSymbol(text$1, main, accent, "\u02c6", "\\^"); // circumflex 4674 4675defineSymbol(text$1, main, accent, "\u02dc", "\\~"); // tilde 4676 4677defineSymbol(text$1, main, accent, "\u02c9", "\\="); // macron 4678 4679defineSymbol(text$1, main, accent, "\u02d8", "\\u"); // breve 4680 4681defineSymbol(text$1, main, accent, "\u02d9", "\\."); // dot above 4682 4683defineSymbol(text$1, main, accent, "\u02da", "\\r"); // ring above 4684 4685defineSymbol(text$1, main, accent, "\u02c7", "\\v"); // caron 4686 4687defineSymbol(text$1, main, accent, "\u00a8", '\\"'); // diaresis 4688 4689defineSymbol(text$1, main, accent, "\u02dd", "\\H"); // double acute 4690 4691defineSymbol(text$1, main, accent, "\u25ef", "\\textcircled"); // \bigcirc glyph 4692// These ligatures are detected and created in Parser.js's `formLigatures`. 4693 4694const ligatures = { 4695 "--": true, 4696 "---": true, 4697 "``": true, 4698 "''": true 4699}; 4700defineSymbol(text$1, main, textord, "\u2013", "--"); 4701defineSymbol(text$1, main, textord, "\u2013", "\\textendash"); 4702defineSymbol(text$1, main, textord, "\u2014", "---"); 4703defineSymbol(text$1, main, textord, "\u2014", "\\textemdash"); 4704defineSymbol(text$1, main, textord, "\u2018", "`"); 4705defineSymbol(text$1, main, textord, "\u2018", "\\textquoteleft"); 4706defineSymbol(text$1, main, textord, "\u2019", "'"); 4707defineSymbol(text$1, main, textord, "\u2019", "\\textquoteright"); 4708defineSymbol(text$1, main, textord, "\u201c", "``"); 4709defineSymbol(text$1, main, textord, "\u201c", "\\textquotedblleft"); 4710defineSymbol(text$1, main, textord, "\u201d", "''"); 4711defineSymbol(text$1, main, textord, "\u201d", "\\textquotedblright"); // \degree from gensymb package 4712 4713defineSymbol(math, main, textord, "\u00b0", "\\degree", true); 4714defineSymbol(text$1, main, textord, "\u00b0", "\\degree"); // \textdegree from inputenc package 4715 4716defineSymbol(text$1, main, textord, "\u00b0", "\\textdegree", true); // TODO: In LaTeX, \pounds can generate a different character in text and math 4717// mode, but among our fonts, only Main-Italic defines this character "163". 4718 4719defineSymbol(math, main, mathord, "\u00a3", "\\pounds"); 4720defineSymbol(math, main, mathord, "\u00a3", "\\mathsterling", true); 4721defineSymbol(text$1, main, mathord, "\u00a3", "\\pounds"); 4722defineSymbol(text$1, main, mathord, "\u00a3", "\\textsterling", true); 4723defineSymbol(math, ams, textord, "\u2720", "\\maltese"); 4724defineSymbol(text$1, ams, textord, "\u2720", "\\maltese"); 4725defineSymbol(text$1, main, spacing, "\u00a0", "\\ "); 4726defineSymbol(text$1, main, spacing, "\u00a0", " "); 4727defineSymbol(text$1, main, spacing, "\u00a0", "~"); // There are lots of symbols which are the same, so we add them in afterwards. 4728// All of these are textords in math mode 4729 4730const mathTextSymbols = "0123456789/@.\""; 4731 4732for (let i = 0; i < mathTextSymbols.length; i++) { 4733 const ch = mathTextSymbols.charAt(i); 4734 defineSymbol(math, main, textord, ch, ch); 4735} // All of these are textords in text mode 4736 4737 4738const textSymbols = "0123456789!@*()-=+[]<>|\";:?/.,"; 4739 4740for (let i = 0; i < textSymbols.length; i++) { 4741 const ch = textSymbols.charAt(i); 4742 defineSymbol(text$1, main, textord, ch, ch); 4743} // All of these are textords in text mode, and mathords in math mode 4744 4745 4746const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 4747 4748for (let i = 0; i < letters.length; i++) { 4749 const ch = letters.charAt(i); 4750 defineSymbol(math, main, mathord, ch, ch); 4751 defineSymbol(text$1, main, textord, ch, ch); 4752} // Blackboard bold and script letters in Unicode range 4753 4754 4755defineSymbol(math, ams, textord, "C", "\u2102"); // blackboard bold 4756 4757defineSymbol(text$1, ams, textord, "C", "\u2102"); 4758defineSymbol(math, ams, textord, "H", "\u210D"); 4759defineSymbol(text$1, ams, textord, "H", "\u210D"); 4760defineSymbol(math, ams, textord, "N", "\u2115"); 4761defineSymbol(text$1, ams, textord, "N", "\u2115"); 4762defineSymbol(math, ams, textord, "P", "\u2119"); 4763defineSymbol(text$1, ams, textord, "P", "\u2119"); 4764defineSymbol(math, ams, textord, "Q", "\u211A"); 4765defineSymbol(text$1, ams, textord, "Q", "\u211A"); 4766defineSymbol(math, ams, textord, "R", "\u211D"); 4767defineSymbol(text$1, ams, textord, "R", "\u211D"); 4768defineSymbol(math, ams, textord, "Z", "\u2124"); 4769defineSymbol(text$1, ams, textord, "Z", "\u2124"); 4770defineSymbol(math, main, mathord, "h", "\u210E"); // italic h, Planck constant 4771 4772defineSymbol(text$1, main, mathord, "h", "\u210E"); // The next loop loads wide (surrogate pair) characters. 4773// We support some letters in the Unicode range U+1D400 to U+1D7FF, 4774// Mathematical Alphanumeric Symbols. 4775// Some editors do not deal well with wide characters. So don't write the 4776// string into this file. Instead, create the string from the surrogate pair. 4777 4778let wideChar = ""; 4779 4780for (let i = 0; i < letters.length; i++) { 4781 const ch = letters.charAt(i); // The hex numbers in the next line are a surrogate pair. 4782 // 0xD835 is the high surrogate for all letters in the range we support. 4783 // 0xDC00 is the low surrogate for bold A. 4784 4785 wideChar = String.fromCharCode(0xD835, 0xDC00 + i); // A-Z a-z bold 4786 4787 defineSymbol(math, main, mathord, ch, wideChar); 4788 defineSymbol(text$1, main, textord, ch, wideChar); 4789 wideChar = String.fromCharCode(0xD835, 0xDC34 + i); // A-Z a-z italic 4790 4791 defineSymbol(math, main, mathord, ch, wideChar); 4792 defineSymbol(text$1, main, textord, ch, wideChar); 4793 wideChar = String.fromCharCode(0xD835, 0xDC68 + i); // A-Z a-z bold italic 4794 4795 defineSymbol(math, main, mathord, ch, wideChar); 4796 defineSymbol(text$1, main, textord, ch, wideChar); 4797 wideChar = String.fromCharCode(0xD835, 0xDD04 + i); // A-Z a-z Fractur 4798 4799 defineSymbol(math, main, mathord, ch, wideChar); 4800 defineSymbol(text$1, main, textord, ch, wideChar); 4801 wideChar = String.fromCharCode(0xD835, 0xDDA0 + i); // A-Z a-z sans-serif 4802 4803 defineSymbol(math, main, mathord, ch, wideChar); 4804 defineSymbol(text$1, main, textord, ch, wideChar); 4805 wideChar = String.fromCharCode(0xD835, 0xDDD4 + i); // A-Z a-z sans bold 4806 4807 defineSymbol(math, main, mathord, ch, wideChar); 4808 defineSymbol(text$1, main, textord, ch, wideChar); 4809 wideChar = String.fromCharCode(0xD835, 0xDE08 + i); // A-Z a-z sans italic 4810 4811 defineSymbol(math, main, mathord, ch, wideChar); 4812 defineSymbol(text$1, main, textord, ch, wideChar); 4813 wideChar = String.fromCharCode(0xD835, 0xDE70 + i); // A-Z a-z monospace 4814 4815 defineSymbol(math, main, mathord, ch, wideChar); 4816 defineSymbol(text$1, main, textord, ch, wideChar); 4817 4818 if (i < 26) { 4819 // KaTeX fonts have only capital letters for blackboard bold and script. 4820 // See exception for k below. 4821 wideChar = String.fromCharCode(0xD835, 0xDD38 + i); // A-Z double struck 4822 4823 defineSymbol(math, main, mathord, ch, wideChar); 4824 defineSymbol(text$1, main, textord, ch, wideChar); 4825 wideChar = String.fromCharCode(0xD835, 0xDC9C + i); // A-Z script 4826 4827 defineSymbol(math, main, mathord, ch, wideChar); 4828 defineSymbol(text$1, main, textord, ch, wideChar); 4829 } // TODO: Add bold script when it is supported by a KaTeX font. 4830 4831} // "k" is the only double struck lower case letter in the KaTeX fonts. 4832 4833 4834wideChar = String.fromCharCode(0xD835, 0xDD5C); // k double struck 4835 4836defineSymbol(math, main, mathord, "k", wideChar); 4837defineSymbol(text$1, main, textord, "k", wideChar); // Next, some wide character numerals 4838 4839for (let i = 0; i < 10; i++) { 4840 const ch = i.toString(); 4841 wideChar = String.fromCharCode(0xD835, 0xDFCE + i); // 0-9 bold 4842 4843 defineSymbol(math, main, mathord, ch, wideChar); 4844 defineSymbol(text$1, main, textord, ch, wideChar); 4845 wideChar = String.fromCharCode(0xD835, 0xDFE2 + i); // 0-9 sans serif 4846 4847 defineSymbol(math, main, mathord, ch, wideChar); 4848 defineSymbol(text$1, main, textord, ch, wideChar); 4849 wideChar = String.fromCharCode(0xD835, 0xDFEC + i); // 0-9 bold sans 4850 4851 defineSymbol(math, main, mathord, ch, wideChar); 4852 defineSymbol(text$1, main, textord, ch, wideChar); 4853 wideChar = String.fromCharCode(0xD835, 0xDFF6 + i); // 0-9 monospace 4854 4855 defineSymbol(math, main, mathord, ch, wideChar); 4856 defineSymbol(text$1, main, textord, ch, wideChar); 4857} // We add these Latin-1 letters as symbols for backwards-compatibility, 4858// but they are not actually in the font, nor are they supported by the 4859// Unicode accent mechanism, so they fall back to Times font and look ugly. 4860// TODO(edemaine): Fix this. 4861 4862 4863const extraLatin = "ÇÐÞçþ"; 4864 4865for (let i = 0; i < extraLatin.length; i++) { 4866 const ch = extraLatin.charAt(i); 4867 defineSymbol(math, main, mathord, ch, ch); 4868 defineSymbol(text$1, main, textord, ch, ch); 4869} 4870 4871defineSymbol(text$1, main, textord, "ð", "ð"); // Unicode versions of existing characters 4872 4873defineSymbol(text$1, main, textord, "\u2013", "–"); 4874defineSymbol(text$1, main, textord, "\u2014", "—"); 4875defineSymbol(text$1, main, textord, "\u2018", "‘"); 4876defineSymbol(text$1, main, textord, "\u2019", "’"); 4877defineSymbol(text$1, main, textord, "\u201c", "“"); 4878defineSymbol(text$1, main, textord, "\u201d", "”"); 4879 4880/** 4881 * This file provides support for Unicode range U+1D400 to U+1D7FF, 4882 * Mathematical Alphanumeric Symbols. 4883 * 4884 * Function wideCharacterFont takes a wide character as input and returns 4885 * the font information necessary to render it properly. 4886 */ 4887/** 4888 * Data below is from https://www.unicode.org/charts/PDF/U1D400.pdf 4889 * That document sorts characters into groups by font type, say bold or italic. 4890 * 4891 * In the arrays below, each subarray consists three elements: 4892 * * The CSS class of that group when in math mode. 4893 * * The CSS class of that group when in text mode. 4894 * * The font name, so that KaTeX can get font metrics. 4895 */ 4896 4897const wideLatinLetterData = [["mathbf", "textbf", "Main-Bold"], // A-Z bold upright 4898["mathbf", "textbf", "Main-Bold"], // a-z bold upright 4899["mathdefault", "textit", "Math-Italic"], // A-Z italic 4900["mathdefault", "textit", "Math-Italic"], // a-z italic 4901["boldsymbol", "boldsymbol", "Main-BoldItalic"], // A-Z bold italic 4902["boldsymbol", "boldsymbol", "Main-BoldItalic"], // a-z bold italic 4903// Map fancy A-Z letters to script, not calligraphic. 4904// This aligns with unicode-math and math fonts (except Cambria Math). 4905["mathscr", "textscr", "Script-Regular"], // A-Z script 4906["", "", ""], // a-z script. No font 4907["", "", ""], // A-Z bold script. No font 4908["", "", ""], // a-z bold script. No font 4909["mathfrak", "textfrak", "Fraktur-Regular"], // A-Z Fraktur 4910["mathfrak", "textfrak", "Fraktur-Regular"], // a-z Fraktur 4911["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck 4912["mathbb", "textbb", "AMS-Regular"], // k double-struck 4913["", "", ""], // A-Z bold Fraktur No font metrics 4914["", "", ""], // a-z bold Fraktur. No font. 4915["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif 4916["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif 4917["mathboldsf", "textboldsf", "SansSerif-Bold"], // A-Z bold sans-serif 4918["mathboldsf", "textboldsf", "SansSerif-Bold"], // a-z bold sans-serif 4919["mathitsf", "textitsf", "SansSerif-Italic"], // A-Z italic sans-serif 4920["mathitsf", "textitsf", "SansSerif-Italic"], // a-z italic sans-serif 4921["", "", ""], // A-Z bold italic sans. No font 4922["", "", ""], // a-z bold italic sans. No font 4923["mathtt", "texttt", "Typewriter-Regular"], // A-Z monospace 4924["mathtt", "texttt", "Typewriter-Regular"]]; 4925const wideNumeralData = [["mathbf", "textbf", "Main-Bold"], // 0-9 bold 4926["", "", ""], // 0-9 double-struck. No KaTeX font. 4927["mathsf", "textsf", "SansSerif-Regular"], // 0-9 sans-serif 4928["mathboldsf", "textboldsf", "SansSerif-Bold"], // 0-9 bold sans-serif 4929["mathtt", "texttt", "Typewriter-Regular"]]; 4930const wideCharacterFont = function wideCharacterFont(wideChar, mode) { 4931 // IE doesn't support codePointAt(). So work with the surrogate pair. 4932 const H = wideChar.charCodeAt(0); // high surrogate 4933 4934 const L = wideChar.charCodeAt(1); // low surrogate 4935 4936 const codePoint = (H - 0xD800) * 0x400 + (L - 0xDC00) + 0x10000; 4937 const j = mode === "math" ? 0 : 1; // column index for CSS class. 4938 4939 if (0x1D400 <= codePoint && codePoint < 0x1D6A4) { 4940 // wideLatinLetterData contains exactly 26 chars on each row. 4941 // So we can calculate the relevant row. No traverse necessary. 4942 const i = Math.floor((codePoint - 0x1D400) / 26); 4943 return [wideLatinLetterData[i][2], wideLatinLetterData[i][j]]; 4944 } else if (0x1D7CE <= codePoint && codePoint <= 0x1D7FF) { 4945 // Numerals, ten per row. 4946 const i = Math.floor((codePoint - 0x1D7CE) / 10); 4947 return [wideNumeralData[i][2], wideNumeralData[i][j]]; 4948 } else if (codePoint === 0x1D6A5 || codePoint === 0x1D6A6) { 4949 // dotless i or j 4950 return [wideLatinLetterData[0][2], wideLatinLetterData[0][j]]; 4951 } else if (0x1D6A6 < codePoint && codePoint < 0x1D7CE) { 4952 // Greek letters. Not supported, yet. 4953 return ["", ""]; 4954 } else { 4955 // We don't support any wide characters outside 1D400–1D7FF. 4956 throw new ParseError("Unsupported character: " + wideChar); 4957 } 4958}; 4959 4960/** 4961 * This file contains information about the options that the Parser carries 4962 * around with it while parsing. Data is held in an `Options` object, and when 4963 * recursing, a new `Options` object can be created with the `.with*` and 4964 * `.reset` functions. 4965 */ 4966const sizeStyleMap = [// Each element contains [textsize, scriptsize, scriptscriptsize]. 4967// The size mappings are taken from TeX with \normalsize=10pt. 4968[1, 1, 1], // size1: [5, 5, 5] \tiny 4969[2, 1, 1], // size2: [6, 5, 5] 4970[3, 1, 1], // size3: [7, 5, 5] \scriptsize 4971[4, 2, 1], // size4: [8, 6, 5] \footnotesize 4972[5, 2, 1], // size5: [9, 6, 5] \small 4973[6, 3, 1], // size6: [10, 7, 5] \normalsize 4974[7, 4, 2], // size7: [12, 8, 6] \large 4975[8, 6, 3], // size8: [14.4, 10, 7] \Large 4976[9, 7, 6], // size9: [17.28, 12, 10] \LARGE 4977[10, 8, 7], // size10: [20.74, 14.4, 12] \huge 4978[11, 10, 9]]; 4979const sizeMultipliers = [// fontMetrics.js:getGlobalMetrics also uses size indexes, so if 4980// you change size indexes, change that function. 49810.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.44, 1.728, 2.074, 2.488]; 4982 4983const sizeAtStyle = function sizeAtStyle(size, style) { 4984 return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1]; 4985}; // In these types, "" (empty string) means "no change". 4986 4987 4988/** 4989 * This is the main options class. It contains the current style, size, color, 4990 * and font. 4991 * 4992 * Options objects should not be modified. To create a new Options with 4993 * different properties, call a `.having*` method. 4994 */ 4995class Options { 4996 // A font family applies to a group of fonts (i.e. SansSerif), while a font 4997 // represents a specific font (i.e. SansSerif Bold). 4998 // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm 4999 5000 /** 5001 * The base size index. 5002 */ 5003 constructor(data) { 5004 this.style = void 0; 5005 this.color = void 0; 5006 this.size = void 0; 5007 this.textSize = void 0; 5008 this.phantom = void 0; 5009 this.font = void 0; 5010 this.fontFamily = void 0; 5011 this.fontWeight = void 0; 5012 this.fontShape = void 0; 5013 this.sizeMultiplier = void 0; 5014 this.maxSize = void 0; 5015 this.minRuleThickness = void 0; 5016 this._fontMetrics = void 0; 5017 this.style = data.style; 5018 this.color = data.color; 5019 this.size = data.size || Options.BASESIZE; 5020 this.textSize = data.textSize || this.size; 5021 this.phantom = !!data.phantom; 5022 this.font = data.font || ""; 5023 this.fontFamily = data.fontFamily || ""; 5024 this.fontWeight = data.fontWeight || ''; 5025 this.fontShape = data.fontShape || ''; 5026 this.sizeMultiplier = sizeMultipliers[this.size - 1]; 5027 this.maxSize = data.maxSize; 5028 this.minRuleThickness = data.minRuleThickness; 5029 this._fontMetrics = undefined; 5030 } 5031 /** 5032 * Returns a new options object with the same properties as "this". Properties 5033 * from "extension" will be copied to the new options object. 5034 */ 5035 5036 5037 extend(extension) { 5038 const data = { 5039 style: this.style, 5040 size: this.size, 5041 textSize: this.textSize, 5042 color: this.color, 5043 phantom: this.phantom, 5044 font: this.font, 5045 fontFamily: this.fontFamily, 5046 fontWeight: this.fontWeight, 5047 fontShape: this.fontShape, 5048 maxSize: this.maxSize, 5049 minRuleThickness: this.minRuleThickness 5050 }; 5051 5052 for (const key in extension) { 5053 if (extension.hasOwnProperty(key)) { 5054 data[key] = extension[key]; 5055 } 5056 } 5057 5058 return new Options(data); 5059 } 5060 /** 5061 * Return an options object with the given style. If `this.style === style`, 5062 * returns `this`. 5063 */ 5064 5065 5066 havingStyle(style) { 5067 if (this.style === style) { 5068 return this; 5069 } else { 5070 return this.extend({ 5071 style: style, 5072 size: sizeAtStyle(this.textSize, style) 5073 }); 5074 } 5075 } 5076 /** 5077 * Return an options object with a cramped version of the current style. If 5078 * the current style is cramped, returns `this`. 5079 */ 5080 5081 5082 havingCrampedStyle() { 5083 return this.havingStyle(this.style.cramp()); 5084 } 5085 /** 5086 * Return an options object with the given size and in at least `\textstyle`. 5087 * Returns `this` if appropriate. 5088 */ 5089 5090 5091 havingSize(size) { 5092 if (this.size === size && this.textSize === size) { 5093 return this; 5094 } else { 5095 return this.extend({ 5096 style: this.style.text(), 5097 size: size, 5098 textSize: size, 5099 sizeMultiplier: sizeMultipliers[size - 1] 5100 }); 5101 } 5102 } 5103 /** 5104 * Like `this.havingSize(BASESIZE).havingStyle(style)`. If `style` is omitted, 5105 * changes to at least `\textstyle`. 5106 */ 5107 5108 5109 havingBaseStyle(style) { 5110 style = style || this.style.text(); 5111 const wantSize = sizeAtStyle(Options.BASESIZE, style); 5112 5113 if (this.size === wantSize && this.textSize === Options.BASESIZE && this.style === style) { 5114 return this; 5115 } else { 5116 return this.extend({ 5117 style: style, 5118 size: wantSize 5119 }); 5120 } 5121 } 5122 /** 5123 * Remove the effect of sizing changes such as \Huge. 5124 * Keep the effect of the current style, such as \scriptstyle. 5125 */ 5126 5127 5128 havingBaseSizing() { 5129 let size; 5130 5131 switch (this.style.id) { 5132 case 4: 5133 case 5: 5134 size = 3; // normalsize in scriptstyle 5135 5136 break; 5137 5138 case 6: 5139 case 7: 5140 size = 1; // normalsize in scriptscriptstyle 5141 5142 break; 5143 5144 default: 5145 size = 6; 5146 // normalsize in textstyle or displaystyle 5147 } 5148 5149 return this.extend({ 5150 style: this.style.text(), 5151 size: size 5152 }); 5153 } 5154 /** 5155 * Create a new options object with the given color. 5156 */ 5157 5158 5159 withColor(color) { 5160 return this.extend({ 5161 color: color 5162 }); 5163 } 5164 /** 5165 * Create a new options object with "phantom" set to true. 5166 */ 5167 5168 5169 withPhantom() { 5170 return this.extend({ 5171 phantom: true 5172 }); 5173 } 5174 /** 5175 * Creates a new options object with the given math font or old text font. 5176 * @type {[type]} 5177 */ 5178 5179 5180 withFont(font) { 5181 return this.extend({ 5182 font 5183 }); 5184 } 5185 /** 5186 * Create a new options objects with the given fontFamily. 5187 */ 5188 5189 5190 withTextFontFamily(fontFamily) { 5191 return this.extend({ 5192 fontFamily, 5193 font: "" 5194 }); 5195 } 5196 /** 5197 * Creates a new options object with the given font weight 5198 */ 5199 5200 5201 withTextFontWeight(fontWeight) { 5202 return this.extend({ 5203 fontWeight, 5204 font: "" 5205 }); 5206 } 5207 /** 5208 * Creates a new options object with the given font weight 5209 */ 5210 5211 5212 withTextFontShape(fontShape) { 5213 return this.extend({ 5214 fontShape, 5215 font: "" 5216 }); 5217 } 5218 /** 5219 * Return the CSS sizing classes required to switch from enclosing options 5220 * `oldOptions` to `this`. Returns an array of classes. 5221 */ 5222 5223 5224 sizingClasses(oldOptions) { 5225 if (oldOptions.size !== this.size) { 5226 return ["sizing", "reset-size" + oldOptions.size, "size" + this.size]; 5227 } else { 5228 return []; 5229 } 5230 } 5231 /** 5232 * Return the CSS sizing classes required to switch to the base size. Like 5233 * `this.havingSize(BASESIZE).sizingClasses(this)`. 5234 */ 5235 5236 5237 baseSizingClasses() { 5238 if (this.size !== Options.BASESIZE) { 5239 return ["sizing", "reset-size" + this.size, "size" + Options.BASESIZE]; 5240 } else { 5241 return []; 5242 } 5243 } 5244 /** 5245 * Return the font metrics for this size. 5246 */ 5247 5248 5249 fontMetrics() { 5250 if (!this._fontMetrics) { 5251 this._fontMetrics = getGlobalMetrics(this.size); 5252 } 5253 5254 return this._fontMetrics; 5255 } 5256 /** 5257 * Gets the CSS color of the current options object 5258 */ 5259 5260 5261 getColor() { 5262 if (this.phantom) { 5263 return "transparent"; 5264 } else { 5265 return this.color; 5266 } 5267 } 5268 5269} 5270 5271Options.BASESIZE = 6; 5272 5273/** 5274 * This file does conversion between units. In particular, it provides 5275 * calculateSize to convert other units into ems. 5276 */ 5277// Thus, multiplying a length by this number converts the length from units 5278// into pts. Dividing the result by ptPerEm gives the number of ems 5279// *assuming* a font size of ptPerEm (normal size, normal style). 5280 5281const ptPerUnit = { 5282 // https://en.wikibooks.org/wiki/LaTeX/Lengths and 5283 // https://tex.stackexchange.com/a/8263 5284 "pt": 1, 5285 // TeX point 5286 "mm": 7227 / 2540, 5287 // millimeter 5288 "cm": 7227 / 254, 5289 // centimeter 5290 "in": 72.27, 5291 // inch 5292 "bp": 803 / 800, 5293 // big (PostScript) points 5294 "pc": 12, 5295 // pica 5296 "dd": 1238 / 1157, 5297 // didot 5298 "cc": 14856 / 1157, 5299 // cicero (12 didot) 5300 "nd": 685 / 642, 5301 // new didot 5302 "nc": 1370 / 107, 5303 // new cicero (12 new didot) 5304 "sp": 1 / 65536, 5305 // scaled point (TeX's internal smallest unit) 5306 // https://tex.stackexchange.com/a/41371 5307 "px": 803 / 800 // \pdfpxdimen defaults to 1 bp in pdfTeX and LuaTeX 5308 5309}; // Dictionary of relative units, for fast validity testing. 5310 5311const relativeUnit = { 5312 "ex": true, 5313 "em": true, 5314 "mu": true 5315}; 5316 5317/** 5318 * Determine whether the specified unit (either a string defining the unit 5319 * or a "size" parse node containing a unit field) is valid. 5320 */ 5321const validUnit = function validUnit(unit) { 5322 if (typeof unit !== "string") { 5323 unit = unit.unit; 5324 } 5325 5326 return unit in ptPerUnit || unit in relativeUnit || unit === "ex"; 5327}; 5328/* 5329 * Convert a "size" parse node (with numeric "number" and string "unit" fields, 5330 * as parsed by functions.js argType "size") into a CSS em value for the 5331 * current style/scale. `options` gives the current options. 5332 */ 5333 5334const calculateSize = function calculateSize(sizeValue, options) { 5335 let scale; 5336 5337 if (sizeValue.unit in ptPerUnit) { 5338 // Absolute units 5339 scale = ptPerUnit[sizeValue.unit] // Convert unit to pt 5340 / options.fontMetrics().ptPerEm // Convert pt to CSS em 5341 / options.sizeMultiplier; // Unscale to make absolute units 5342 } else if (sizeValue.unit === "mu") { 5343 // `mu` units scale with scriptstyle/scriptscriptstyle. 5344 scale = options.fontMetrics().cssEmPerMu; 5345 } else { 5346 // Other relative units always refer to the *textstyle* font 5347 // in the current size. 5348 let unitOptions; 5349 5350 if (options.style.isTight()) { 5351 // isTight() means current style is script/scriptscript. 5352 unitOptions = options.havingStyle(options.style.text()); 5353 } else { 5354 unitOptions = options; 5355 } // TODO: In TeX these units are relative to the quad of the current 5356 // *text* font, e.g. cmr10. KaTeX instead uses values from the 5357 // comparably-sized *Computer Modern symbol* font. At 10pt, these 5358 // match. At 7pt and 5pt, they differ: cmr7=1.138894, cmsy7=1.170641; 5359 // cmr5=1.361133, cmsy5=1.472241. Consider $\scriptsize a\kern1emb$. 5360 // TeX \showlists shows a kern of 1.13889 * fontsize; 5361 // KaTeX shows a kern of 1.171 * fontsize. 5362 5363 5364 if (sizeValue.unit === "ex") { 5365 scale = unitOptions.fontMetrics().xHeight; 5366 } else if (sizeValue.unit === "em") { 5367 scale = unitOptions.fontMetrics().quad; 5368 } else { 5369 throw new ParseError("Invalid unit: '" + sizeValue.unit + "'"); 5370 } 5371 5372 if (unitOptions !== options) { 5373 scale *= unitOptions.sizeMultiplier / options.sizeMultiplier; 5374 } 5375 } 5376 5377 return Math.min(sizeValue.number * scale, options.maxSize); 5378}; 5379 5380/* eslint no-console:0 */ 5381// The following have to be loaded from Main-Italic font, using class mathit 5382const mathitLetters = ["\\imath", "ı", // dotless i 5383"\\jmath", "ȷ", // dotless j 5384"\\pounds", "\\mathsterling", "\\textsterling", "£"]; 5385/** 5386 * Looks up the given symbol in fontMetrics, after applying any symbol 5387 * replacements defined in symbol.js 5388 */ 5389 5390const lookupSymbol = function lookupSymbol(value, // TODO(#963): Use a union type for this. 5391fontName, mode) { 5392 // Replace the value with its replaced value from symbol.js 5393 if (symbols[mode][value] && symbols[mode][value].replace) { 5394 value = symbols[mode][value].replace; 5395 } 5396 5397 return { 5398 value: value, 5399 metrics: getCharacterMetrics(value, fontName, mode) 5400 }; 5401}; 5402/** 5403 * Makes a symbolNode after translation via the list of symbols in symbols.js. 5404 * Correctly pulls out metrics for the character, and optionally takes a list of 5405 * classes to be attached to the node. 5406 * 5407 * TODO: make argument order closer to makeSpan 5408 * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which 5409 * should if present come first in `classes`. 5410 * TODO(#953): Make `options` mandatory and always pass it in. 5411 */ 5412 5413 5414const makeSymbol = function makeSymbol(value, fontName, mode, options, classes) { 5415 const lookup = lookupSymbol(value, fontName, mode); 5416 const metrics = lookup.metrics; 5417 value = lookup.value; 5418 let symbolNode; 5419 5420 if (metrics) { 5421 let italic = metrics.italic; 5422 5423 if (mode === "text" || options && options.font === "mathit") { 5424 italic = 0; 5425 } 5426 5427 symbolNode = new SymbolNode(value, metrics.height, metrics.depth, italic, metrics.skew, metrics.width, classes); 5428 } else { 5429 // TODO(emily): Figure out a good way to only print this in development 5430 typeof console !== "undefined" && console.warn("No character metrics " + `for '${value}' in style '${fontName}' and mode '${mode}'`); 5431 symbolNode = new SymbolNode(value, 0, 0, 0, 0, 0, classes); 5432 } 5433 5434 if (options) { 5435 symbolNode.maxFontSize = options.sizeMultiplier; 5436 5437 if (options.style.isTight()) { 5438 symbolNode.classes.push("mtight"); 5439 } 5440 5441 const color = options.getColor(); 5442 5443 if (color) { 5444 symbolNode.style.color = color; 5445 } 5446 } 5447 5448 return symbolNode; 5449}; 5450/** 5451 * Makes a symbol in Main-Regular or AMS-Regular. 5452 * Used for rel, bin, open, close, inner, and punct. 5453 */ 5454 5455 5456const mathsym = function mathsym(value, mode, options, classes) { 5457 if (classes === void 0) { 5458 classes = []; 5459 } 5460 5461 // Decide what font to render the symbol in by its entry in the symbols 5462 // table. 5463 // Have a special case for when the value = \ because the \ is used as a 5464 // textord in unsupported command errors but cannot be parsed as a regular 5465 // text ordinal and is therefore not present as a symbol in the symbols 5466 // table for text, as well as a special case for boldsymbol because it 5467 // can be used for bold + and - 5468 if (options.font === "boldsymbol" && lookupSymbol(value, "Main-Bold", mode).metrics) { 5469 return makeSymbol(value, "Main-Bold", mode, options, classes.concat(["mathbf"])); 5470 } else if (value === "\\" || symbols[mode][value].font === "main") { 5471 return makeSymbol(value, "Main-Regular", mode, options, classes); 5472 } else { 5473 return makeSymbol(value, "AMS-Regular", mode, options, classes.concat(["amsrm"])); 5474 } 5475}; 5476/** 5477 * Determines which of the two font names (Main-Italic and Math-Italic) and 5478 * corresponding style tags (maindefault or mathit) to use for default math font, 5479 * depending on the symbol. 5480 */ 5481 5482 5483const mathdefault = function mathdefault(value, mode, options, classes) { 5484 if (/[0-9]/.test(value.charAt(0)) || // glyphs for \imath and \jmath do not exist in Math-Italic so we 5485 // need to use Main-Italic instead 5486 utils.contains(mathitLetters, value)) { 5487 return { 5488 fontName: "Main-Italic", 5489 fontClass: "mathit" 5490 }; 5491 } else { 5492 return { 5493 fontName: "Math-Italic", 5494 fontClass: "mathdefault" 5495 }; 5496 } 5497}; 5498/** 5499 * Determines which of the font names (Main-Italic, Math-Italic, and Caligraphic) 5500 * and corresponding style tags (mathit, mathdefault, or mathcal) to use for font 5501 * "mathnormal", depending on the symbol. Use this function instead of fontMap for 5502 * font "mathnormal". 5503 */ 5504 5505 5506const mathnormal = function mathnormal(value, mode, options, classes) { 5507 if (utils.contains(mathitLetters, value)) { 5508 return { 5509 fontName: "Main-Italic", 5510 fontClass: "mathit" 5511 }; 5512 } else if (/[0-9]/.test(value.charAt(0))) { 5513 return { 5514 fontName: "Caligraphic-Regular", 5515 fontClass: "mathcal" 5516 }; 5517 } else { 5518 return { 5519 fontName: "Math-Italic", 5520 fontClass: "mathdefault" 5521 }; 5522 } 5523}; 5524/** 5525 * Determines which of the two font names (Main-Bold and Math-BoldItalic) and 5526 * corresponding style tags (mathbf or boldsymbol) to use for font "boldsymbol", 5527 * depending on the symbol. Use this function instead of fontMap for font 5528 * "boldsymbol". 5529 */ 5530 5531 5532const boldsymbol = function boldsymbol(value, mode, options, classes) { 5533 if (lookupSymbol(value, "Math-BoldItalic", mode).metrics) { 5534 return { 5535 fontName: "Math-BoldItalic", 5536 fontClass: "boldsymbol" 5537 }; 5538 } else { 5539 // Some glyphs do not exist in Math-BoldItalic so we need to use 5540 // Main-Bold instead. 5541 return { 5542 fontName: "Main-Bold", 5543 fontClass: "mathbf" 5544 }; 5545 } 5546}; 5547/** 5548 * Makes either a mathord or textord in the correct font and color. 5549 */ 5550 5551 5552const makeOrd = function makeOrd(group, options, type) { 5553 const mode = group.mode; 5554 const text = group.text; 5555 const classes = ["mord"]; // Math mode or Old font (i.e. \rm) 5556 5557 const isFont = mode === "math" || mode === "text" && options.font; 5558 const fontOrFamily = isFont ? options.font : options.fontFamily; 5559 5560 if (text.charCodeAt(0) === 0xD835) { 5561 // surrogate pairs get special treatment 5562 const _wideCharacterFont = wideCharacterFont(text, mode), 5563 wideFontName = _wideCharacterFont[0], 5564 wideFontClass = _wideCharacterFont[1]; 5565 5566 return makeSymbol(text, wideFontName, mode, options, classes.concat(wideFontClass)); 5567 } else if (fontOrFamily) { 5568 let fontName; 5569 let fontClasses; 5570 5571 if (fontOrFamily === "boldsymbol" || fontOrFamily === "mathnormal") { 5572 const fontData = fontOrFamily === "boldsymbol" ? boldsymbol(text, mode, options, classes) : mathnormal(text, mode, options, classes); 5573 fontName = fontData.fontName; 5574 fontClasses = [fontData.fontClass]; 5575 } else if (utils.contains(mathitLetters, text)) { 5576 fontName = "Main-Italic"; 5577 fontClasses = ["mathit"]; 5578 } else if (isFont) { 5579 fontName = fontMap[fontOrFamily].fontName; 5580 fontClasses = [fontOrFamily]; 5581 } else { 5582 fontName = retrieveTextFontName(fontOrFamily, options.fontWeight, options.fontShape); 5583 fontClasses = [fontOrFamily, options.fontWeight, options.fontShape]; 5584 } 5585 5586 if (lookupSymbol(text, fontName, mode).metrics) { 5587 return makeSymbol(text, fontName, mode, options, classes.concat(fontClasses)); 5588 } else if (ligatures.hasOwnProperty(text) && fontName.substr(0, 10) === "Typewriter") { 5589 // Deconstruct ligatures in monospace fonts (\texttt, \tt). 5590 const parts = []; 5591 5592 for (let i = 0; i < text.length; i++) { 5593 parts.push(makeSymbol(text[i], fontName, mode, options, classes.concat(fontClasses))); 5594 } 5595 5596 return makeFragment(parts); 5597 } 5598 } // Makes a symbol in the default font for mathords and textords. 5599 5600 5601 if (type === "mathord") { 5602 const fontLookup = mathdefault(text, mode, options, classes); 5603 return makeSymbol(text, fontLookup.fontName, mode, options, classes.concat([fontLookup.fontClass])); 5604 } else if (type === "textord") { 5605 const font = symbols[mode][text] && symbols[mode][text].font; 5606 5607 if (font === "ams") { 5608 const fontName = retrieveTextFontName("amsrm", options.fontWeight, options.fontShape); 5609 return makeSymbol(text, fontName, mode, options, classes.concat("amsrm", options.fontWeight, options.fontShape)); 5610 } else if (font === "main" || !font) { 5611 const fontName = retrieveTextFontName("textrm", options.fontWeight, options.fontShape); 5612 return makeSymbol(text, fontName, mode, options, classes.concat(options.fontWeight, options.fontShape)); 5613 } else { 5614 // fonts added by plugins 5615 const fontName = retrieveTextFontName(font, options.fontWeight, options.fontShape); // We add font name as a css class 5616 5617 return makeSymbol(text, fontName, mode, options, classes.concat(fontName, options.fontWeight, options.fontShape)); 5618 } 5619 } else { 5620 throw new Error("unexpected type: " + type + " in makeOrd"); 5621 } 5622}; 5623/** 5624 * Returns true if subsequent symbolNodes have the same classes, skew, maxFont, 5625 * and styles. 5626 */ 5627 5628 5629const canCombine = (prev, next) => { 5630 if (createClass(prev.classes) !== createClass(next.classes) || prev.skew !== next.skew || prev.maxFontSize !== next.maxFontSize) { 5631 return false; 5632 } 5633 5634 for (const style in prev.style) { 5635 if (prev.style.hasOwnProperty(style) && prev.style[style] !== next.style[style]) { 5636 return false; 5637 } 5638 } 5639 5640 for (const style in next.style) { 5641 if (next.style.hasOwnProperty(style) && prev.style[style] !== next.style[style]) { 5642 return false; 5643 } 5644 } 5645 5646 return true; 5647}; 5648/** 5649 * Combine consequetive domTree.symbolNodes into a single symbolNode. 5650 * Note: this function mutates the argument. 5651 */ 5652 5653 5654const tryCombineChars = chars => { 5655 for (let i = 0; i < chars.length - 1; i++) { 5656 const prev = chars[i]; 5657 const next = chars[i + 1]; 5658 5659 if (prev instanceof SymbolNode && next instanceof SymbolNode && canCombine(prev, next)) { 5660 prev.text += next.text; 5661 prev.height = Math.max(prev.height, next.height); 5662 prev.depth = Math.max(prev.depth, next.depth); // Use the last character's italic correction since we use 5663 // it to add padding to the right of the span created from 5664 // the combined characters. 5665 5666 prev.italic = next.italic; 5667 chars.splice(i + 1, 1); 5668 i--; 5669 } 5670 } 5671 5672 return chars; 5673}; 5674/** 5675 * Calculate the height, depth, and maxFontSize of an element based on its 5676 * children. 5677 */ 5678 5679 5680const sizeElementFromChildren = function sizeElementFromChildren(elem) { 5681 let height = 0; 5682 let depth = 0; 5683 let maxFontSize = 0; 5684 5685 for (let i = 0; i < elem.children.length; i++) { 5686 const child = elem.children[i]; 5687 5688 if (child.height > height) { 5689 height = child.height; 5690 } 5691 5692 if (child.depth > depth) { 5693 depth = child.depth; 5694 } 5695 5696 if (child.maxFontSize > maxFontSize) { 5697 maxFontSize = child.maxFontSize; 5698 } 5699 } 5700 5701 elem.height = height; 5702 elem.depth = depth; 5703 elem.maxFontSize = maxFontSize; 5704}; 5705/** 5706 * Makes a span with the given list of classes, list of children, and options. 5707 * 5708 * TODO(#953): Ensure that `options` is always provided (currently some call 5709 * sites don't pass it) and make the type below mandatory. 5710 * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which 5711 * should if present come first in `classes`. 5712 */ 5713 5714 5715const makeSpan = function makeSpan(classes, children, options, style) { 5716 const span = new Span(classes, children, options, style); 5717 sizeElementFromChildren(span); 5718 return span; 5719}; // SVG one is simpler -- doesn't require height, depth, max-font setting. 5720// This is also a separate method for typesafety. 5721 5722 5723const makeSvgSpan = (classes, children, options, style) => new Span(classes, children, options, style); 5724 5725const makeLineSpan = function makeLineSpan(className, options, thickness) { 5726 const line = makeSpan([className], [], options); 5727 line.height = Math.max(thickness || options.fontMetrics().defaultRuleThickness, options.minRuleThickness); 5728 line.style.borderBottomWidth = line.height + "em"; 5729 line.maxFontSize = 1.0; 5730 return line; 5731}; 5732/** 5733 * Makes an anchor with the given href, list of classes, list of children, 5734 * and options. 5735 */ 5736 5737 5738const makeAnchor = function makeAnchor(href, classes, children, options) { 5739 const anchor = new Anchor(href, classes, children, options); 5740 sizeElementFromChildren(anchor); 5741 return anchor; 5742}; 5743/** 5744 * Makes a document fragment with the given list of children. 5745 */ 5746 5747 5748const makeFragment = function makeFragment(children) { 5749 const fragment = new DocumentFragment(children); 5750 sizeElementFromChildren(fragment); 5751 return fragment; 5752}; 5753/** 5754 * Wraps group in a span if it's a document fragment, allowing to apply classes 5755 * and styles 5756 */ 5757 5758 5759const wrapFragment = function wrapFragment(group, options) { 5760 if (group instanceof DocumentFragment) { 5761 return makeSpan([], [group], options); 5762 } 5763 5764 return group; 5765}; // These are exact object types to catch typos in the names of the optional fields. 5766 5767 5768// Computes the updated `children` list and the overall depth. 5769// 5770// This helper function for makeVList makes it easier to enforce type safety by 5771// allowing early exits (returns) in the logic. 5772const getVListChildrenAndDepth = function getVListChildrenAndDepth(params) { 5773 if (params.positionType === "individualShift") { 5774 const oldChildren = params.children; 5775 const children = [oldChildren[0]]; // Add in kerns to the list of params.children to get each element to be 5776 // shifted to the correct specified shift 5777 5778 const depth = -oldChildren[0].shift - oldChildren[0].elem.depth; 5779 let currPos = depth; 5780 5781 for (let i = 1; i < oldChildren.length; i++) { 5782 const diff = -oldChildren[i].shift - currPos - oldChildren[i].elem.depth; 5783 const size = diff - (oldChildren[i - 1].elem.height + oldChildren[i - 1].elem.depth); 5784 currPos = currPos + diff; 5785 children.push({ 5786 type: "kern", 5787 size 5788 }); 5789 children.push(oldChildren[i]); 5790 } 5791 5792 return { 5793 children, 5794 depth 5795 }; 5796 } 5797 5798 let depth; 5799 5800 if (params.positionType === "top") { 5801 // We always start at the bottom, so calculate the bottom by adding up 5802 // all the sizes 5803 let bottom = params.positionData; 5804 5805 for (let i = 0; i < params.children.length; i++) { 5806 const child = params.children[i]; 5807 bottom -= child.type === "kern" ? child.size : child.elem.height + child.elem.depth; 5808 } 5809 5810 depth = bottom; 5811 } else if (params.positionType === "bottom") { 5812 depth = -params.positionData; 5813 } else { 5814 const firstChild = params.children[0]; 5815 5816 if (firstChild.type !== "elem") { 5817 throw new Error('First child must have type "elem".'); 5818 } 5819 5820 if (params.positionType === "shift") { 5821 depth = -firstChild.elem.depth - params.positionData; 5822 } else if (params.positionType === "firstBaseline") { 5823 depth = -firstChild.elem.depth; 5824 } else { 5825 throw new Error(`Invalid positionType ${params.positionType}.`); 5826 } 5827 } 5828 5829 return { 5830 children: params.children, 5831 depth 5832 }; 5833}; 5834/** 5835 * Makes a vertical list by stacking elements and kerns on top of each other. 5836 * Allows for many different ways of specifying the positioning method. 5837 * 5838 * See VListParam documentation above. 5839 */ 5840 5841 5842const makeVList = function makeVList(params, options) { 5843 const _getVListChildrenAndD = getVListChildrenAndDepth(params), 5844 children = _getVListChildrenAndD.children, 5845 depth = _getVListChildrenAndD.depth; // Create a strut that is taller than any list item. The strut is added to 5846 // each item, where it will determine the item's baseline. Since it has 5847 // `overflow:hidden`, the strut's top edge will sit on the item's line box's 5848 // top edge and the strut's bottom edge will sit on the item's baseline, 5849 // with no additional line-height spacing. This allows the item baseline to 5850 // be positioned precisely without worrying about font ascent and 5851 // line-height. 5852 5853 5854 let pstrutSize = 0; 5855 5856 for (let i = 0; i < children.length; i++) { 5857 const child = children[i]; 5858 5859 if (child.type === "elem") { 5860 const elem = child.elem; 5861 pstrutSize = Math.max(pstrutSize, elem.maxFontSize, elem.height); 5862 } 5863 } 5864 5865 pstrutSize += 2; 5866 const pstrut = makeSpan(["pstrut"], []); 5867 pstrut.style.height = pstrutSize + "em"; // Create a new list of actual children at the correct offsets 5868 5869 const realChildren = []; 5870 let minPos = depth; 5871 let maxPos = depth; 5872 let currPos = depth; 5873 5874 for (let i = 0; i < children.length; i++) { 5875 const child = children[i]; 5876 5877 if (child.type === "kern") { 5878 currPos += child.size; 5879 } else { 5880 const elem = child.elem; 5881 const classes = child.wrapperClasses || []; 5882 const style = child.wrapperStyle || {}; 5883 const childWrap = makeSpan(classes, [pstrut, elem], undefined, style); 5884 childWrap.style.top = -pstrutSize - currPos - elem.depth + "em"; 5885 5886 if (child.marginLeft) { 5887 childWrap.style.marginLeft = child.marginLeft; 5888 } 5889 5890 if (child.marginRight) { 5891 childWrap.style.marginRight = child.marginRight; 5892 } 5893 5894 realChildren.push(childWrap); 5895 currPos += elem.height + elem.depth; 5896 } 5897 5898 minPos = Math.min(minPos, currPos); 5899 maxPos = Math.max(maxPos, currPos); 5900 } // The vlist contents go in a table-cell with `vertical-align:bottom`. 5901 // This cell's bottom edge will determine the containing table's baseline 5902 // without overly expanding the containing line-box. 5903 5904 5905 const vlist = makeSpan(["vlist"], realChildren); 5906 vlist.style.height = maxPos + "em"; // A second row is used if necessary to represent the vlist's depth. 5907 5908 let rows; 5909 5910 if (minPos < 0) { 5911 // We will define depth in an empty span with display: table-cell. 5912 // It should render with the height that we define. But Chrome, in 5913 // contenteditable mode only, treats that span as if it contains some 5914 // text content. And that min-height over-rides our desired height. 5915 // So we put another empty span inside the depth strut span. 5916 const emptySpan = makeSpan([], []); 5917 const depthStrut = makeSpan(["vlist"], [emptySpan]); 5918 depthStrut.style.height = -minPos + "em"; // Safari wants the first row to have inline content; otherwise it 5919 // puts the bottom of the *second* row on the baseline. 5920 5921 const topStrut = makeSpan(["vlist-s"], [new SymbolNode("\u200b")]); 5922 rows = [makeSpan(["vlist-r"], [vlist, topStrut]), makeSpan(["vlist-r"], [depthStrut])]; 5923 } else { 5924 rows = [makeSpan(["vlist-r"], [vlist])]; 5925 } 5926 5927 const vtable = makeSpan(["vlist-t"], rows); 5928 5929 if (rows.length === 2) { 5930 vtable.classes.push("vlist-t2"); 5931 } 5932 5933 vtable.height = maxPos; 5934 vtable.depth = -minPos; 5935 return vtable; 5936}; // Glue is a concept from TeX which is a flexible space between elements in 5937// either a vertical or horizontal list. In KaTeX, at least for now, it's 5938// static space between elements in a horizontal layout. 5939 5940 5941const makeGlue = (measurement, options) => { 5942 // Make an empty span for the space 5943 const rule = makeSpan(["mspace"], [], options); 5944 const size = calculateSize(measurement, options); 5945 rule.style.marginRight = `${size}em`; 5946 return rule; 5947}; // Takes font options, and returns the appropriate fontLookup name 5948 5949 5950const retrieveTextFontName = function retrieveTextFontName(fontFamily, fontWeight, fontShape) { 5951 let baseFontName = ""; 5952 5953 switch (fontFamily) { 5954 case "amsrm": 5955 baseFontName = "AMS"; 5956 break; 5957 5958 case "textrm": 5959 baseFontName = "Main"; 5960 break; 5961 5962 case "textsf": 5963 baseFontName = "SansSerif"; 5964 break; 5965 5966 case "texttt": 5967 baseFontName = "Typewriter"; 5968 break; 5969 5970 default: 5971 baseFontName = fontFamily; 5972 // use fonts added by a plugin 5973 } 5974 5975 let fontStylesName; 5976 5977 if (fontWeight === "textbf" && fontShape === "textit") { 5978 fontStylesName = "BoldItalic"; 5979 } else if (fontWeight === "textbf") { 5980 fontStylesName = "Bold"; 5981 } else if (fontWeight === "textit") { 5982 fontStylesName = "Italic"; 5983 } else { 5984 fontStylesName = "Regular"; 5985 } 5986 5987 return `${baseFontName}-${fontStylesName}`; 5988}; 5989/** 5990 * Maps TeX font commands to objects containing: 5991 * - variant: string used for "mathvariant" attribute in buildMathML.js 5992 * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics 5993 */ 5994// A map between tex font commands an MathML mathvariant attribute values 5995 5996 5997const fontMap = { 5998 // styles 5999 "mathbf": { 6000 variant: "bold", 6001 fontName: "Main-Bold" 6002 }, 6003 "mathrm": { 6004 variant: "normal", 6005 fontName: "Main-Regular" 6006 }, 6007 "textit": { 6008 variant: "italic", 6009 fontName: "Main-Italic" 6010 }, 6011 "mathit": { 6012 variant: "italic", 6013 fontName: "Main-Italic" 6014 }, 6015 // Default math font, "mathnormal" and "boldsymbol" are missing because they 6016 // require the use of several fonts: Main-Italic and Math-Italic for default 6017 // math font, Main-Italic, Math-Italic, Caligraphic for "mathnormal", and 6018 // Math-BoldItalic and Main-Bold for "boldsymbol". This is handled by a 6019 // special case in makeOrd which ends up calling mathdefault, mathnormal, 6020 // and boldsymbol. 6021 // families 6022 "mathbb": { 6023 variant: "double-struck", 6024 fontName: "AMS-Regular" 6025 }, 6026 "mathcal": { 6027 variant: "script", 6028 fontName: "Caligraphic-Regular" 6029 }, 6030 "mathfrak": { 6031 variant: "fraktur", 6032 fontName: "Fraktur-Regular" 6033 }, 6034 "mathscr": { 6035 variant: "script", 6036 fontName: "Script-Regular" 6037 }, 6038 "mathsf": { 6039 variant: "sans-serif", 6040 fontName: "SansSerif-Regular" 6041 }, 6042 "mathtt": { 6043 variant: "monospace", 6044 fontName: "Typewriter-Regular" 6045 } 6046}; 6047const svgData = { 6048 // path, width, height 6049 vec: ["vec", 0.471, 0.714], 6050 // values from the font glyph 6051 oiintSize1: ["oiintSize1", 0.957, 0.499], 6052 // oval to overlay the integrand 6053 oiintSize2: ["oiintSize2", 1.472, 0.659], 6054 oiiintSize1: ["oiiintSize1", 1.304, 0.499], 6055 oiiintSize2: ["oiiintSize2", 1.98, 0.659] 6056}; 6057 6058const staticSvg = function staticSvg(value, options) { 6059 // Create a span with inline SVG for the element. 6060 const _svgData$value = svgData[value], 6061 pathName = _svgData$value[0], 6062 width = _svgData$value[1], 6063 height = _svgData$value[2]; 6064 const path = new PathNode(pathName); 6065 const svgNode = new SvgNode([path], { 6066 "width": width + "em", 6067 "height": height + "em", 6068 // Override CSS rule `.katex svg { width: 100% }` 6069 "style": "width:" + width + "em", 6070 "viewBox": "0 0 " + 1000 * width + " " + 1000 * height, 6071 "preserveAspectRatio": "xMinYMin" 6072 }); 6073 const span = makeSvgSpan(["overlay"], [svgNode], options); 6074 span.height = height; 6075 span.style.height = height + "em"; 6076 span.style.width = width + "em"; 6077 return span; 6078}; 6079 6080var buildCommon = { 6081 fontMap, 6082 makeSymbol, 6083 mathsym, 6084 makeSpan, 6085 makeSvgSpan, 6086 makeLineSpan, 6087 makeAnchor, 6088 makeFragment, 6089 wrapFragment, 6090 makeVList, 6091 makeOrd, 6092 makeGlue, 6093 staticSvg, 6094 svgData, 6095 tryCombineChars 6096}; 6097 6098/** 6099 * Asserts that the node is of the given type and returns it with stricter 6100 * typing. Throws if the node's type does not match. 6101 */ 6102function assertNodeType(node, type) { 6103 const typedNode = checkNodeType(node, type); 6104 6105 if (!typedNode) { 6106 throw new Error(`Expected node of type ${type}, but got ` + (node ? `node of type ${node.type}` : String(node))); 6107 } // $FlowFixMe: Unsure why. 6108 6109 6110 return typedNode; 6111} 6112/** 6113 * Returns the node more strictly typed iff it is of the given type. Otherwise, 6114 * returns null. 6115 */ 6116 6117function checkNodeType(node, type) { 6118 if (node && node.type === type) { 6119 // The definition of ParseNode<TYPE> doesn't communicate to flow that 6120 // `type: TYPE` (as that's not explicitly mentioned anywhere), though that 6121 // happens to be true for all our value types. 6122 // $FlowFixMe 6123 return node; 6124 } 6125 6126 return null; 6127} 6128/** 6129 * Asserts that the node is of the given type and returns it with stricter 6130 * typing. Throws if the node's type does not match. 6131 */ 6132 6133function assertAtomFamily(node, family) { 6134 const typedNode = checkAtomFamily(node, family); 6135 6136 if (!typedNode) { 6137 throw new Error(`Expected node of type "atom" and family "${family}", but got ` + (node ? node.type === "atom" ? `atom of family ${node.family}` : `node of type ${node.type}` : String(node))); 6138 } 6139 6140 return typedNode; 6141} 6142/** 6143 * Returns the node more strictly typed iff it is of the given type. Otherwise, 6144 * returns null. 6145 */ 6146 6147function checkAtomFamily(node, family) { 6148 return node && node.type === "atom" && node.family === family ? node : null; 6149} 6150/** 6151 * Returns the node more strictly typed iff it is of the given type. Otherwise, 6152 * returns null. 6153 */ 6154 6155function assertSymbolNodeType(node) { 6156 const typedNode = checkSymbolNodeType(node); 6157 6158 if (!typedNode) { 6159 throw new Error(`Expected node of symbol group type, but got ` + (node ? `node of type ${node.type}` : String(node))); 6160 } 6161 6162 return typedNode; 6163} 6164/** 6165 * Returns the node more strictly typed iff it is of the given type. Otherwise, 6166 * returns null. 6167 */ 6168 6169function checkSymbolNodeType(node) { 6170 if (node && (node.type === "atom" || NON_ATOMS.hasOwnProperty(node.type))) { 6171 // $FlowFixMe 6172 return node; 6173 } 6174 6175 return null; 6176} 6177 6178/** 6179 * Describes spaces between different classes of atoms. 6180 */ 6181const thinspace = { 6182 number: 3, 6183 unit: "mu" 6184}; 6185const mediumspace = { 6186 number: 4, 6187 unit: "mu" 6188}; 6189const thickspace = { 6190 number: 5, 6191 unit: "mu" 6192}; // Making the type below exact with all optional fields doesn't work due to 6193// - https://github.com/facebook/flow/issues/4582 6194// - https://github.com/facebook/flow/issues/5688 6195// However, since *all* fields are optional, $Shape<> works as suggested in 5688 6196// above. 6197 6198// Spacing relationships for display and text styles 6199const spacings = { 6200 mord: { 6201 mop: thinspace, 6202 mbin: mediumspace, 6203 mrel: thickspace, 6204 minner: thinspace 6205 }, 6206 mop: { 6207 mord: thinspace, 6208 mop: thinspace, 6209 mrel: thickspace, 6210 minner: thinspace 6211 }, 6212 mbin: { 6213 mord: mediumspace, 6214 mop: mediumspace, 6215 mopen: mediumspace, 6216 minner: mediumspace 6217 }, 6218 mrel: { 6219 mord: thickspace, 6220 mop: thickspace, 6221 mopen: thickspace, 6222 minner: thickspace 6223 }, 6224 mopen: {}, 6225 mclose: { 6226 mop: thinspace, 6227 mbin: mediumspace, 6228 mrel: thickspace, 6229 minner: thinspace 6230 }, 6231 mpunct: { 6232 mord: thinspace, 6233 mop: thinspace, 6234 mrel: thickspace, 6235 mopen: thinspace, 6236 mclose: thinspace, 6237 mpunct: thinspace, 6238 minner: thinspace 6239 }, 6240 minner: { 6241 mord: thinspace, 6242 mop: thinspace, 6243 mbin: mediumspace, 6244 mrel: thickspace, 6245 mopen: thinspace, 6246 mpunct: thinspace, 6247 minner: thinspace 6248 } 6249}; // Spacing relationships for script and scriptscript styles 6250 6251const tightSpacings = { 6252 mord: { 6253 mop: thinspace 6254 }, 6255 mop: { 6256 mord: thinspace, 6257 mop: thinspace 6258 }, 6259 mbin: {}, 6260 mrel: {}, 6261 mopen: {}, 6262 mclose: { 6263 mop: thinspace 6264 }, 6265 mpunct: {}, 6266 minner: { 6267 mop: thinspace 6268 } 6269}; 6270 6271/** 6272 * All registered functions. 6273 * `functions.js` just exports this same dictionary again and makes it public. 6274 * `Parser.js` requires this dictionary. 6275 */ 6276const _functions = {}; 6277/** 6278 * All HTML builders. Should be only used in the `define*` and the `build*ML` 6279 * functions. 6280 */ 6281 6282const _htmlGroupBuilders = {}; 6283/** 6284 * All MathML builders. Should be only used in the `define*` and the `build*ML` 6285 * functions. 6286 */ 6287 6288const _mathmlGroupBuilders = {}; 6289function defineFunction(_ref) { 6290 let type = _ref.type, 6291 names = _ref.names, 6292 props = _ref.props, 6293 handler = _ref.handler, 6294 htmlBuilder = _ref.htmlBuilder, 6295 mathmlBuilder = _ref.mathmlBuilder; 6296 // Set default values of functions 6297 const data = { 6298 type, 6299 numArgs: props.numArgs, 6300 argTypes: props.argTypes, 6301 greediness: props.greediness === undefined ? 1 : props.greediness, 6302 allowedInText: !!props.allowedInText, 6303 allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, 6304 numOptionalArgs: props.numOptionalArgs || 0, 6305 infix: !!props.infix, 6306 handler: handler 6307 }; 6308 6309 for (let i = 0; i < names.length; ++i) { 6310 _functions[names[i]] = data; 6311 } 6312 6313 if (type) { 6314 if (htmlBuilder) { 6315 _htmlGroupBuilders[type] = htmlBuilder; 6316 } 6317 6318 if (mathmlBuilder) { 6319 _mathmlGroupBuilders[type] = mathmlBuilder; 6320 } 6321 } 6322} 6323/** 6324 * Use this to register only the HTML and MathML builders for a function (e.g. 6325 * if the function's ParseNode is generated in Parser.js rather than via a 6326 * stand-alone handler provided to `defineFunction`). 6327 */ 6328 6329function defineFunctionBuilders(_ref2) { 6330 let type = _ref2.type, 6331 htmlBuilder = _ref2.htmlBuilder, 6332 mathmlBuilder = _ref2.mathmlBuilder; 6333 defineFunction({ 6334 type, 6335 names: [], 6336 props: { 6337 numArgs: 0 6338 }, 6339 6340 handler() { 6341 throw new Error('Should never be called.'); 6342 }, 6343 6344 htmlBuilder, 6345 mathmlBuilder 6346 }); 6347} // Since the corresponding buildHTML/buildMathML function expects a 6348// list of elements, we normalize for different kinds of arguments 6349 6350const ordargument = function ordargument(arg) { 6351 const node = checkNodeType(arg, "ordgroup"); 6352 return node ? node.body : [arg]; 6353}; 6354 6355/** 6356 * This file does the main work of building a domTree structure from a parse 6357 * tree. The entry point is the `buildHTML` function, which takes a parse tree. 6358 * Then, the buildExpression, buildGroup, and various groupBuilders functions 6359 * are called, to produce a final HTML tree. 6360 */ 6361const makeSpan$1 = buildCommon.makeSpan; // Binary atoms (first class `mbin`) change into ordinary atoms (`mord`) 6362// depending on their surroundings. See TeXbook pg. 442-446, Rules 5 and 6, 6363// and the text before Rule 19. 6364 6365const binLeftCanceller = ["leftmost", "mbin", "mopen", "mrel", "mop", "mpunct"]; 6366const binRightCanceller = ["rightmost", "mrel", "mclose", "mpunct"]; 6367const styleMap = { 6368 "display": Style$1.DISPLAY, 6369 "text": Style$1.TEXT, 6370 "script": Style$1.SCRIPT, 6371 "scriptscript": Style$1.SCRIPTSCRIPT 6372}; 6373const DomEnum = { 6374 mord: "mord", 6375 mop: "mop", 6376 mbin: "mbin", 6377 mrel: "mrel", 6378 mopen: "mopen", 6379 mclose: "mclose", 6380 mpunct: "mpunct", 6381 minner: "minner" 6382}; 6383 6384/** 6385 * Take a list of nodes, build them in order, and return a list of the built 6386 * nodes. documentFragments are flattened into their contents, so the 6387 * returned list contains no fragments. `isRealGroup` is true if `expression` 6388 * is a real group (no atoms will be added on either side), as opposed to 6389 * a partial group (e.g. one created by \color). `surrounding` is an array 6390 * consisting type of nodes that will be added to the left and right. 6391 */ 6392const buildExpression = function buildExpression(expression, options, isRealGroup, surrounding) { 6393 if (surrounding === void 0) { 6394 surrounding = [null, null]; 6395 } 6396 6397 // Parse expressions into `groups`. 6398 const groups = []; 6399 6400 for (let i = 0; i < expression.length; i++) { 6401 const output = buildGroup(expression[i], options); 6402 6403 if (output instanceof DocumentFragment) { 6404 const children = output.children; 6405 groups.push(...children); 6406 } else { 6407 groups.push(output); 6408 } 6409 } // If `expression` is a partial group, let the parent handle spacings 6410 // to avoid processing groups multiple times. 6411 6412 6413 if (!isRealGroup) { 6414 return groups; 6415 } 6416 6417 let glueOptions = options; 6418 6419 if (expression.length === 1) { 6420 const node = checkNodeType(expression[0], "sizing") || checkNodeType(expression[0], "styling"); 6421 6422 if (!node) ; else if (node.type === "sizing") { 6423 glueOptions = options.havingSize(node.size); 6424 } else if (node.type === "styling") { 6425 glueOptions = options.havingStyle(styleMap[node.style]); 6426 } 6427 } // Dummy spans for determining spacings between surrounding atoms. 6428 // If `expression` has no atoms on the left or right, class "leftmost" 6429 // or "rightmost", respectively, is used to indicate it. 6430 6431 6432 const dummyPrev = makeSpan$1([surrounding[0] || "leftmost"], [], options); 6433 const dummyNext = makeSpan$1([surrounding[1] || "rightmost"], [], options); // TODO: These code assumes that a node's math class is the first element 6434 // of its `classes` array. A later cleanup should ensure this, for 6435 // instance by changing the signature of `makeSpan`. 6436 // Before determining what spaces to insert, perform bin cancellation. 6437 // Binary operators change to ordinary symbols in some contexts. 6438 6439 traverseNonSpaceNodes(groups, (node, prev) => { 6440 const prevType = prev.classes[0]; 6441 const type = node.classes[0]; 6442 6443 if (prevType === "mbin" && utils.contains(binRightCanceller, type)) { 6444 prev.classes[0] = "mord"; 6445 } else if (type === "mbin" && utils.contains(binLeftCanceller, prevType)) { 6446 node.classes[0] = "mord"; 6447 } 6448 }, { 6449 node: dummyPrev 6450 }, dummyNext); 6451 traverseNonSpaceNodes(groups, (node, prev) => { 6452 const prevType = getTypeOfDomTree(prev); 6453 const type = getTypeOfDomTree(node); // 'mtight' indicates that the node is script or scriptscript style. 6454 6455 const space = prevType && type ? node.hasClass("mtight") ? tightSpacings[prevType][type] : spacings[prevType][type] : null; 6456 6457 if (space) { 6458 // Insert glue (spacing) after the `prev`. 6459 return buildCommon.makeGlue(space, glueOptions); 6460 } 6461 }, { 6462 node: dummyPrev 6463 }, dummyNext); 6464 return groups; 6465}; // Depth-first traverse non-space `nodes`, calling `callback` with the current and 6466// previous node as arguments, optionally returning a node to insert after the 6467// previous node. `prev` is an object with the previous node and `insertAfter` 6468// function to insert after it. `next` is a node that will be added to the right. 6469// Used for bin cancellation and inserting spacings. 6470 6471const traverseNonSpaceNodes = function traverseNonSpaceNodes(nodes, callback, prev, next) { 6472 if (next) { 6473 // temporarily append the right node, if exists 6474 nodes.push(next); 6475 } 6476 6477 let i = 0; 6478 6479 for (; i < nodes.length; i++) { 6480 const node = nodes[i]; 6481 const partialGroup = checkPartialGroup(node); 6482 6483 if (partialGroup) { 6484 // Recursive DFS 6485 // $FlowFixMe: make nodes a $ReadOnlyArray by returning a new array 6486 traverseNonSpaceNodes(partialGroup.children, callback, prev); 6487 continue; 6488 } // Ignore explicit spaces (e.g., \;, \,) when determining what implicit 6489 // spacing should go between atoms of different classes 6490 6491 6492 if (node.classes[0] === "mspace") { 6493 continue; 6494 } 6495 6496 const result = callback(node, prev.node); 6497 6498 if (result) { 6499 if (prev.insertAfter) { 6500 prev.insertAfter(result); 6501 } else { 6502 // insert at front 6503 nodes.unshift(result); 6504 i++; 6505 } 6506 } 6507 6508 prev.node = node; 6509 6510 prev.insertAfter = (index => n => { 6511 nodes.splice(index + 1, 0, n); 6512 i++; 6513 })(i); 6514 } 6515 6516 if (next) { 6517 nodes.pop(); 6518 } 6519}; // Check if given node is a partial group, i.e., does not affect spacing around. 6520 6521 6522const checkPartialGroup = function checkPartialGroup(node) { 6523 if (node instanceof DocumentFragment || node instanceof Anchor) { 6524 return node; 6525 } 6526 6527 return null; 6528}; // Return the outermost node of a domTree. 6529 6530 6531const getOutermostNode = function getOutermostNode(node, side) { 6532 const partialGroup = checkPartialGroup(node); 6533 6534 if (partialGroup) { 6535 const children = partialGroup.children; 6536 6537 if (children.length) { 6538 if (side === "right") { 6539 return getOutermostNode(children[children.length - 1], "right"); 6540 } else if (side === "left") { 6541 return getOutermostNode(children[0], "left"); 6542 } 6543 } 6544 } 6545 6546 return node; 6547}; // Return math atom class (mclass) of a domTree. 6548// If `side` is given, it will get the type of the outermost node at given side. 6549 6550 6551const getTypeOfDomTree = function getTypeOfDomTree(node, side) { 6552 if (!node) { 6553 return null; 6554 } 6555 6556 if (side) { 6557 node = getOutermostNode(node, side); 6558 } // This makes a lot of assumptions as to where the type of atom 6559 // appears. We should do a better job of enforcing this. 6560 6561 6562 return DomEnum[node.classes[0]] || null; 6563}; 6564const makeNullDelimiter = function makeNullDelimiter(options, classes) { 6565 const moreClasses = ["nulldelimiter"].concat(options.baseSizingClasses()); 6566 return makeSpan$1(classes.concat(moreClasses)); 6567}; 6568/** 6569 * buildGroup is the function that takes a group and calls the correct groupType 6570 * function for it. It also handles the interaction of size and style changes 6571 * between parents and children. 6572 */ 6573 6574const buildGroup = function buildGroup(group, options, baseOptions) { 6575 if (!group) { 6576 return makeSpan$1(); 6577 } 6578 6579 if (_htmlGroupBuilders[group.type]) { 6580 // Call the groupBuilders function 6581 let groupNode = _htmlGroupBuilders[group.type](group, options); // If the size changed between the parent and the current group, account 6582 // for that size difference. 6583 6584 if (baseOptions && options.size !== baseOptions.size) { 6585 groupNode = makeSpan$1(options.sizingClasses(baseOptions), [groupNode], options); 6586 const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; 6587 groupNode.height *= multiplier; 6588 groupNode.depth *= multiplier; 6589 } 6590 6591 return groupNode; 6592 } else { 6593 throw new ParseError("Got group of unknown type: '" + group.type + "'"); 6594 } 6595}; 6596/** 6597 * Combine an array of HTML DOM nodes (e.g., the output of `buildExpression`) 6598 * into an unbreakable HTML node of class .base, with proper struts to 6599 * guarantee correct vertical extent. `buildHTML` calls this repeatedly to 6600 * make up the entire expression as a sequence of unbreakable units. 6601 */ 6602 6603function buildHTMLUnbreakable(children, options) { 6604 // Compute height and depth of this chunk. 6605 const body = makeSpan$1(["base"], children, options); // Add strut, which ensures that the top of the HTML element falls at 6606 // the height of the expression, and the bottom of the HTML element 6607 // falls at the depth of the expression. 6608 // We used to have separate top and bottom struts, where the bottom strut 6609 // would like to use `vertical-align: top`, but in IE 9 this lowers the 6610 // baseline of the box to the bottom of this strut (instead of staying in 6611 // the normal place) so we use an absolute value for vertical-align instead. 6612 6613 const strut = makeSpan$1(["strut"]); 6614 strut.style.height = body.height + body.depth + "em"; 6615 strut.style.verticalAlign = -body.depth + "em"; 6616 body.children.unshift(strut); 6617 return body; 6618} 6619/** 6620 * Take an entire parse tree, and build it into an appropriate set of HTML 6621 * nodes. 6622 */ 6623 6624 6625function buildHTML(tree, options) { 6626 // Strip off outer tag wrapper for processing below. 6627 let tag = null; 6628 6629 if (tree.length === 1 && tree[0].type === "tag") { 6630 tag = tree[0].tag; 6631 tree = tree[0].body; 6632 } // Build the expression contained in the tree 6633 6634 6635 const expression = buildExpression(tree, options, true); 6636 const children = []; // Create one base node for each chunk between potential line breaks. 6637 // The TeXBook [p.173] says "A formula will be broken only after a 6638 // relation symbol like $=$ or $<$ or $\rightarrow$, or after a binary 6639 // operation symbol like $+$ or $-$ or $\times$, where the relation or 6640 // binary operation is on the ``outer level'' of the formula (i.e., not 6641 // enclosed in {...} and not part of an \over construction)." 6642 6643 let parts = []; 6644 6645 for (let i = 0; i < expression.length; i++) { 6646 parts.push(expression[i]); 6647 6648 if (expression[i].hasClass("mbin") || expression[i].hasClass("mrel") || expression[i].hasClass("allowbreak")) { 6649 // Put any post-operator glue on same line as operator. 6650 // Watch for \nobreak along the way, and stop at \newline. 6651 let nobreak = false; 6652 6653 while (i < expression.length - 1 && expression[i + 1].hasClass("mspace") && !expression[i + 1].hasClass("newline")) { 6654 i++; 6655 parts.push(expression[i]); 6656 6657 if (expression[i].hasClass("nobreak")) { 6658 nobreak = true; 6659 } 6660 } // Don't allow break if \nobreak among the post-operator glue. 6661 6662 6663 if (!nobreak) { 6664 children.push(buildHTMLUnbreakable(parts, options)); 6665 parts = []; 6666 } 6667 } else if (expression[i].hasClass("newline")) { 6668 // Write the line except the newline 6669 parts.pop(); 6670 6671 if (parts.length > 0) { 6672 children.push(buildHTMLUnbreakable(parts, options)); 6673 parts = []; 6674 } // Put the newline at the top level 6675 6676 6677 children.push(expression[i]); 6678 } 6679 } 6680 6681 if (parts.length > 0) { 6682 children.push(buildHTMLUnbreakable(parts, options)); 6683 } // Now, if there was a tag, build it too and append it as a final child. 6684 6685 6686 let tagChild; 6687 6688 if (tag) { 6689 tagChild = buildHTMLUnbreakable(buildExpression(tag, options, true)); 6690 tagChild.classes = ["tag"]; 6691 children.push(tagChild); 6692 } 6693 6694 const htmlNode = makeSpan$1(["katex-html"], children); 6695 htmlNode.setAttribute("aria-hidden", "true"); // Adjust the strut of the tag to be the maximum height of all children 6696 // (the height of the enclosing htmlNode) for proper vertical alignment. 6697 6698 if (tagChild) { 6699 const strut = tagChild.children[0]; 6700 strut.style.height = htmlNode.height + htmlNode.depth + "em"; 6701 strut.style.verticalAlign = -htmlNode.depth + "em"; 6702 } 6703 6704 return htmlNode; 6705} 6706 6707/** 6708 * These objects store data about MathML nodes. This is the MathML equivalent 6709 * of the types in domTree.js. Since MathML handles its own rendering, and 6710 * since we're mainly using MathML to improve accessibility, we don't manage 6711 * any of the styling state that the plain DOM nodes do. 6712 * 6713 * The `toNode` and `toMarkup` functions work simlarly to how they do in 6714 * domTree.js, creating namespaced DOM nodes and HTML text markup respectively. 6715 */ 6716function newDocumentFragment(children) { 6717 return new DocumentFragment(children); 6718} 6719/** 6720 * This node represents a general purpose MathML node of any type. The 6721 * constructor requires the type of node to create (for example, `"mo"` or 6722 * `"mspace"`, corresponding to `<mo>` and `<mspace>` tags). 6723 */ 6724 6725class MathNode { 6726 constructor(type, children) { 6727 this.type = void 0; 6728 this.attributes = void 0; 6729 this.children = void 0; 6730 this.type = type; 6731 this.attributes = {}; 6732 this.children = children || []; 6733 } 6734 /** 6735 * Sets an attribute on a MathML node. MathML depends on attributes to convey a 6736 * semantic content, so this is used heavily. 6737 */ 6738 6739 6740 setAttribute(name, value) { 6741 this.attributes[name] = value; 6742 } 6743 /** 6744 * Gets an attribute on a MathML node. 6745 */ 6746 6747 6748 getAttribute(name) { 6749 return this.attributes[name]; 6750 } 6751 /** 6752 * Converts the math node into a MathML-namespaced DOM element. 6753 */ 6754 6755 6756 toNode() { 6757 const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); 6758 6759 for (const attr in this.attributes) { 6760 if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { 6761 node.setAttribute(attr, this.attributes[attr]); 6762 } 6763 } 6764 6765 for (let i = 0; i < this.children.length; i++) { 6766 node.appendChild(this.children[i].toNode()); 6767 } 6768 6769 return node; 6770 } 6771 /** 6772 * Converts the math node into an HTML markup string. 6773 */ 6774 6775 6776 toMarkup() { 6777 let markup = "<" + this.type; // Add the attributes 6778 6779 for (const attr in this.attributes) { 6780 if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { 6781 markup += " " + attr + "=\""; 6782 markup += utils.escape(this.attributes[attr]); 6783 markup += "\""; 6784 } 6785 } 6786 6787 markup += ">"; 6788 6789 for (let i = 0; i < this.children.length; i++) { 6790 markup += this.children[i].toMarkup(); 6791 } 6792 6793 markup += "</" + this.type + ">"; 6794 return markup; 6795 } 6796 /** 6797 * Converts the math node into a string, similar to innerText, but escaped. 6798 */ 6799 6800 6801 toText() { 6802 return this.children.map(child => child.toText()).join(""); 6803 } 6804 6805} 6806/** 6807 * This node represents a piece of text. 6808 */ 6809 6810class TextNode { 6811 constructor(text) { 6812 this.text = void 0; 6813 this.text = text; 6814 } 6815 /** 6816 * Converts the text node into a DOM text node. 6817 */ 6818 6819 6820 toNode() { 6821 return document.createTextNode(this.text); 6822 } 6823 /** 6824 * Converts the text node into escaped HTML markup 6825 * (representing the text itself). 6826 */ 6827 6828 6829 toMarkup() { 6830 return utils.escape(this.toText()); 6831 } 6832 /** 6833 * Converts the text node into a string 6834 * (representing the text iteself). 6835 */ 6836 6837 6838 toText() { 6839 return this.text; 6840 } 6841 6842} 6843/** 6844 * This node represents a space, but may render as <mspace.../> or as text, 6845 * depending on the width. 6846 */ 6847 6848class SpaceNode { 6849 /** 6850 * Create a Space node with width given in CSS ems. 6851 */ 6852 constructor(width) { 6853 this.width = void 0; 6854 this.character = void 0; 6855 this.width = width; // See https://www.w3.org/TR/2000/WD-MathML2-20000328/chapter6.html 6856 // for a table of space-like characters. We use Unicode 6857 // representations instead of &LongNames; as it's not clear how to 6858 // make the latter via document.createTextNode. 6859 6860 if (width >= 0.05555 && width <= 0.05556) { 6861 this.character = "\u200a"; //   6862 } else if (width >= 0.1666 && width <= 0.1667) { 6863 this.character = "\u2009"; //   6864 } else if (width >= 0.2222 && width <= 0.2223) { 6865 this.character = "\u2005"; //   6866 } else if (width >= 0.2777 && width <= 0.2778) { 6867 this.character = "\u2005\u200a"; //    6868 } else if (width >= -0.05556 && width <= -0.05555) { 6869 this.character = "\u200a\u2063"; // ​ 6870 } else if (width >= -0.1667 && width <= -0.1666) { 6871 this.character = "\u2009\u2063"; // ​ 6872 } else if (width >= -0.2223 && width <= -0.2222) { 6873 this.character = "\u205f\u2063"; // ​ 6874 } else if (width >= -0.2778 && width <= -0.2777) { 6875 this.character = "\u2005\u2063"; // ​ 6876 } else { 6877 this.character = null; 6878 } 6879 } 6880 /** 6881 * Converts the math node into a MathML-namespaced DOM element. 6882 */ 6883 6884 6885 toNode() { 6886 if (this.character) { 6887 return document.createTextNode(this.character); 6888 } else { 6889 const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mspace"); 6890 node.setAttribute("width", this.width + "em"); 6891 return node; 6892 } 6893 } 6894 /** 6895 * Converts the math node into an HTML markup string. 6896 */ 6897 6898 6899 toMarkup() { 6900 if (this.character) { 6901 return `<mtext>${this.character}</mtext>`; 6902 } else { 6903 return `<mspace width="${this.width}em"/>`; 6904 } 6905 } 6906 /** 6907 * Converts the math node into a string, similar to innerText. 6908 */ 6909 6910 6911 toText() { 6912 if (this.character) { 6913 return this.character; 6914 } else { 6915 return " "; 6916 } 6917 } 6918 6919} 6920 6921var mathMLTree = { 6922 MathNode, 6923 TextNode, 6924 SpaceNode, 6925 newDocumentFragment 6926}; 6927 6928/** 6929 * This file converts a parse tree into a cooresponding MathML tree. The main 6930 * entry point is the `buildMathML` function, which takes a parse tree from the 6931 * parser. 6932 */ 6933 6934/** 6935 * Takes a symbol and converts it into a MathML text node after performing 6936 * optional replacement from symbols.js. 6937 */ 6938const makeText = function makeText(text, mode, options) { 6939 if (symbols[mode][text] && symbols[mode][text].replace && text.charCodeAt(0) !== 0xD835 && !(ligatures.hasOwnProperty(text) && options && (options.fontFamily && options.fontFamily.substr(4, 2) === "tt" || options.font && options.font.substr(4, 2) === "tt"))) { 6940 text = symbols[mode][text].replace; 6941 } 6942 6943 return new mathMLTree.TextNode(text); 6944}; 6945/** 6946 * Wrap the given array of nodes in an <mrow> node if needed, i.e., 6947 * unless the array has length 1. Always returns a single node. 6948 */ 6949 6950const makeRow = function makeRow(body) { 6951 if (body.length === 1) { 6952 return body[0]; 6953 } else { 6954 return new mathMLTree.MathNode("mrow", body); 6955 } 6956}; 6957/** 6958 * Returns the math variant as a string or null if none is required. 6959 */ 6960 6961const getVariant = function getVariant(group, options) { 6962 // Handle \text... font specifiers as best we can. 6963 // MathML has a limited list of allowable mathvariant specifiers; see 6964 // https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt 6965 if (options.fontFamily === "texttt") { 6966 return "monospace"; 6967 } else if (options.fontFamily === "textsf") { 6968 if (options.fontShape === "textit" && options.fontWeight === "textbf") { 6969 return "sans-serif-bold-italic"; 6970 } else if (options.fontShape === "textit") { 6971 return "sans-serif-italic"; 6972 } else if (options.fontWeight === "textbf") { 6973 return "bold-sans-serif"; 6974 } else { 6975 return "sans-serif"; 6976 } 6977 } else if (options.fontShape === "textit" && options.fontWeight === "textbf") { 6978 return "bold-italic"; 6979 } else if (options.fontShape === "textit") { 6980 return "italic"; 6981 } else if (options.fontWeight === "textbf") { 6982 return "bold"; 6983 } 6984 6985 const font = options.font; 6986 6987 if (!font || font === "mathnormal") { 6988 return null; 6989 } 6990 6991 const mode = group.mode; 6992 6993 if (font === "mathit") { 6994 return "italic"; 6995 } else if (font === "boldsymbol") { 6996 return "bold-italic"; 6997 } else if (font === "mathbf") { 6998 return "bold"; 6999 } else if (font === "mathbb") { 7000 return "double-struck"; 7001 } else if (font === "mathfrak") { 7002 return "fraktur"; 7003 } else if (font === "mathscr" || font === "mathcal") { 7004 // MathML makes no distinction between script and caligrahpic 7005 return "script"; 7006 } else if (font === "mathsf") { 7007 return "sans-serif"; 7008 } else if (font === "mathtt") { 7009 return "monospace"; 7010 } 7011 7012 let text = group.text; 7013 7014 if (utils.contains(["\\imath", "\\jmath"], text)) { 7015 return null; 7016 } 7017 7018 if (symbols[mode][text] && symbols[mode][text].replace) { 7019 text = symbols[mode][text].replace; 7020 } 7021 7022 const fontName = buildCommon.fontMap[font].fontName; 7023 7024 if (getCharacterMetrics(text, fontName, mode)) { 7025 return buildCommon.fontMap[font].variant; 7026 } 7027 7028 return null; 7029}; 7030/** 7031 * Takes a list of nodes, builds them, and returns a list of the generated 7032 * MathML nodes. Also combine consecutive <mtext> outputs into a single 7033 * <mtext> tag. 7034 */ 7035 7036const buildExpression$1 = function buildExpression(expression, options, isOrdgroup) { 7037 if (expression.length === 1) { 7038 const group = buildGroup$1(expression[0], options); 7039 7040 if (isOrdgroup && group instanceof MathNode && group.type === "mo") { 7041 // When TeX writers want to suppress spacing on an operator, 7042 // they often put the operator by itself inside braces. 7043 group.setAttribute("lspace", "0em"); 7044 group.setAttribute("rspace", "0em"); 7045 } 7046 7047 return [group]; 7048 } 7049 7050 const groups = []; 7051 let lastGroup; 7052 7053 for (let i = 0; i < expression.length; i++) { 7054 const group = buildGroup$1(expression[i], options); 7055 7056 if (group instanceof MathNode && lastGroup instanceof MathNode) { 7057 // Concatenate adjacent <mtext>s 7058 if (group.type === 'mtext' && lastGroup.type === 'mtext' && group.getAttribute('mathvariant') === lastGroup.getAttribute('mathvariant')) { 7059 lastGroup.children.push(...group.children); 7060 continue; // Concatenate adjacent <mn>s 7061 } else if (group.type === 'mn' && lastGroup.type === 'mn') { 7062 lastGroup.children.push(...group.children); 7063 continue; // Concatenate <mn>...</mn> followed by <mi>.</mi> 7064 } else if (group.type === 'mi' && group.children.length === 1 && lastGroup.type === 'mn') { 7065 const child = group.children[0]; 7066 7067 if (child instanceof TextNode && child.text === '.') { 7068 lastGroup.children.push(...group.children); 7069 continue; 7070 } 7071 } else if (lastGroup.type === 'mi' && lastGroup.children.length === 1) { 7072 const lastChild = lastGroup.children[0]; 7073 7074 if (lastChild instanceof TextNode && lastChild.text === '\u0338' && (group.type === 'mo' || group.type === 'mi' || group.type === 'mn')) { 7075 const child = group.children[0]; 7076 7077 if (child instanceof TextNode && child.text.length > 0) { 7078 // Overlay with combining character long solidus 7079 child.text = child.text.slice(0, 1) + "\u0338" + child.text.slice(1); 7080 groups.pop(); 7081 } 7082 } 7083 } 7084 } 7085 7086 groups.push(group); 7087 lastGroup = group; 7088 } 7089 7090 return groups; 7091}; 7092/** 7093 * Equivalent to buildExpression, but wraps the elements in an <mrow> 7094 * if there's more than one. Returns a single node instead of an array. 7095 */ 7096 7097const buildExpressionRow = function buildExpressionRow(expression, options, isOrdgroup) { 7098 return makeRow(buildExpression$1(expression, options, isOrdgroup)); 7099}; 7100/** 7101 * Takes a group from the parser and calls the appropriate groupBuilders function 7102 * on it to produce a MathML node. 7103 */ 7104 7105const buildGroup$1 = function buildGroup(group, options) { 7106 if (!group) { 7107 return new mathMLTree.MathNode("mrow"); 7108 } 7109 7110 if (_mathmlGroupBuilders[group.type]) { 7111 // Call the groupBuilders function 7112 const result = _mathmlGroupBuilders[group.type](group, options); 7113 return result; 7114 } else { 7115 throw new ParseError("Got group of unknown type: '" + group.type + "'"); 7116 } 7117}; 7118/** 7119 * Takes a full parse tree and settings and builds a MathML representation of 7120 * it. In particular, we put the elements from building the parse tree into a 7121 * <semantics> tag so we can also include that TeX source as an annotation. 7122 * 7123 * Note that we actually return a domTree element with a `<math>` inside it so 7124 * we can do appropriate styling. 7125 */ 7126 7127function buildMathML(tree, texExpression, options, forMathmlOnly) { 7128 const expression = buildExpression$1(tree, options); // Wrap up the expression in an mrow so it is presented in the semantics 7129 // tag correctly, unless it's a single <mrow> or <mtable>. 7130 7131 let wrapper; 7132 7133 if (expression.length === 1 && expression[0] instanceof MathNode && utils.contains(["mrow", "mtable"], expression[0].type)) { 7134 wrapper = expression[0]; 7135 } else { 7136 wrapper = new mathMLTree.MathNode("mrow", expression); 7137 } // Build a TeX annotation of the source 7138 7139 7140 const annotation = new mathMLTree.MathNode("annotation", [new mathMLTree.TextNode(texExpression)]); 7141 annotation.setAttribute("encoding", "application/x-tex"); 7142 const semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); 7143 const math = new mathMLTree.MathNode("math", [semantics]); 7144 math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); // You can't style <math> nodes, so we wrap the node in a span. 7145 // NOTE: The span class is not typed to have <math> nodes as children, and 7146 // we don't want to make the children type more generic since the children 7147 // of span are expected to have more fields in `buildHtml` contexts. 7148 7149 const wrapperClass = forMathmlOnly ? "katex" : "katex-mathml"; // $FlowFixMe 7150 7151 return buildCommon.makeSpan([wrapperClass], [math]); 7152} 7153 7154const optionsFromSettings = function optionsFromSettings(settings) { 7155 return new Options({ 7156 style: settings.displayMode ? Style$1.DISPLAY : Style$1.TEXT, 7157 maxSize: settings.maxSize, 7158 minRuleThickness: settings.minRuleThickness 7159 }); 7160}; 7161 7162const displayWrap = function displayWrap(node, settings) { 7163 if (settings.displayMode) { 7164 const classes = ["katex-display"]; 7165 7166 if (settings.leqno) { 7167 classes.push("leqno"); 7168 } 7169 7170 if (settings.fleqn) { 7171 classes.push("fleqn"); 7172 } 7173 7174 node = buildCommon.makeSpan(classes, [node]); 7175 } 7176 7177 return node; 7178}; 7179 7180const buildTree = function buildTree(tree, expression, settings) { 7181 const options = optionsFromSettings(settings); 7182 let katexNode; 7183 7184 if (settings.output === "mathml") { 7185 return buildMathML(tree, expression, options, true); 7186 } else if (settings.output === "html") { 7187 const htmlNode = buildHTML(tree, options); 7188 katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); 7189 } else { 7190 const mathMLNode = buildMathML(tree, expression, options, false); 7191 const htmlNode = buildHTML(tree, options); 7192 katexNode = buildCommon.makeSpan(["katex"], [mathMLNode, htmlNode]); 7193 } 7194 7195 return displayWrap(katexNode, settings); 7196}; 7197const buildHTMLTree = function buildHTMLTree(tree, expression, settings) { 7198 const options = optionsFromSettings(settings); 7199 const htmlNode = buildHTML(tree, options); 7200 const katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); 7201 return displayWrap(katexNode, settings); 7202}; 7203 7204/** 7205 * This file provides support to buildMathML.js and buildHTML.js 7206 * for stretchy wide elements rendered from SVG files 7207 * and other CSS trickery. 7208 */ 7209const stretchyCodePoint = { 7210 widehat: "^", 7211 widecheck: "ˇ", 7212 widetilde: "~", 7213 utilde: "~", 7214 overleftarrow: "\u2190", 7215 underleftarrow: "\u2190", 7216 xleftarrow: "\u2190", 7217 overrightarrow: "\u2192", 7218 underrightarrow: "\u2192", 7219 xrightarrow: "\u2192", 7220 underbrace: "\u23df", 7221 overbrace: "\u23de", 7222 overgroup: "\u23e0", 7223 undergroup: "\u23e1", 7224 overleftrightarrow: "\u2194", 7225 underleftrightarrow: "\u2194", 7226 xleftrightarrow: "\u2194", 7227 Overrightarrow: "\u21d2", 7228 xRightarrow: "\u21d2", 7229 overleftharpoon: "\u21bc", 7230 xleftharpoonup: "\u21bc", 7231 overrightharpoon: "\u21c0", 7232 xrightharpoonup: "\u21c0", 7233 xLeftarrow: "\u21d0", 7234 xLeftrightarrow: "\u21d4", 7235 xhookleftarrow: "\u21a9", 7236 xhookrightarrow: "\u21aa", 7237 xmapsto: "\u21a6", 7238 xrightharpoondown: "\u21c1", 7239 xleftharpoondown: "\u21bd", 7240 xrightleftharpoons: "\u21cc", 7241 xleftrightharpoons: "\u21cb", 7242 xtwoheadleftarrow: "\u219e", 7243 xtwoheadrightarrow: "\u21a0", 7244 xlongequal: "=", 7245 xtofrom: "\u21c4", 7246 xrightleftarrows: "\u21c4", 7247 xrightequilibrium: "\u21cc", 7248 // Not a perfect match. 7249 xleftequilibrium: "\u21cb" // None better available. 7250 7251}; 7252 7253const mathMLnode = function mathMLnode(label) { 7254 const node = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(stretchyCodePoint[label.substr(1)])]); 7255 node.setAttribute("stretchy", "true"); 7256 return node; 7257}; // Many of the KaTeX SVG images have been adapted from glyphs in KaTeX fonts. 7258// Copyright (c) 2009-2010, Design Science, Inc. (<www.mathjax.org>) 7259// Copyright (c) 2014-2017 Khan Academy (<www.khanacademy.org>) 7260// Licensed under the SIL Open Font License, Version 1.1. 7261// See \nhttp://scripts.sil.org/OFL 7262// Very Long SVGs 7263// Many of the KaTeX stretchy wide elements use a long SVG image and an 7264// overflow: hidden tactic to achieve a stretchy image while avoiding 7265// distortion of arrowheads or brace corners. 7266// The SVG typically contains a very long (400 em) arrow. 7267// The SVG is in a container span that has overflow: hidden, so the span 7268// acts like a window that exposes only part of the SVG. 7269// The SVG always has a longer, thinner aspect ratio than the container span. 7270// After the SVG fills 100% of the height of the container span, 7271// there is a long arrow shaft left over. That left-over shaft is not shown. 7272// Instead, it is sliced off because the span's CSS has overflow: hidden. 7273// Thus, the reader sees an arrow that matches the subject matter width 7274// without distortion. 7275// Some functions, such as \cancel, need to vary their aspect ratio. These 7276// functions do not get the overflow SVG treatment. 7277// Second Brush Stroke 7278// Low resolution monitors struggle to display images in fine detail. 7279// So browsers apply anti-aliasing. A long straight arrow shaft therefore 7280// will sometimes appear as if it has a blurred edge. 7281// To mitigate this, these SVG files contain a second "brush-stroke" on the 7282// arrow shafts. That is, a second long thin rectangular SVG path has been 7283// written directly on top of each arrow shaft. This reinforcement causes 7284// some of the screen pixels to display as black instead of the anti-aliased 7285// gray pixel that a single path would generate. So we get arrow shafts 7286// whose edges appear to be sharper. 7287// In the katexImagesData object just below, the dimensions all 7288// correspond to path geometry inside the relevant SVG. 7289// For example, \overrightarrow uses the same arrowhead as glyph U+2192 7290// from the KaTeX Main font. The scaling factor is 1000. 7291// That is, inside the font, that arrowhead is 522 units tall, which 7292// corresponds to 0.522 em inside the document. 7293 7294 7295const katexImagesData = { 7296 // path(s), minWidth, height, align 7297 overrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"], 7298 overleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"], 7299 underrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"], 7300 underleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"], 7301 xrightarrow: [["rightarrow"], 1.469, 522, "xMaxYMin"], 7302 xleftarrow: [["leftarrow"], 1.469, 522, "xMinYMin"], 7303 Overrightarrow: [["doublerightarrow"], 0.888, 560, "xMaxYMin"], 7304 xRightarrow: [["doublerightarrow"], 1.526, 560, "xMaxYMin"], 7305 xLeftarrow: [["doubleleftarrow"], 1.526, 560, "xMinYMin"], 7306 overleftharpoon: [["leftharpoon"], 0.888, 522, "xMinYMin"], 7307 xleftharpoonup: [["leftharpoon"], 0.888, 522, "xMinYMin"], 7308 xleftharpoondown: [["leftharpoondown"], 0.888, 522, "xMinYMin"], 7309 overrightharpoon: [["rightharpoon"], 0.888, 522, "xMaxYMin"], 7310 xrightharpoonup: [["rightharpoon"], 0.888, 522, "xMaxYMin"], 7311 xrightharpoondown: [["rightharpoondown"], 0.888, 522, "xMaxYMin"], 7312 xlongequal: [["longequal"], 0.888, 334, "xMinYMin"], 7313 xtwoheadleftarrow: [["twoheadleftarrow"], 0.888, 334, "xMinYMin"], 7314 xtwoheadrightarrow: [["twoheadrightarrow"], 0.888, 334, "xMaxYMin"], 7315 overleftrightarrow: [["leftarrow", "rightarrow"], 0.888, 522], 7316 overbrace: [["leftbrace", "midbrace", "rightbrace"], 1.6, 548], 7317 underbrace: [["leftbraceunder", "midbraceunder", "rightbraceunder"], 1.6, 548], 7318 underleftrightarrow: [["leftarrow", "rightarrow"], 0.888, 522], 7319 xleftrightarrow: [["leftarrow", "rightarrow"], 1.75, 522], 7320 xLeftrightarrow: [["doubleleftarrow", "doublerightarrow"], 1.75, 560], 7321 xrightleftharpoons: [["leftharpoondownplus", "rightharpoonplus"], 1.75, 716], 7322 xleftrightharpoons: [["leftharpoonplus", "rightharpoondownplus"], 1.75, 716], 7323 xhookleftarrow: [["leftarrow", "righthook"], 1.08, 522], 7324 xhookrightarrow: [["lefthook", "rightarrow"], 1.08, 522], 7325 overlinesegment: [["leftlinesegment", "rightlinesegment"], 0.888, 522], 7326 underlinesegment: [["leftlinesegment", "rightlinesegment"], 0.888, 522], 7327 overgroup: [["leftgroup", "rightgroup"], 0.888, 342], 7328 undergroup: [["leftgroupunder", "rightgroupunder"], 0.888, 342], 7329 xmapsto: [["leftmapsto", "rightarrow"], 1.5, 522], 7330 xtofrom: [["leftToFrom", "rightToFrom"], 1.75, 528], 7331 // The next three arrows are from the mhchem package. 7332 // In mhchem.sty, min-length is 2.0em. But these arrows might appear in the 7333 // document as \xrightarrow or \xrightleftharpoons. Those have 7334 // min-length = 1.75em, so we set min-length on these next three to match. 7335 xrightleftarrows: [["baraboveleftarrow", "rightarrowabovebar"], 1.75, 901], 7336 xrightequilibrium: [["baraboveshortleftharpoon", "rightharpoonaboveshortbar"], 1.75, 716], 7337 xleftequilibrium: [["shortbaraboveleftharpoon", "shortrightharpoonabovebar"], 1.75, 716] 7338}; 7339 7340const groupLength = function groupLength(arg) { 7341 if (arg.type === "ordgroup") { 7342 return arg.body.length; 7343 } else { 7344 return 1; 7345 } 7346}; 7347 7348const svgSpan = function svgSpan(group, options) { 7349 // Create a span with inline SVG for the element. 7350 function buildSvgSpan_() { 7351 let viewBoxWidth = 400000; // default 7352 7353 const label = group.label.substr(1); 7354 7355 if (utils.contains(["widehat", "widecheck", "widetilde", "utilde"], label)) { 7356 // Each type in the `if` statement corresponds to one of the ParseNode 7357 // types below. This narrowing is required to access `grp.base`. 7358 const grp = group; // There are four SVG images available for each function. 7359 // Choose a taller image when there are more characters. 7360 7361 const numChars = groupLength(grp.base); 7362 let viewBoxHeight; 7363 let pathName; 7364 let height; 7365 7366 if (numChars > 5) { 7367 if (label === "widehat" || label === "widecheck") { 7368 viewBoxHeight = 420; 7369 viewBoxWidth = 2364; 7370 height = 0.42; 7371 pathName = label + "4"; 7372 } else { 7373 viewBoxHeight = 312; 7374 viewBoxWidth = 2340; 7375 height = 0.34; 7376 pathName = "tilde4"; 7377 } 7378 } else { 7379 const imgIndex = [1, 1, 2, 2, 3, 3][numChars]; 7380 7381 if (label === "widehat" || label === "widecheck") { 7382 viewBoxWidth = [0, 1062, 2364, 2364, 2364][imgIndex]; 7383 viewBoxHeight = [0, 239, 300, 360, 420][imgIndex]; 7384 height = [0, 0.24, 0.3, 0.3, 0.36, 0.42][imgIndex]; 7385 pathName = label + imgIndex; 7386 } else { 7387 viewBoxWidth = [0, 600, 1033, 2339, 2340][imgIndex]; 7388 viewBoxHeight = [0, 260, 286, 306, 312][imgIndex]; 7389 height = [0, 0.26, 0.286, 0.3, 0.306, 0.34][imgIndex]; 7390 pathName = "tilde" + imgIndex; 7391 } 7392 } 7393 7394 const path = new PathNode(pathName); 7395 const svgNode = new SvgNode([path], { 7396 "width": "100%", 7397 "height": height + "em", 7398 "viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`, 7399 "preserveAspectRatio": "none" 7400 }); 7401 return { 7402 span: buildCommon.makeSvgSpan([], [svgNode], options), 7403 minWidth: 0, 7404 height 7405 }; 7406 } else { 7407 const spans = []; 7408 const data = katexImagesData[label]; 7409 const paths = data[0], 7410 minWidth = data[1], 7411 viewBoxHeight = data[2]; 7412 const height = viewBoxHeight / 1000; 7413 const numSvgChildren = paths.length; 7414 let widthClasses; 7415 let aligns; 7416 7417 if (numSvgChildren === 1) { 7418 // $FlowFixMe: All these cases must be of the 4-tuple type. 7419 const align1 = data[3]; 7420 widthClasses = ["hide-tail"]; 7421 aligns = [align1]; 7422 } else if (numSvgChildren === 2) { 7423 widthClasses = ["halfarrow-left", "halfarrow-right"]; 7424 aligns = ["xMinYMin", "xMaxYMin"]; 7425 } else if (numSvgChildren === 3) { 7426 widthClasses = ["brace-left", "brace-center", "brace-right"]; 7427 aligns = ["xMinYMin", "xMidYMin", "xMaxYMin"]; 7428 } else { 7429 throw new Error(`Correct katexImagesData or update code here to support 7430 ${numSvgChildren} children.`); 7431 } 7432 7433 for (let i = 0; i < numSvgChildren; i++) { 7434 const path = new PathNode(paths[i]); 7435 const svgNode = new SvgNode([path], { 7436 "width": "400em", 7437 "height": height + "em", 7438 "viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`, 7439 "preserveAspectRatio": aligns[i] + " slice" 7440 }); 7441 const span = buildCommon.makeSvgSpan([widthClasses[i]], [svgNode], options); 7442 7443 if (numSvgChildren === 1) { 7444 return { 7445 span, 7446 minWidth, 7447 height 7448 }; 7449 } else { 7450 span.style.height = height + "em"; 7451 spans.push(span); 7452 } 7453 } 7454 7455 return { 7456 span: buildCommon.makeSpan(["stretchy"], spans, options), 7457 minWidth, 7458 height 7459 }; 7460 } 7461 } // buildSvgSpan_() 7462 7463 7464 const _buildSvgSpan_ = buildSvgSpan_(), 7465 span = _buildSvgSpan_.span, 7466 minWidth = _buildSvgSpan_.minWidth, 7467 height = _buildSvgSpan_.height; // Note that we are returning span.depth = 0. 7468 // Any adjustments relative to the baseline must be done in buildHTML. 7469 7470 7471 span.height = height; 7472 span.style.height = height + "em"; 7473 7474 if (minWidth > 0) { 7475 span.style.minWidth = minWidth + "em"; 7476 } 7477 7478 return span; 7479}; 7480 7481const encloseSpan = function encloseSpan(inner, label, pad, options) { 7482 // Return an image span for \cancel, \bcancel, \xcancel, or \fbox 7483 let img; 7484 const totalHeight = inner.height + inner.depth + 2 * pad; 7485 7486 if (/fbox|color/.test(label)) { 7487 img = buildCommon.makeSpan(["stretchy", label], [], options); 7488 7489 if (label === "fbox") { 7490 const color = options.color && options.getColor(); 7491 7492 if (color) { 7493 img.style.borderColor = color; 7494 } 7495 } 7496 } else { 7497 // \cancel, \bcancel, or \xcancel 7498 // Since \cancel's SVG is inline and it omits the viewBox attribute, 7499 // its stroke-width will not vary with span area. 7500 const lines = []; 7501 7502 if (/^[bx]cancel$/.test(label)) { 7503 lines.push(new LineNode({ 7504 "x1": "0", 7505 "y1": "0", 7506 "x2": "100%", 7507 "y2": "100%", 7508 "stroke-width": "0.046em" 7509 })); 7510 } 7511 7512 if (/^x?cancel$/.test(label)) { 7513 lines.push(new LineNode({ 7514 "x1": "0", 7515 "y1": "100%", 7516 "x2": "100%", 7517 "y2": "0", 7518 "stroke-width": "0.046em" 7519 })); 7520 } 7521 7522 const svgNode = new SvgNode(lines, { 7523 "width": "100%", 7524 "height": totalHeight + "em" 7525 }); 7526 img = buildCommon.makeSvgSpan([], [svgNode], options); 7527 } 7528 7529 img.height = totalHeight; 7530 img.style.height = totalHeight + "em"; 7531 return img; 7532}; 7533 7534var stretchy = { 7535 encloseSpan, 7536 mathMLnode, 7537 svgSpan 7538}; 7539 7540// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but 7541const htmlBuilder = (grp, options) => { 7542 // Accents are handled in the TeXbook pg. 443, rule 12. 7543 let base; 7544 let group; 7545 const supSub = checkNodeType(grp, "supsub"); 7546 let supSubGroup; 7547 7548 if (supSub) { 7549 // If our base is a character box, and we have superscripts and 7550 // subscripts, the supsub will defer to us. In particular, we want 7551 // to attach the superscripts and subscripts to the inner body (so 7552 // that the position of the superscripts and subscripts won't be 7553 // affected by the height of the accent). We accomplish this by 7554 // sticking the base of the accent into the base of the supsub, and 7555 // rendering that, while keeping track of where the accent is. 7556 // The real accent group is the base of the supsub group 7557 group = assertNodeType(supSub.base, "accent"); // The character box is the base of the accent group 7558 7559 base = group.base; // Stick the character box into the base of the supsub group 7560 7561 supSub.base = base; // Rerender the supsub group with its new base, and store that 7562 // result. 7563 7564 supSubGroup = assertSpan(buildGroup(supSub, options)); // reset original base 7565 7566 supSub.base = group; 7567 } else { 7568 group = assertNodeType(grp, "accent"); 7569 base = group.base; 7570 } // Build the base group 7571 7572 7573 const body = buildGroup(base, options.havingCrampedStyle()); // Does the accent need to shift for the skew of a character? 7574 7575 const mustShift = group.isShifty && utils.isCharacterBox(base); // Calculate the skew of the accent. This is based on the line "If the 7576 // nucleus is not a single character, let s = 0; otherwise set s to the 7577 // kern amount for the nucleus followed by the \skewchar of its font." 7578 // Note that our skew metrics are just the kern between each character 7579 // and the skewchar. 7580 7581 let skew = 0; 7582 7583 if (mustShift) { 7584 // If the base is a character box, then we want the skew of the 7585 // innermost character. To do that, we find the innermost character: 7586 const baseChar = utils.getBaseElem(base); // Then, we render its group to get the symbol inside it 7587 7588 const baseGroup = buildGroup(baseChar, options.havingCrampedStyle()); // Finally, we pull the skew off of the symbol. 7589 7590 skew = assertSymbolDomNode(baseGroup).skew; // Note that we now throw away baseGroup, because the layers we 7591 // removed with getBaseElem might contain things like \color which 7592 // we can't get rid of. 7593 // TODO(emily): Find a better way to get the skew 7594 } // calculate the amount of space between the body and the accent 7595 7596 7597 let clearance = Math.min(body.height, options.fontMetrics().xHeight); // Build the accent 7598 7599 let accentBody; 7600 7601 if (!group.isStretchy) { 7602 let accent; 7603 let width; 7604 7605 if (group.label === "\\vec") { 7606 // Before version 0.9, \vec used the combining font glyph U+20D7. 7607 // But browsers, especially Safari, are not consistent in how they 7608 // render combining characters when not preceded by a character. 7609 // So now we use an SVG. 7610 // If Safari reforms, we should consider reverting to the glyph. 7611 accent = buildCommon.staticSvg("vec", options); 7612 width = buildCommon.svgData.vec[1]; 7613 } else { 7614 accent = buildCommon.makeOrd({ 7615 mode: group.mode, 7616 text: group.label 7617 }, options, "textord"); 7618 accent = assertSymbolDomNode(accent); // Remove the italic correction of the accent, because it only serves to 7619 // shift the accent over to a place we don't want. 7620 7621 accent.italic = 0; 7622 width = accent.width; 7623 } 7624 7625 accentBody = buildCommon.makeSpan(["accent-body"], [accent]); // "Full" accents expand the width of the resulting symbol to be 7626 // at least the width of the accent, and overlap directly onto the 7627 // character without any vertical offset. 7628 7629 const accentFull = group.label === "\\textcircled"; 7630 7631 if (accentFull) { 7632 accentBody.classes.push('accent-full'); 7633 clearance = body.height; 7634 } // Shift the accent over by the skew. 7635 7636 7637 let left = skew; // CSS defines `.katex .accent .accent-body:not(.accent-full) { width: 0 }` 7638 // so that the accent doesn't contribute to the bounding box. 7639 // We need to shift the character by its width (effectively half 7640 // its width) to compensate. 7641 7642 if (!accentFull) { 7643 left -= width / 2; 7644 } 7645 7646 accentBody.style.left = left + "em"; // \textcircled uses the \bigcirc glyph, so it needs some 7647 // vertical adjustment to match LaTeX. 7648 7649 if (group.label === "\\textcircled") { 7650 accentBody.style.top = ".2em"; 7651 } 7652 7653 accentBody = buildCommon.makeVList({ 7654 positionType: "firstBaseline", 7655 children: [{ 7656 type: "elem", 7657 elem: body 7658 }, { 7659 type: "kern", 7660 size: -clearance 7661 }, { 7662 type: "elem", 7663 elem: accentBody 7664 }] 7665 }, options); 7666 } else { 7667 accentBody = stretchy.svgSpan(group, options); 7668 accentBody = buildCommon.makeVList({ 7669 positionType: "firstBaseline", 7670 children: [{ 7671 type: "elem", 7672 elem: body 7673 }, { 7674 type: "elem", 7675 elem: accentBody, 7676 wrapperClasses: ["svg-align"], 7677 wrapperStyle: skew > 0 ? { 7678 width: `calc(100% - ${2 * skew}em)`, 7679 marginLeft: `${2 * skew}em` 7680 } : undefined 7681 }] 7682 }, options); 7683 } 7684 7685 const accentWrap = buildCommon.makeSpan(["mord", "accent"], [accentBody], options); 7686 7687 if (supSubGroup) { 7688 // Here, we replace the "base" child of the supsub with our newly 7689 // generated accent. 7690 supSubGroup.children[0] = accentWrap; // Since we don't rerun the height calculation after replacing the 7691 // accent, we manually recalculate height. 7692 7693 supSubGroup.height = Math.max(accentWrap.height, supSubGroup.height); // Accents should always be ords, even when their innards are not. 7694 7695 supSubGroup.classes[0] = "mord"; 7696 return supSubGroup; 7697 } else { 7698 return accentWrap; 7699 } 7700}; 7701 7702const mathmlBuilder = (group, options) => { 7703 const accentNode = group.isStretchy ? stretchy.mathMLnode(group.label) : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); 7704 const node = new mathMLTree.MathNode("mover", [buildGroup$1(group.base, options), accentNode]); 7705 node.setAttribute("accent", "true"); 7706 return node; 7707}; 7708 7709const NON_STRETCHY_ACCENT_REGEX = new RegExp(["\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\check", "\\hat", "\\vec", "\\dot", "\\mathring"].map(accent => `\\${accent}`).join("|")); // Accents 7710 7711defineFunction({ 7712 type: "accent", 7713 names: ["\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\check", "\\hat", "\\vec", "\\dot", "\\mathring", "\\widecheck", "\\widehat", "\\widetilde", "\\overrightarrow", "\\overleftarrow", "\\Overrightarrow", "\\overleftrightarrow", "\\overgroup", "\\overlinesegment", "\\overleftharpoon", "\\overrightharpoon"], 7714 props: { 7715 numArgs: 1 7716 }, 7717 handler: (context, args) => { 7718 const base = args[0]; 7719 const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); 7720 const isShifty = !isStretchy || context.funcName === "\\widehat" || context.funcName === "\\widetilde" || context.funcName === "\\widecheck"; 7721 return { 7722 type: "accent", 7723 mode: context.parser.mode, 7724 label: context.funcName, 7725 isStretchy: isStretchy, 7726 isShifty: isShifty, 7727 base: base 7728 }; 7729 }, 7730 htmlBuilder, 7731 mathmlBuilder 7732}); // Text-mode accents 7733 7734defineFunction({ 7735 type: "accent", 7736 names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v", "\\textcircled"], 7737 props: { 7738 numArgs: 1, 7739 allowedInText: true, 7740 allowedInMath: false 7741 }, 7742 handler: (context, args) => { 7743 const base = args[0]; 7744 return { 7745 type: "accent", 7746 mode: context.parser.mode, 7747 label: context.funcName, 7748 isStretchy: false, 7749 isShifty: true, 7750 base: base 7751 }; 7752 }, 7753 htmlBuilder, 7754 mathmlBuilder 7755}); 7756 7757// Horizontal overlap functions 7758defineFunction({ 7759 type: "accentUnder", 7760 names: ["\\underleftarrow", "\\underrightarrow", "\\underleftrightarrow", "\\undergroup", "\\underlinesegment", "\\utilde"], 7761 props: { 7762 numArgs: 1 7763 }, 7764 handler: (_ref, args) => { 7765 let parser = _ref.parser, 7766 funcName = _ref.funcName; 7767 const base = args[0]; 7768 return { 7769 type: "accentUnder", 7770 mode: parser.mode, 7771 label: funcName, 7772 base: base 7773 }; 7774 }, 7775 htmlBuilder: (group, options) => { 7776 // Treat under accents much like underlines. 7777 const innerGroup = buildGroup(group.base, options); 7778 const accentBody = stretchy.svgSpan(group, options); 7779 const kern = group.label === "\\utilde" ? 0.12 : 0; // Generate the vlist, with the appropriate kerns 7780 7781 const vlist = buildCommon.makeVList({ 7782 positionType: "bottom", 7783 positionData: accentBody.height + kern, 7784 children: [{ 7785 type: "elem", 7786 elem: accentBody, 7787 wrapperClasses: ["svg-align"] 7788 }, { 7789 type: "kern", 7790 size: kern 7791 }, { 7792 type: "elem", 7793 elem: innerGroup 7794 }] 7795 }, options); 7796 return buildCommon.makeSpan(["mord", "accentunder"], [vlist], options); 7797 }, 7798 mathmlBuilder: (group, options) => { 7799 const accentNode = stretchy.mathMLnode(group.label); 7800 const node = new mathMLTree.MathNode("munder", [buildGroup$1(group.base, options), accentNode]); 7801 node.setAttribute("accentunder", "true"); 7802 return node; 7803 } 7804}); 7805 7806// Helper function 7807const paddedNode = group => { 7808 const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); 7809 node.setAttribute("width", "+0.6em"); 7810 node.setAttribute("lspace", "0.3em"); 7811 return node; 7812}; // Stretchy arrows with an optional argument 7813 7814 7815defineFunction({ 7816 type: "xArrow", 7817 names: ["\\xleftarrow", "\\xrightarrow", "\\xLeftarrow", "\\xRightarrow", "\\xleftrightarrow", "\\xLeftrightarrow", "\\xhookleftarrow", "\\xhookrightarrow", "\\xmapsto", "\\xrightharpoondown", "\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup", "\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal", "\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xtofrom", // The next 3 functions are here to support the mhchem extension. 7818 // Direct use of these functions is discouraged and may break someday. 7819 "\\xrightleftarrows", "\\xrightequilibrium", "\\xleftequilibrium"], 7820 props: { 7821 numArgs: 1, 7822 numOptionalArgs: 1 7823 }, 7824 7825 handler(_ref, args, optArgs) { 7826 let parser = _ref.parser, 7827 funcName = _ref.funcName; 7828 return { 7829 type: "xArrow", 7830 mode: parser.mode, 7831 label: funcName, 7832 body: args[0], 7833 below: optArgs[0] 7834 }; 7835 }, 7836 7837 // Flow is unable to correctly infer the type of `group`, even though it's 7838 // unamibiguously determined from the passed-in `type` above. 7839 htmlBuilder(group, options) { 7840 const style = options.style; // Build the argument groups in the appropriate style. 7841 // Ref: amsmath.dtx: \hbox{$\scriptstyle\mkern#3mu{#6}\mkern#4mu$}% 7842 // Some groups can return document fragments. Handle those by wrapping 7843 // them in a span. 7844 7845 let newOptions = options.havingStyle(style.sup()); 7846 const upperGroup = buildCommon.wrapFragment(buildGroup(group.body, newOptions, options), options); 7847 upperGroup.classes.push("x-arrow-pad"); 7848 let lowerGroup; 7849 7850 if (group.below) { 7851 // Build the lower group 7852 newOptions = options.havingStyle(style.sub()); 7853 lowerGroup = buildCommon.wrapFragment(buildGroup(group.below, newOptions, options), options); 7854 lowerGroup.classes.push("x-arrow-pad"); 7855 } 7856 7857 const arrowBody = stretchy.svgSpan(group, options); // Re shift: Note that stretchy.svgSpan returned arrowBody.depth = 0. 7858 // The point we want on the math axis is at 0.5 * arrowBody.height. 7859 7860 const arrowShift = -options.fontMetrics().axisHeight + 0.5 * arrowBody.height; // 2 mu kern. Ref: amsmath.dtx: #7\if0#2\else\mkern#2mu\fi 7861 7862 let upperShift = -options.fontMetrics().axisHeight - 0.5 * arrowBody.height - 0.111; // 0.111 em = 2 mu 7863 7864 if (upperGroup.depth > 0.25 || group.label === "\\xleftequilibrium") { 7865 upperShift -= upperGroup.depth; // shift up if depth encroaches 7866 } // Generate the vlist 7867 7868 7869 let vlist; 7870 7871 if (lowerGroup) { 7872 const lowerShift = -options.fontMetrics().axisHeight + lowerGroup.height + 0.5 * arrowBody.height + 0.111; 7873 vlist = buildCommon.makeVList({ 7874 positionType: "individualShift", 7875 children: [{ 7876 type: "elem", 7877 elem: upperGroup, 7878 shift: upperShift 7879 }, { 7880 type: "elem", 7881 elem: arrowBody, 7882 shift: arrowShift 7883 }, { 7884 type: "elem", 7885 elem: lowerGroup, 7886 shift: lowerShift 7887 }] 7888 }, options); 7889 } else { 7890 vlist = buildCommon.makeVList({ 7891 positionType: "individualShift", 7892 children: [{ 7893 type: "elem", 7894 elem: upperGroup, 7895 shift: upperShift 7896 }, { 7897 type: "elem", 7898 elem: arrowBody, 7899 shift: arrowShift 7900 }] 7901 }, options); 7902 } // $FlowFixMe: Replace this with passing "svg-align" into makeVList. 7903 7904 7905 vlist.children[0].children[0].children[1].classes.push("svg-align"); 7906 return buildCommon.makeSpan(["mrel", "x-arrow"], [vlist], options); 7907 }, 7908 7909 mathmlBuilder(group, options) { 7910 const arrowNode = stretchy.mathMLnode(group.label); 7911 let node; 7912 7913 if (group.body) { 7914 const upperNode = paddedNode(buildGroup$1(group.body, options)); 7915 7916 if (group.below) { 7917 const lowerNode = paddedNode(buildGroup$1(group.below, options)); 7918 node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); 7919 } else { 7920 node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); 7921 } 7922 } else if (group.below) { 7923 const lowerNode = paddedNode(buildGroup$1(group.below, options)); 7924 node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]); 7925 } else { 7926 // This should never happen. 7927 // Parser.js throws an error if there is no argument. 7928 node = paddedNode(); 7929 node = new mathMLTree.MathNode("mover", [arrowNode, node]); 7930 } 7931 7932 return node; 7933 } 7934 7935}); 7936 7937// {123} and converts into symbol with code 123. It is used by the *macro* 7938// \char defined in macros.js. 7939 7940defineFunction({ 7941 type: "textord", 7942 names: ["\\@char"], 7943 props: { 7944 numArgs: 1, 7945 allowedInText: true 7946 }, 7947 7948 handler(_ref, args) { 7949 let parser = _ref.parser; 7950 const arg = assertNodeType(args[0], "ordgroup"); 7951 const group = arg.body; 7952 let number = ""; 7953 7954 for (let i = 0; i < group.length; i++) { 7955 const node = assertNodeType(group[i], "textord"); 7956 number += node.text; 7957 } 7958 7959 const code = parseInt(number); 7960 7961 if (isNaN(code)) { 7962 throw new ParseError(`\\@char has non-numeric argument ${number}`); 7963 } 7964 7965 return { 7966 type: "textord", 7967 mode: parser.mode, 7968 text: String.fromCharCode(code) 7969 }; 7970 } 7971 7972}); 7973 7974const htmlBuilder$1 = (group, options) => { 7975 const elements = buildExpression(group.body, options.withColor(group.color), false); // \color isn't supposed to affect the type of the elements it contains. 7976 // To accomplish this, we wrap the results in a fragment, so the inner 7977 // elements will be able to directly interact with their neighbors. For 7978 // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3` 7979 7980 return buildCommon.makeFragment(elements); 7981}; 7982 7983const mathmlBuilder$1 = (group, options) => { 7984 const inner = buildExpression$1(group.body, options.withColor(group.color)); 7985 const node = new mathMLTree.MathNode("mstyle", inner); 7986 node.setAttribute("mathcolor", group.color); 7987 return node; 7988}; 7989 7990defineFunction({ 7991 type: "color", 7992 names: ["\\textcolor"], 7993 props: { 7994 numArgs: 2, 7995 allowedInText: true, 7996 greediness: 3, 7997 argTypes: ["color", "original"] 7998 }, 7999 8000 handler(_ref, args) { 8001 let parser = _ref.parser; 8002 const color = assertNodeType(args[0], "color-token").color; 8003 const body = args[1]; 8004 return { 8005 type: "color", 8006 mode: parser.mode, 8007 color, 8008 body: ordargument(body) 8009 }; 8010 }, 8011 8012 htmlBuilder: htmlBuilder$1, 8013 mathmlBuilder: mathmlBuilder$1 8014}); 8015defineFunction({ 8016 type: "color", 8017 names: ["\\color"], 8018 props: { 8019 numArgs: 1, 8020 allowedInText: true, 8021 greediness: 3, 8022 argTypes: ["color"] 8023 }, 8024 8025 handler(_ref2, args) { 8026 let parser = _ref2.parser, 8027 breakOnTokenText = _ref2.breakOnTokenText; 8028 const color = assertNodeType(args[0], "color-token").color; // Set macro \current@color in current namespace to store the current 8029 // color, mimicking the behavior of color.sty. 8030 // This is currently used just to correctly color a \right 8031 // that follows a \color command. 8032 8033 parser.gullet.macros.set("\\current@color", color); // Parse out the implicit body that should be colored. 8034 8035 const body = parser.parseExpression(true, breakOnTokenText); 8036 return { 8037 type: "color", 8038 mode: parser.mode, 8039 color, 8040 body 8041 }; 8042 }, 8043 8044 htmlBuilder: htmlBuilder$1, 8045 mathmlBuilder: mathmlBuilder$1 8046}); 8047 8048// Row breaks within tabular environments, and line breaks at top level 8049// same signature, we implement them as one megafunction, with newRow 8050// indicating whether we're in the \cr case, and newLine indicating whether 8051// to break the line in the \newline case. 8052 8053defineFunction({ 8054 type: "cr", 8055 names: ["\\cr", "\\newline"], 8056 props: { 8057 numArgs: 0, 8058 numOptionalArgs: 1, 8059 argTypes: ["size"], 8060 allowedInText: true 8061 }, 8062 8063 handler(_ref, args, optArgs) { 8064 let parser = _ref.parser, 8065 funcName = _ref.funcName; 8066 const size = optArgs[0]; 8067 const newRow = funcName === "\\cr"; 8068 let newLine = false; 8069 8070 if (!newRow) { 8071 if (parser.settings.displayMode && parser.settings.useStrictBehavior("newLineInDisplayMode", "In LaTeX, \\\\ or \\newline " + "does nothing in display mode")) { 8072 newLine = false; 8073 } else { 8074 newLine = true; 8075 } 8076 } 8077 8078 return { 8079 type: "cr", 8080 mode: parser.mode, 8081 newLine, 8082 newRow, 8083 size: size && assertNodeType(size, "size").value 8084 }; 8085 }, 8086 8087 // The following builders are called only at the top level, 8088 // not within tabular/array environments. 8089 htmlBuilder(group, options) { 8090 if (group.newRow) { 8091 throw new ParseError("\\cr valid only within a tabular/array environment"); 8092 } 8093 8094 const span = buildCommon.makeSpan(["mspace"], [], options); 8095 8096 if (group.newLine) { 8097 span.classes.push("newline"); 8098 8099 if (group.size) { 8100 span.style.marginTop = calculateSize(group.size, options) + "em"; 8101 } 8102 } 8103 8104 return span; 8105 }, 8106 8107 mathmlBuilder(group, options) { 8108 const node = new mathMLTree.MathNode("mspace"); 8109 8110 if (group.newLine) { 8111 node.setAttribute("linebreak", "newline"); 8112 8113 if (group.size) { 8114 node.setAttribute("height", calculateSize(group.size, options) + "em"); 8115 } 8116 } 8117 8118 return node; 8119 } 8120 8121}); 8122 8123/** 8124 * This file deals with creating delimiters of various sizes. The TeXbook 8125 * discusses these routines on page 441-442, in the "Another subroutine sets box 8126 * x to a specified variable delimiter" paragraph. 8127 * 8128 * There are three main routines here. `makeSmallDelim` makes a delimiter in the 8129 * normal font, but in either text, script, or scriptscript style. 8130 * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1, 8131 * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of 8132 * smaller pieces that are stacked on top of one another. 8133 * 8134 * The functions take a parameter `center`, which determines if the delimiter 8135 * should be centered around the axis. 8136 * 8137 * Then, there are three exposed functions. `sizedDelim` makes a delimiter in 8138 * one of the given sizes. This is used for things like `\bigl`. 8139 * `customSizedDelim` makes a delimiter with a given total height+depth. It is 8140 * called in places like `\sqrt`. `leftRightDelim` makes an appropriate 8141 * delimiter which surrounds an expression of a given height an depth. It is 8142 * used in `\left` and `\right`. 8143 */ 8144 8145/** 8146 * Get the metrics for a given symbol and font, after transformation (i.e. 8147 * after following replacement from symbols.js) 8148 */ 8149const getMetrics = function getMetrics(symbol, font, mode) { 8150 const replace = symbols.math[symbol] && symbols.math[symbol].replace; 8151 const metrics = getCharacterMetrics(replace || symbol, font, mode); 8152 8153 if (!metrics) { 8154 throw new Error(`Unsupported symbol ${symbol} and font size ${font}.`); 8155 } 8156 8157 return metrics; 8158}; 8159/** 8160 * Puts a delimiter span in a given style, and adds appropriate height, depth, 8161 * and maxFontSizes. 8162 */ 8163 8164 8165const styleWrap = function styleWrap(delim, toStyle, options, classes) { 8166 const newOptions = options.havingBaseStyle(toStyle); 8167 const span = buildCommon.makeSpan(classes.concat(newOptions.sizingClasses(options)), [delim], options); 8168 const delimSizeMultiplier = newOptions.sizeMultiplier / options.sizeMultiplier; 8169 span.height *= delimSizeMultiplier; 8170 span.depth *= delimSizeMultiplier; 8171 span.maxFontSize = newOptions.sizeMultiplier; 8172 return span; 8173}; 8174 8175const centerSpan = function centerSpan(span, options, style) { 8176 const newOptions = options.havingBaseStyle(style); 8177 const shift = (1 - options.sizeMultiplier / newOptions.sizeMultiplier) * options.fontMetrics().axisHeight; 8178 span.classes.push("delimcenter"); 8179 span.style.top = shift + "em"; 8180 span.height -= shift; 8181 span.depth += shift; 8182}; 8183/** 8184 * Makes a small delimiter. This is a delimiter that comes in the Main-Regular 8185 * font, but is restyled to either be in textstyle, scriptstyle, or 8186 * scriptscriptstyle. 8187 */ 8188 8189 8190const makeSmallDelim = function makeSmallDelim(delim, style, center, options, mode, classes) { 8191 const text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options); 8192 const span = styleWrap(text, style, options, classes); 8193 8194 if (center) { 8195 centerSpan(span, options, style); 8196 } 8197 8198 return span; 8199}; 8200/** 8201 * Builds a symbol in the given font size (note size is an integer) 8202 */ 8203 8204 8205const mathrmSize = function mathrmSize(value, size, mode, options) { 8206 return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode, options); 8207}; 8208/** 8209 * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2, 8210 * Size3, or Size4 fonts. It is always rendered in textstyle. 8211 */ 8212 8213 8214const makeLargeDelim = function makeLargeDelim(delim, size, center, options, mode, classes) { 8215 const inner = mathrmSize(delim, size, mode, options); 8216 const span = styleWrap(buildCommon.makeSpan(["delimsizing", "size" + size], [inner], options), Style$1.TEXT, options, classes); 8217 8218 if (center) { 8219 centerSpan(span, options, Style$1.TEXT); 8220 } 8221 8222 return span; 8223}; 8224/** 8225 * Make an inner span with the given offset and in the given font. This is used 8226 * in `makeStackedDelim` to make the stacking pieces for the delimiter. 8227 */ 8228 8229 8230const makeInner = function makeInner(symbol, font, mode) { 8231 let sizeClass; // Apply the correct CSS class to choose the right font. 8232 8233 if (font === "Size1-Regular") { 8234 sizeClass = "delim-size1"; 8235 } else 8236 /* if (font === "Size4-Regular") */ 8237 { 8238 sizeClass = "delim-size4"; 8239 } 8240 8241 const inner = buildCommon.makeSpan(["delimsizinginner", sizeClass], [buildCommon.makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]); // Since this will be passed into `makeVList` in the end, wrap the element 8242 // in the appropriate tag that VList uses. 8243 8244 return { 8245 type: "elem", 8246 elem: inner 8247 }; 8248}; // Helper for makeStackedDelim 8249 8250 8251const lap = { 8252 type: "kern", 8253 size: -0.005 8254}; 8255/** 8256 * Make a stacked delimiter out of a given delimiter, with the total height at 8257 * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook. 8258 */ 8259 8260const makeStackedDelim = function makeStackedDelim(delim, heightTotal, center, options, mode, classes) { 8261 // There are four parts, the top, an optional middle, a repeated part, and a 8262 // bottom. 8263 let top; 8264 let middle; 8265 let repeat; 8266 let bottom; 8267 top = repeat = bottom = delim; 8268 middle = null; // Also keep track of what font the delimiters are in 8269 8270 let font = "Size1-Regular"; // We set the parts and font based on the symbol. Note that we use 8271 // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the 8272 // repeats of the arrows 8273 8274 if (delim === "\\uparrow") { 8275 repeat = bottom = "\u23d0"; 8276 } else if (delim === "\\Uparrow") { 8277 repeat = bottom = "\u2016"; 8278 } else if (delim === "\\downarrow") { 8279 top = repeat = "\u23d0"; 8280 } else if (delim === "\\Downarrow") { 8281 top = repeat = "\u2016"; 8282 } else if (delim === "\\updownarrow") { 8283 top = "\\uparrow"; 8284 repeat = "\u23d0"; 8285 bottom = "\\downarrow"; 8286 } else if (delim === "\\Updownarrow") { 8287 top = "\\Uparrow"; 8288 repeat = "\u2016"; 8289 bottom = "\\Downarrow"; 8290 } else if (delim === "[" || delim === "\\lbrack") { 8291 top = "\u23a1"; 8292 repeat = "\u23a2"; 8293 bottom = "\u23a3"; 8294 font = "Size4-Regular"; 8295 } else if (delim === "]" || delim === "\\rbrack") { 8296 top = "\u23a4"; 8297 repeat = "\u23a5"; 8298 bottom = "\u23a6"; 8299 font = "Size4-Regular"; 8300 } else if (delim === "\\lfloor" || delim === "\u230a") { 8301 repeat = top = "\u23a2"; 8302 bottom = "\u23a3"; 8303 font = "Size4-Regular"; 8304 } else if (delim === "\\lceil" || delim === "\u2308") { 8305 top = "\u23a1"; 8306 repeat = bottom = "\u23a2"; 8307 font = "Size4-Regular"; 8308 } else if (delim === "\\rfloor" || delim === "\u230b") { 8309 repeat = top = "\u23a5"; 8310 bottom = "\u23a6"; 8311 font = "Size4-Regular"; 8312 } else if (delim === "\\rceil" || delim === "\u2309") { 8313 top = "\u23a4"; 8314 repeat = bottom = "\u23a5"; 8315 font = "Size4-Regular"; 8316 } else if (delim === "(" || delim === "\\lparen") { 8317 top = "\u239b"; 8318 repeat = "\u239c"; 8319 bottom = "\u239d"; 8320 font = "Size4-Regular"; 8321 } else if (delim === ")" || delim === "\\rparen") { 8322 top = "\u239e"; 8323 repeat = "\u239f"; 8324 bottom = "\u23a0"; 8325 font = "Size4-Regular"; 8326 } else if (delim === "\\{" || delim === "\\lbrace") { 8327 top = "\u23a7"; 8328 middle = "\u23a8"; 8329 bottom = "\u23a9"; 8330 repeat = "\u23aa"; 8331 font = "Size4-Regular"; 8332 } else if (delim === "\\}" || delim === "\\rbrace") { 8333 top = "\u23ab"; 8334 middle = "\u23ac"; 8335 bottom = "\u23ad"; 8336 repeat = "\u23aa"; 8337 font = "Size4-Regular"; 8338 } else if (delim === "\\lgroup" || delim === "\u27ee") { 8339 top = "\u23a7"; 8340 bottom = "\u23a9"; 8341 repeat = "\u23aa"; 8342 font = "Size4-Regular"; 8343 } else if (delim === "\\rgroup" || delim === "\u27ef") { 8344 top = "\u23ab"; 8345 bottom = "\u23ad"; 8346 repeat = "\u23aa"; 8347 font = "Size4-Regular"; 8348 } else if (delim === "\\lmoustache" || delim === "\u23b0") { 8349 top = "\u23a7"; 8350 bottom = "\u23ad"; 8351 repeat = "\u23aa"; 8352 font = "Size4-Regular"; 8353 } else if (delim === "\\rmoustache" || delim === "\u23b1") { 8354 top = "\u23ab"; 8355 bottom = "\u23a9"; 8356 repeat = "\u23aa"; 8357 font = "Size4-Regular"; 8358 } // Get the metrics of the four sections 8359 8360 8361 const topMetrics = getMetrics(top, font, mode); 8362 const topHeightTotal = topMetrics.height + topMetrics.depth; 8363 const repeatMetrics = getMetrics(repeat, font, mode); 8364 const repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth; 8365 const bottomMetrics = getMetrics(bottom, font, mode); 8366 const bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth; 8367 let middleHeightTotal = 0; 8368 let middleFactor = 1; 8369 8370 if (middle !== null) { 8371 const middleMetrics = getMetrics(middle, font, mode); 8372 middleHeightTotal = middleMetrics.height + middleMetrics.depth; 8373 middleFactor = 2; // repeat symmetrically above and below middle 8374 } // Calcuate the minimal height that the delimiter can have. 8375 // It is at least the size of the top, bottom, and optional middle combined. 8376 8377 8378 const minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal; // Compute the number of copies of the repeat symbol we will need 8379 8380 const repeatCount = Math.max(0, Math.ceil((heightTotal - minHeight) / (middleFactor * repeatHeightTotal))); // Compute the total height of the delimiter including all the symbols 8381 8382 const realHeightTotal = minHeight + repeatCount * middleFactor * repeatHeightTotal; // The center of the delimiter is placed at the center of the axis. Note 8383 // that in this context, "center" means that the delimiter should be 8384 // centered around the axis in the current style, while normally it is 8385 // centered around the axis in textstyle. 8386 8387 let axisHeight = options.fontMetrics().axisHeight; 8388 8389 if (center) { 8390 axisHeight *= options.sizeMultiplier; 8391 } // Calculate the depth 8392 8393 8394 const depth = realHeightTotal / 2 - axisHeight; // This function differs from the TeX procedure in one way. 8395 // We shift each repeat element downwards by 0.005em, to prevent a gap 8396 // due to browser floating point rounding error. 8397 // Then, at the last element-to element joint, we add one extra repeat 8398 // element to cover the gap created by the shifts. 8399 // Find the shift needed to align the upper end of the extra element at a point 8400 // 0.005em above the lower end of the top element. 8401 8402 const shiftOfExtraElement = (repeatCount + 1) * 0.005 - repeatHeightTotal; // Now, we start building the pieces that will go into the vlist 8403 // Keep a list of the inner pieces 8404 8405 const inners = []; // Add the bottom symbol 8406 8407 inners.push(makeInner(bottom, font, mode)); 8408 8409 if (middle === null) { 8410 // Add that many symbols 8411 for (let i = 0; i < repeatCount; i++) { 8412 inners.push(lap); // overlap 8413 8414 inners.push(makeInner(repeat, font, mode)); 8415 } 8416 } else { 8417 // When there is a middle bit, we need the middle part and two repeated 8418 // sections 8419 for (let i = 0; i < repeatCount; i++) { 8420 inners.push(lap); 8421 inners.push(makeInner(repeat, font, mode)); 8422 } // Insert one extra repeat element. 8423 8424 8425 inners.push({ 8426 type: "kern", 8427 size: shiftOfExtraElement 8428 }); 8429 inners.push(makeInner(repeat, font, mode)); 8430 inners.push(lap); // Now insert the middle of the brace. 8431 8432 inners.push(makeInner(middle, font, mode)); 8433 8434 for (let i = 0; i < repeatCount; i++) { 8435 inners.push(lap); 8436 inners.push(makeInner(repeat, font, mode)); 8437 } 8438 } // To cover the gap create by the overlaps, insert one more repeat element, 8439 // at a position that juts 0.005 above the bottom of the top element. 8440 8441 8442 inners.push({ 8443 type: "kern", 8444 size: shiftOfExtraElement 8445 }); 8446 inners.push(makeInner(repeat, font, mode)); 8447 inners.push(lap); // Add the top symbol 8448 8449 inners.push(makeInner(top, font, mode)); // Finally, build the vlist 8450 8451 const newOptions = options.havingBaseStyle(Style$1.TEXT); 8452 const inner = buildCommon.makeVList({ 8453 positionType: "bottom", 8454 positionData: depth, 8455 children: inners 8456 }, newOptions); 8457 return styleWrap(buildCommon.makeSpan(["delimsizing", "mult"], [inner], newOptions), Style$1.TEXT, options, classes); 8458}; // All surds have 0.08em padding above the viniculum inside the SVG. 8459// That keeps browser span height rounding error from pinching the line. 8460 8461 8462const vbPad = 80; // padding above the surd, measured inside the viewBox. 8463 8464const emPad = 0.08; // padding, in ems, measured in the document. 8465 8466const sqrtSvg = function sqrtSvg(sqrtName, height, viewBoxHeight, extraViniculum, options) { 8467 const path = sqrtPath(sqrtName, extraViniculum, viewBoxHeight); 8468 const pathNode = new PathNode(sqrtName, path); 8469 const svg = new SvgNode([pathNode], { 8470 // Note: 1000:1 ratio of viewBox to document em width. 8471 "width": "400em", 8472 "height": height + "em", 8473 "viewBox": "0 0 400000 " + viewBoxHeight, 8474 "preserveAspectRatio": "xMinYMin slice" 8475 }); 8476 return buildCommon.makeSvgSpan(["hide-tail"], [svg], options); 8477}; 8478/** 8479 * Make a sqrt image of the given height, 8480 */ 8481 8482 8483const makeSqrtImage = function makeSqrtImage(height, options) { 8484 // Define a newOptions that removes the effect of size changes such as \Huge. 8485 // We don't pick different a height surd for \Huge. For it, we scale up. 8486 const newOptions = options.havingBaseSizing(); // Pick the desired surd glyph from a sequence of surds. 8487 8488 const delim = traverseSequence("\\surd", height * newOptions.sizeMultiplier, stackLargeDelimiterSequence, newOptions); 8489 let sizeMultiplier = newOptions.sizeMultiplier; // default 8490 // The standard sqrt SVGs each have a 0.04em thick viniculum. 8491 // If Settings.minRuleThickness is larger than that, we add extraViniculum. 8492 8493 const extraViniculum = Math.max(0, options.minRuleThickness - options.fontMetrics().sqrtRuleThickness); // Create a span containing an SVG image of a sqrt symbol. 8494 8495 let span; 8496 let spanHeight = 0; 8497 let texHeight = 0; 8498 let viewBoxHeight = 0; 8499 let advanceWidth; // We create viewBoxes with 80 units of "padding" above each surd. 8500 // Then browser rounding error on the parent span height will not 8501 // encroach on the ink of the viniculum. But that padding is not 8502 // included in the TeX-like `height` used for calculation of 8503 // vertical alignment. So texHeight = span.height < span.style.height. 8504 8505 if (delim.type === "small") { 8506 // Get an SVG that is derived from glyph U+221A in font KaTeX-Main. 8507 // 1000 unit normal glyph height. 8508 viewBoxHeight = 1000 + 1000 * extraViniculum + vbPad; 8509 8510 if (height < 1.0) { 8511 sizeMultiplier = 1.0; // mimic a \textfont radical 8512 } else if (height < 1.4) { 8513 sizeMultiplier = 0.7; // mimic a \scriptfont radical 8514 } 8515 8516 spanHeight = (1.0 + extraViniculum + emPad) / sizeMultiplier; 8517 texHeight = (1.00 + extraViniculum) / sizeMultiplier; 8518 span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, extraViniculum, options); 8519 span.style.minWidth = "0.853em"; 8520 advanceWidth = 0.833 / sizeMultiplier; // from the font. 8521 } else if (delim.type === "large") { 8522 // These SVGs come from fonts: KaTeX_Size1, _Size2, etc. 8523 viewBoxHeight = (1000 + vbPad) * sizeToMaxHeight[delim.size]; 8524 texHeight = (sizeToMaxHeight[delim.size] + extraViniculum) / sizeMultiplier; 8525 spanHeight = (sizeToMaxHeight[delim.size] + extraViniculum + emPad) / sizeMultiplier; 8526 span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight, extraViniculum, options); 8527 span.style.minWidth = "1.02em"; 8528 advanceWidth = 1.0 / sizeMultiplier; // 1.0 from the font. 8529 } else { 8530 // Tall sqrt. In TeX, this would be stacked using multiple glyphs. 8531 // We'll use a single SVG to accomplish the same thing. 8532 spanHeight = height + extraViniculum + emPad; 8533 texHeight = height + extraViniculum; 8534 viewBoxHeight = Math.floor(1000 * height + extraViniculum) + vbPad; 8535 span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, extraViniculum, options); 8536 span.style.minWidth = "0.742em"; 8537 advanceWidth = 1.056; 8538 } 8539 8540 span.height = texHeight; 8541 span.style.height = spanHeight + "em"; 8542 return { 8543 span, 8544 advanceWidth, 8545 // Calculate the actual line width. 8546 // This actually should depend on the chosen font -- e.g. \boldmath 8547 // should use the thicker surd symbols from e.g. KaTeX_Main-Bold, and 8548 // have thicker rules. 8549 ruleWidth: (options.fontMetrics().sqrtRuleThickness + extraViniculum) * sizeMultiplier 8550 }; 8551}; // There are three kinds of delimiters, delimiters that stack when they become 8552// too large 8553 8554 8555const stackLargeDelimiters = ["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230a", "\u230b", "\\lceil", "\\rceil", "\u2308", "\u2309", "\\surd"]; // delimiters that always stack 8556 8557const stackAlwaysDelimiters = ["\\uparrow", "\\downarrow", "\\updownarrow", "\\Uparrow", "\\Downarrow", "\\Updownarrow", "|", "\\|", "\\vert", "\\Vert", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27ee", "\u27ef", "\\lmoustache", "\\rmoustache", "\u23b0", "\u23b1"]; // and delimiters that never stack 8558 8559const stackNeverDelimiters = ["<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt"]; // Metrics of the different sizes. Found by looking at TeX's output of 8560// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ 8561// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. 8562 8563const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; 8564/** 8565 * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4. 8566 */ 8567 8568const makeSizedDelim = function makeSizedDelim(delim, size, options, mode, classes) { 8569 // < and > turn into \langle and \rangle in delimiters 8570 if (delim === "<" || delim === "\\lt" || delim === "\u27e8") { 8571 delim = "\\langle"; 8572 } else if (delim === ">" || delim === "\\gt" || delim === "\u27e9") { 8573 delim = "\\rangle"; 8574 } // Sized delimiters are never centered. 8575 8576 8577 if (utils.contains(stackLargeDelimiters, delim) || utils.contains(stackNeverDelimiters, delim)) { 8578 return makeLargeDelim(delim, size, false, options, mode, classes); 8579 } else if (utils.contains(stackAlwaysDelimiters, delim)) { 8580 return makeStackedDelim(delim, sizeToMaxHeight[size], false, options, mode, classes); 8581 } else { 8582 throw new ParseError("Illegal delimiter: '" + delim + "'"); 8583 } 8584}; 8585/** 8586 * There are three different sequences of delimiter sizes that the delimiters 8587 * follow depending on the kind of delimiter. This is used when creating custom 8588 * sized delimiters to decide whether to create a small, large, or stacked 8589 * delimiter. 8590 * 8591 * In real TeX, these sequences aren't explicitly defined, but are instead 8592 * defined inside the font metrics. Since there are only three sequences that 8593 * are possible for the delimiters that TeX defines, it is easier to just encode 8594 * them explicitly here. 8595 */ 8596 8597 8598// Delimiters that never stack try small delimiters and large delimiters only 8599const stackNeverDelimiterSequence = [{ 8600 type: "small", 8601 style: Style$1.SCRIPTSCRIPT 8602}, { 8603 type: "small", 8604 style: Style$1.SCRIPT 8605}, { 8606 type: "small", 8607 style: Style$1.TEXT 8608}, { 8609 type: "large", 8610 size: 1 8611}, { 8612 type: "large", 8613 size: 2 8614}, { 8615 type: "large", 8616 size: 3 8617}, { 8618 type: "large", 8619 size: 4 8620}]; // Delimiters that always stack try the small delimiters first, then stack 8621 8622const stackAlwaysDelimiterSequence = [{ 8623 type: "small", 8624 style: Style$1.SCRIPTSCRIPT 8625}, { 8626 type: "small", 8627 style: Style$1.SCRIPT 8628}, { 8629 type: "small", 8630 style: Style$1.TEXT 8631}, { 8632 type: "stack" 8633}]; // Delimiters that stack when large try the small and then large delimiters, and 8634// stack afterwards 8635 8636const stackLargeDelimiterSequence = [{ 8637 type: "small", 8638 style: Style$1.SCRIPTSCRIPT 8639}, { 8640 type: "small", 8641 style: Style$1.SCRIPT 8642}, { 8643 type: "small", 8644 style: Style$1.TEXT 8645}, { 8646 type: "large", 8647 size: 1 8648}, { 8649 type: "large", 8650 size: 2 8651}, { 8652 type: "large", 8653 size: 3 8654}, { 8655 type: "large", 8656 size: 4 8657}, { 8658 type: "stack" 8659}]; 8660/** 8661 * Get the font used in a delimiter based on what kind of delimiter it is. 8662 * TODO(#963) Use more specific font family return type once that is introduced. 8663 */ 8664 8665const delimTypeToFont = function delimTypeToFont(type) { 8666 if (type.type === "small") { 8667 return "Main-Regular"; 8668 } else if (type.type === "large") { 8669 return "Size" + type.size + "-Regular"; 8670 } else if (type.type === "stack") { 8671 return "Size4-Regular"; 8672 } else { 8673 throw new Error(`Add support for delim type '${type.type}' here.`); 8674 } 8675}; 8676/** 8677 * Traverse a sequence of types of delimiters to decide what kind of delimiter 8678 * should be used to create a delimiter of the given height+depth. 8679 */ 8680 8681 8682const traverseSequence = function traverseSequence(delim, height, sequence, options) { 8683 // Here, we choose the index we should start at in the sequences. In smaller 8684 // sizes (which correspond to larger numbers in style.size) we start earlier 8685 // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts 8686 // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2 8687 const start = Math.min(2, 3 - options.style.size); 8688 8689 for (let i = start; i < sequence.length; i++) { 8690 if (sequence[i].type === "stack") { 8691 // This is always the last delimiter, so we just break the loop now. 8692 break; 8693 } 8694 8695 const metrics = getMetrics(delim, delimTypeToFont(sequence[i]), "math"); 8696 let heightDepth = metrics.height + metrics.depth; // Small delimiters are scaled down versions of the same font, so we 8697 // account for the style change size. 8698 8699 if (sequence[i].type === "small") { 8700 const newOptions = options.havingBaseStyle(sequence[i].style); 8701 heightDepth *= newOptions.sizeMultiplier; 8702 } // Check if the delimiter at this size works for the given height. 8703 8704 8705 if (heightDepth > height) { 8706 return sequence[i]; 8707 } 8708 } // If we reached the end of the sequence, return the last sequence element. 8709 8710 8711 return sequence[sequence.length - 1]; 8712}; 8713/** 8714 * Make a delimiter of a given height+depth, with optional centering. Here, we 8715 * traverse the sequences, and create a delimiter that the sequence tells us to. 8716 */ 8717 8718 8719const makeCustomSizedDelim = function makeCustomSizedDelim(delim, height, center, options, mode, classes) { 8720 if (delim === "<" || delim === "\\lt" || delim === "\u27e8") { 8721 delim = "\\langle"; 8722 } else if (delim === ">" || delim === "\\gt" || delim === "\u27e9") { 8723 delim = "\\rangle"; 8724 } // Decide what sequence to use 8725 8726 8727 let sequence; 8728 8729 if (utils.contains(stackNeverDelimiters, delim)) { 8730 sequence = stackNeverDelimiterSequence; 8731 } else if (utils.contains(stackLargeDelimiters, delim)) { 8732 sequence = stackLargeDelimiterSequence; 8733 } else { 8734 sequence = stackAlwaysDelimiterSequence; 8735 } // Look through the sequence 8736 8737 8738 const delimType = traverseSequence(delim, height, sequence, options); // Get the delimiter from font glyphs. 8739 // Depending on the sequence element we decided on, call the 8740 // appropriate function. 8741 8742 if (delimType.type === "small") { 8743 return makeSmallDelim(delim, delimType.style, center, options, mode, classes); 8744 } else if (delimType.type === "large") { 8745 return makeLargeDelim(delim, delimType.size, center, options, mode, classes); 8746 } else 8747 /* if (delimType.type === "stack") */ 8748 { 8749 return makeStackedDelim(delim, height, center, options, mode, classes); 8750 } 8751}; 8752/** 8753 * Make a delimiter for use with `\left` and `\right`, given a height and depth 8754 * of an expression that the delimiters surround. 8755 */ 8756 8757 8758const makeLeftRightDelim = function makeLeftRightDelim(delim, height, depth, options, mode, classes) { 8759 // We always center \left/\right delimiters, so the axis is always shifted 8760 const axisHeight = options.fontMetrics().axisHeight * options.sizeMultiplier; // Taken from TeX source, tex.web, function make_left_right 8761 8762 const delimiterFactor = 901; 8763 const delimiterExtend = 5.0 / options.fontMetrics().ptPerEm; 8764 const maxDistFromAxis = Math.max(height - axisHeight, depth + axisHeight); 8765 const totalHeight = Math.max( // In real TeX, calculations are done using integral values which are 8766 // 65536 per pt, or 655360 per em. So, the division here truncates in 8767 // TeX but doesn't here, producing different results. If we wanted to 8768 // exactly match TeX's calculation, we could do 8769 // Math.floor(655360 * maxDistFromAxis / 500) * 8770 // delimiterFactor / 655360 8771 // (To see the difference, compare 8772 // x^{x^{\left(\rule{0.1em}{0.68em}\right)}} 8773 // in TeX and KaTeX) 8774 maxDistFromAxis / 500 * delimiterFactor, 2 * maxDistFromAxis - delimiterExtend); // Finally, we defer to `makeCustomSizedDelim` with our calculated total 8775 // height 8776 8777 return makeCustomSizedDelim(delim, totalHeight, true, options, mode, classes); 8778}; 8779 8780var delimiter = { 8781 sqrtImage: makeSqrtImage, 8782 sizedDelim: makeSizedDelim, 8783 customSizedDelim: makeCustomSizedDelim, 8784 leftRightDelim: makeLeftRightDelim 8785}; 8786 8787// Extra data needed for the delimiter handler down below 8788const delimiterSizes = { 8789 "\\bigl": { 8790 mclass: "mopen", 8791 size: 1 8792 }, 8793 "\\Bigl": { 8794 mclass: "mopen", 8795 size: 2 8796 }, 8797 "\\biggl": { 8798 mclass: "mopen", 8799 size: 3 8800 }, 8801 "\\Biggl": { 8802 mclass: "mopen", 8803 size: 4 8804 }, 8805 "\\bigr": { 8806 mclass: "mclose", 8807 size: 1 8808 }, 8809 "\\Bigr": { 8810 mclass: "mclose", 8811 size: 2 8812 }, 8813 "\\biggr": { 8814 mclass: "mclose", 8815 size: 3 8816 }, 8817 "\\Biggr": { 8818 mclass: "mclose", 8819 size: 4 8820 }, 8821 "\\bigm": { 8822 mclass: "mrel", 8823 size: 1 8824 }, 8825 "\\Bigm": { 8826 mclass: "mrel", 8827 size: 2 8828 }, 8829 "\\biggm": { 8830 mclass: "mrel", 8831 size: 3 8832 }, 8833 "\\Biggm": { 8834 mclass: "mrel", 8835 size: 4 8836 }, 8837 "\\big": { 8838 mclass: "mord", 8839 size: 1 8840 }, 8841 "\\Big": { 8842 mclass: "mord", 8843 size: 2 8844 }, 8845 "\\bigg": { 8846 mclass: "mord", 8847 size: 3 8848 }, 8849 "\\Bigg": { 8850 mclass: "mord", 8851 size: 4 8852 } 8853}; 8854const delimiters = ["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230a", "\u230b", "\\lceil", "\\rceil", "\u2308", "\u2309", "<", ">", "\\langle", "\u27e8", "\\rangle", "\u27e9", "\\lt", "\\gt", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27ee", "\u27ef", "\\lmoustache", "\\rmoustache", "\u23b0", "\u23b1", "/", "\\backslash", "|", "\\vert", "\\|", "\\Vert", "\\uparrow", "\\Uparrow", "\\downarrow", "\\Downarrow", "\\updownarrow", "\\Updownarrow", "."]; 8855 8856// Delimiter functions 8857function checkDelimiter(delim, context) { 8858 const symDelim = checkSymbolNodeType(delim); 8859 8860 if (symDelim && utils.contains(delimiters, symDelim.text)) { 8861 return symDelim; 8862 } else { 8863 throw new ParseError("Invalid delimiter: '" + (symDelim ? symDelim.text : JSON.stringify(delim)) + "' after '" + context.funcName + "'", delim); 8864 } 8865} 8866 8867defineFunction({ 8868 type: "delimsizing", 8869 names: ["\\bigl", "\\Bigl", "\\biggl", "\\Biggl", "\\bigr", "\\Bigr", "\\biggr", "\\Biggr", "\\bigm", "\\Bigm", "\\biggm", "\\Biggm", "\\big", "\\Big", "\\bigg", "\\Bigg"], 8870 props: { 8871 numArgs: 1 8872 }, 8873 handler: (context, args) => { 8874 const delim = checkDelimiter(args[0], context); 8875 return { 8876 type: "delimsizing", 8877 mode: context.parser.mode, 8878 size: delimiterSizes[context.funcName].size, 8879 mclass: delimiterSizes[context.funcName].mclass, 8880 delim: delim.text 8881 }; 8882 }, 8883 htmlBuilder: (group, options) => { 8884 if (group.delim === ".") { 8885 // Empty delimiters still count as elements, even though they don't 8886 // show anything. 8887 return buildCommon.makeSpan([group.mclass]); 8888 } // Use delimiter.sizedDelim to generate the delimiter. 8889 8890 8891 return delimiter.sizedDelim(group.delim, group.size, options, group.mode, [group.mclass]); 8892 }, 8893 mathmlBuilder: group => { 8894 const children = []; 8895 8896 if (group.delim !== ".") { 8897 children.push(makeText(group.delim, group.mode)); 8898 } 8899 8900 const node = new mathMLTree.MathNode("mo", children); 8901 8902 if (group.mclass === "mopen" || group.mclass === "mclose") { 8903 // Only some of the delimsizing functions act as fences, and they 8904 // return "mopen" or "mclose" mclass. 8905 node.setAttribute("fence", "true"); 8906 } else { 8907 // Explicitly disable fencing if it's not a fence, to override the 8908 // defaults. 8909 node.setAttribute("fence", "false"); 8910 } 8911 8912 return node; 8913 } 8914}); 8915 8916function assertParsed(group) { 8917 if (!group.body) { 8918 throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); 8919 } 8920} 8921 8922defineFunction({ 8923 type: "leftright-right", 8924 names: ["\\right"], 8925 props: { 8926 numArgs: 1 8927 }, 8928 handler: (context, args) => { 8929 // \left case below triggers parsing of \right in 8930 // `const right = parser.parseFunction();` 8931 // uses this return value. 8932 const color = context.parser.gullet.macros.get("\\current@color"); 8933 8934 if (color && typeof color !== "string") { 8935 throw new ParseError("\\current@color set to non-string in \\right"); 8936 } 8937 8938 return { 8939 type: "leftright-right", 8940 mode: context.parser.mode, 8941 delim: checkDelimiter(args[0], context).text, 8942 color // undefined if not set via \color 8943 8944 }; 8945 } 8946}); 8947defineFunction({ 8948 type: "leftright", 8949 names: ["\\left"], 8950 props: { 8951 numArgs: 1 8952 }, 8953 handler: (context, args) => { 8954 const delim = checkDelimiter(args[0], context); 8955 const parser = context.parser; // Parse out the implicit body 8956 8957 ++parser.leftrightDepth; // parseExpression stops before '\\right' 8958 8959 const body = parser.parseExpression(false); 8960 --parser.leftrightDepth; // Check the next token 8961 8962 parser.expect("\\right", false); 8963 const right = assertNodeType(parser.parseFunction(), "leftright-right"); 8964 return { 8965 type: "leftright", 8966 mode: parser.mode, 8967 body, 8968 left: delim.text, 8969 right: right.delim, 8970 rightColor: right.color 8971 }; 8972 }, 8973 htmlBuilder: (group, options) => { 8974 assertParsed(group); // Build the inner expression 8975 8976 const inner = buildExpression(group.body, options, true, ["mopen", "mclose"]); 8977 let innerHeight = 0; 8978 let innerDepth = 0; 8979 let hadMiddle = false; // Calculate its height and depth 8980 8981 for (let i = 0; i < inner.length; i++) { 8982 // Property `isMiddle` not defined on `span`. See comment in 8983 // "middle"'s htmlBuilder. 8984 // $FlowFixMe 8985 if (inner[i].isMiddle) { 8986 hadMiddle = true; 8987 } else { 8988 innerHeight = Math.max(inner[i].height, innerHeight); 8989 innerDepth = Math.max(inner[i].depth, innerDepth); 8990 } 8991 } // The size of delimiters is the same, regardless of what style we are 8992 // in. Thus, to correctly calculate the size of delimiter we need around 8993 // a group, we scale down the inner size based on the size. 8994 8995 8996 innerHeight *= options.sizeMultiplier; 8997 innerDepth *= options.sizeMultiplier; 8998 let leftDelim; 8999 9000 if (group.left === ".") { 9001 // Empty delimiters in \left and \right make null delimiter spaces. 9002 leftDelim = makeNullDelimiter(options, ["mopen"]); 9003 } else { 9004 // Otherwise, use leftRightDelim to generate the correct sized 9005 // delimiter. 9006 leftDelim = delimiter.leftRightDelim(group.left, innerHeight, innerDepth, options, group.mode, ["mopen"]); 9007 } // Add it to the beginning of the expression 9008 9009 9010 inner.unshift(leftDelim); // Handle middle delimiters 9011 9012 if (hadMiddle) { 9013 for (let i = 1; i < inner.length; i++) { 9014 const middleDelim = inner[i]; // Property `isMiddle` not defined on `span`. See comment in 9015 // "middle"'s htmlBuilder. 9016 // $FlowFixMe 9017 9018 const isMiddle = middleDelim.isMiddle; 9019 9020 if (isMiddle) { 9021 // Apply the options that were active when \middle was called 9022 inner[i] = delimiter.leftRightDelim(isMiddle.delim, innerHeight, innerDepth, isMiddle.options, group.mode, []); 9023 } 9024 } 9025 } 9026 9027 let rightDelim; // Same for the right delimiter, but using color specified by \color 9028 9029 if (group.right === ".") { 9030 rightDelim = makeNullDelimiter(options, ["mclose"]); 9031 } else { 9032 const colorOptions = group.rightColor ? options.withColor(group.rightColor) : options; 9033 rightDelim = delimiter.leftRightDelim(group.right, innerHeight, innerDepth, colorOptions, group.mode, ["mclose"]); 9034 } // Add it to the end of the expression. 9035 9036 9037 inner.push(rightDelim); 9038 return buildCommon.makeSpan(["minner"], inner, options); 9039 }, 9040 mathmlBuilder: (group, options) => { 9041 assertParsed(group); 9042 const inner = buildExpression$1(group.body, options); 9043 9044 if (group.left !== ".") { 9045 const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); 9046 leftNode.setAttribute("fence", "true"); 9047 inner.unshift(leftNode); 9048 } 9049 9050 if (group.right !== ".") { 9051 const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); 9052 rightNode.setAttribute("fence", "true"); 9053 9054 if (group.rightColor) { 9055 rightNode.setAttribute("mathcolor", group.rightColor); 9056 } 9057 9058 inner.push(rightNode); 9059 } 9060 9061 return makeRow(inner); 9062 } 9063}); 9064defineFunction({ 9065 type: "middle", 9066 names: ["\\middle"], 9067 props: { 9068 numArgs: 1 9069 }, 9070 handler: (context, args) => { 9071 const delim = checkDelimiter(args[0], context); 9072 9073 if (!context.parser.leftrightDepth) { 9074 throw new ParseError("\\middle without preceding \\left", delim); 9075 } 9076 9077 return { 9078 type: "middle", 9079 mode: context.parser.mode, 9080 delim: delim.text 9081 }; 9082 }, 9083 htmlBuilder: (group, options) => { 9084 let middleDelim; 9085 9086 if (group.delim === ".") { 9087 middleDelim = makeNullDelimiter(options, []); 9088 } else { 9089 middleDelim = delimiter.sizedDelim(group.delim, 1, options, group.mode, []); 9090 const isMiddle = { 9091 delim: group.delim, 9092 options 9093 }; // Property `isMiddle` not defined on `span`. It is only used in 9094 // this file above. 9095 // TODO: Fix this violation of the `span` type and possibly rename 9096 // things since `isMiddle` sounds like a boolean, but is a struct. 9097 // $FlowFixMe 9098 9099 middleDelim.isMiddle = isMiddle; 9100 } 9101 9102 return middleDelim; 9103 }, 9104 mathmlBuilder: (group, options) => { 9105 // A Firefox \middle will strech a character vertically only if it 9106 // is in the fence part of the operator dictionary at: 9107 // https://www.w3.org/TR/MathML3/appendixc.html. 9108 // So we need to avoid U+2223 and use plain "|" instead. 9109 const textNode = group.delim === "\\vert" || group.delim === "|" ? makeText("|", "text") : makeText(group.delim, group.mode); 9110 const middleNode = new mathMLTree.MathNode("mo", [textNode]); 9111 middleNode.setAttribute("fence", "true"); // MathML gives 5/18em spacing to each <mo> element. 9112 // \middle should get delimiter spacing instead. 9113 9114 middleNode.setAttribute("lspace", "0.05em"); 9115 middleNode.setAttribute("rspace", "0.05em"); 9116 return middleNode; 9117 } 9118}); 9119 9120const htmlBuilder$2 = (group, options) => { 9121 // \cancel, \bcancel, \xcancel, \sout, \fbox, \colorbox, \fcolorbox 9122 // Some groups can return document fragments. Handle those by wrapping 9123 // them in a span. 9124 const inner = buildCommon.wrapFragment(buildGroup(group.body, options), options); 9125 const label = group.label.substr(1); 9126 const scale = options.sizeMultiplier; 9127 let img; 9128 let imgShift = 0; // In the LaTeX cancel package, line geometry is slightly different 9129 // depending on whether the subject is wider than it is tall, or vice versa. 9130 // We don't know the width of a group, so as a proxy, we test if 9131 // the subject is a single character. This captures most of the 9132 // subjects that should get the "tall" treatment. 9133 9134 const isSingleChar = utils.isCharacterBox(group.body); 9135 9136 if (label === "sout") { 9137 img = buildCommon.makeSpan(["stretchy", "sout"]); 9138 img.height = options.fontMetrics().defaultRuleThickness / scale; 9139 imgShift = -0.5 * options.fontMetrics().xHeight; 9140 } else { 9141 // Add horizontal padding 9142 if (/cancel/.test(label)) { 9143 if (!isSingleChar) { 9144 inner.classes.push("cancel-pad"); 9145 } 9146 } else { 9147 inner.classes.push("boxpad"); 9148 } // Add vertical padding 9149 9150 9151 let vertPad = 0; 9152 let ruleThickness = 0; // ref: cancel package: \advance\totalheight2\p@ % "+2" 9153 9154 if (/box/.test(label)) { 9155 ruleThickness = Math.max(options.fontMetrics().fboxrule, // default 9156 options.minRuleThickness // User override. 9157 ); 9158 vertPad = options.fontMetrics().fboxsep + (label === "colorbox" ? 0 : ruleThickness); 9159 } else { 9160 vertPad = isSingleChar ? 0.2 : 0; 9161 } 9162 9163 img = stretchy.encloseSpan(inner, label, vertPad, options); 9164 9165 if (/fbox|boxed|fcolorbox/.test(label)) { 9166 img.style.borderStyle = "solid"; 9167 img.style.borderWidth = `${ruleThickness}em`; 9168 } 9169 9170 imgShift = inner.depth + vertPad; 9171 9172 if (group.backgroundColor) { 9173 img.style.backgroundColor = group.backgroundColor; 9174 9175 if (group.borderColor) { 9176 img.style.borderColor = group.borderColor; 9177 } 9178 } 9179 } 9180 9181 let vlist; 9182 9183 if (group.backgroundColor) { 9184 vlist = buildCommon.makeVList({ 9185 positionType: "individualShift", 9186 children: [// Put the color background behind inner; 9187 { 9188 type: "elem", 9189 elem: img, 9190 shift: imgShift 9191 }, { 9192 type: "elem", 9193 elem: inner, 9194 shift: 0 9195 }] 9196 }, options); 9197 } else { 9198 vlist = buildCommon.makeVList({ 9199 positionType: "individualShift", 9200 children: [// Write the \cancel stroke on top of inner. 9201 { 9202 type: "elem", 9203 elem: inner, 9204 shift: 0 9205 }, { 9206 type: "elem", 9207 elem: img, 9208 shift: imgShift, 9209 wrapperClasses: /cancel/.test(label) ? ["svg-align"] : [] 9210 }] 9211 }, options); 9212 } 9213 9214 if (/cancel/.test(label)) { 9215 // The cancel package documentation says that cancel lines add their height 9216 // to the expression, but tests show that isn't how it actually works. 9217 vlist.height = inner.height; 9218 vlist.depth = inner.depth; 9219 } 9220 9221 if (/cancel/.test(label) && !isSingleChar) { 9222 // cancel does not create horiz space for its line extension. 9223 return buildCommon.makeSpan(["mord", "cancel-lap"], [vlist], options); 9224 } else { 9225 return buildCommon.makeSpan(["mord"], [vlist], options); 9226 } 9227}; 9228 9229const mathmlBuilder$2 = (group, options) => { 9230 let fboxsep = 0; 9231 const node = new mathMLTree.MathNode(group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", [buildGroup$1(group.body, options)]); 9232 9233 switch (group.label) { 9234 case "\\cancel": 9235 node.setAttribute("notation", "updiagonalstrike"); 9236 break; 9237 9238 case "\\bcancel": 9239 node.setAttribute("notation", "downdiagonalstrike"); 9240 break; 9241 9242 case "\\sout": 9243 node.setAttribute("notation", "horizontalstrike"); 9244 break; 9245 9246 case "\\fbox": 9247 node.setAttribute("notation", "box"); 9248 break; 9249 9250 case "\\fcolorbox": 9251 case "\\colorbox": 9252 // <menclose> doesn't have a good notation option. So use <mpadded> 9253 // instead. Set some attributes that come included with <menclose>. 9254 fboxsep = options.fontMetrics().fboxsep * options.fontMetrics().ptPerEm; 9255 node.setAttribute("width", `+${2 * fboxsep}pt`); 9256 node.setAttribute("height", `+${2 * fboxsep}pt`); 9257 node.setAttribute("lspace", `${fboxsep}pt`); // 9258 9259 node.setAttribute("voffset", `${fboxsep}pt`); 9260 9261 if (group.label === "\\fcolorbox") { 9262 const thk = Math.max(options.fontMetrics().fboxrule, // default 9263 options.minRuleThickness // user override 9264 ); 9265 node.setAttribute("style", "border: " + thk + "em solid " + String(group.borderColor)); 9266 } 9267 9268 break; 9269 9270 case "\\xcancel": 9271 node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); 9272 break; 9273 } 9274 9275 if (group.backgroundColor) { 9276 node.setAttribute("mathbackground", group.backgroundColor); 9277 } 9278 9279 return node; 9280}; 9281 9282defineFunction({ 9283 type: "enclose", 9284 names: ["\\colorbox"], 9285 props: { 9286 numArgs: 2, 9287 allowedInText: true, 9288 greediness: 3, 9289 argTypes: ["color", "text"] 9290 }, 9291 9292 handler(_ref, args, optArgs) { 9293 let parser = _ref.parser, 9294 funcName = _ref.funcName; 9295 const color = assertNodeType(args[0], "color-token").color; 9296 const body = args[1]; 9297 return { 9298 type: "enclose", 9299 mode: parser.mode, 9300 label: funcName, 9301 backgroundColor: color, 9302 body 9303 }; 9304 }, 9305 9306 htmlBuilder: htmlBuilder$2, 9307 mathmlBuilder: mathmlBuilder$2 9308}); 9309defineFunction({ 9310 type: "enclose", 9311 names: ["\\fcolorbox"], 9312 props: { 9313 numArgs: 3, 9314 allowedInText: true, 9315 greediness: 3, 9316 argTypes: ["color", "color", "text"] 9317 }, 9318 9319 handler(_ref2, args, optArgs) { 9320 let parser = _ref2.parser, 9321 funcName = _ref2.funcName; 9322 const borderColor = assertNodeType(args[0], "color-token").color; 9323 const backgroundColor = assertNodeType(args[1], "color-token").color; 9324 const body = args[2]; 9325 return { 9326 type: "enclose", 9327 mode: parser.mode, 9328 label: funcName, 9329 backgroundColor, 9330 borderColor, 9331 body 9332 }; 9333 }, 9334 9335 htmlBuilder: htmlBuilder$2, 9336 mathmlBuilder: mathmlBuilder$2 9337}); 9338defineFunction({ 9339 type: "enclose", 9340 names: ["\\fbox"], 9341 props: { 9342 numArgs: 1, 9343 argTypes: ["hbox"], 9344 allowedInText: true 9345 }, 9346 9347 handler(_ref3, args) { 9348 let parser = _ref3.parser; 9349 return { 9350 type: "enclose", 9351 mode: parser.mode, 9352 label: "\\fbox", 9353 body: args[0] 9354 }; 9355 } 9356 9357}); 9358defineFunction({ 9359 type: "enclose", 9360 names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout"], 9361 props: { 9362 numArgs: 1 9363 }, 9364 9365 handler(_ref4, args, optArgs) { 9366 let parser = _ref4.parser, 9367 funcName = _ref4.funcName; 9368 const body = args[0]; 9369 return { 9370 type: "enclose", 9371 mode: parser.mode, 9372 label: funcName, 9373 body 9374 }; 9375 }, 9376 9377 htmlBuilder: htmlBuilder$2, 9378 mathmlBuilder: mathmlBuilder$2 9379}); 9380 9381/** 9382 * All registered environments. 9383 * `environments.js` exports this same dictionary again and makes it public. 9384 * `Parser.js` requires this dictionary via `environments.js`. 9385 */ 9386const _environments = {}; 9387function defineEnvironment(_ref) { 9388 let type = _ref.type, 9389 names = _ref.names, 9390 props = _ref.props, 9391 handler = _ref.handler, 9392 htmlBuilder = _ref.htmlBuilder, 9393 mathmlBuilder = _ref.mathmlBuilder; 9394 // Set default values of environments. 9395 const data = { 9396 type, 9397 numArgs: props.numArgs || 0, 9398 greediness: 1, 9399 allowedInText: false, 9400 numOptionalArgs: 0, 9401 handler 9402 }; 9403 9404 for (let i = 0; i < names.length; ++i) { 9405 // TODO: The value type of _environments should be a type union of all 9406 // possible `EnvSpec<>` possibilities instead of `EnvSpec<*>`, which is 9407 // an existential type. 9408 // $FlowFixMe 9409 _environments[names[i]] = data; 9410 } 9411 9412 if (htmlBuilder) { 9413 _htmlGroupBuilders[type] = htmlBuilder; 9414 } 9415 9416 if (mathmlBuilder) { 9417 _mathmlGroupBuilders[type] = mathmlBuilder; 9418 } 9419} 9420 9421function getHLines(parser) { 9422 // Return an array. The array length = number of hlines. 9423 // Each element in the array tells if the line is dashed. 9424 const hlineInfo = []; 9425 parser.consumeSpaces(); 9426 let nxt = parser.fetch().text; 9427 9428 while (nxt === "\\hline" || nxt === "\\hdashline") { 9429 parser.consume(); 9430 hlineInfo.push(nxt === "\\hdashline"); 9431 parser.consumeSpaces(); 9432 nxt = parser.fetch().text; 9433 } 9434 9435 return hlineInfo; 9436} 9437/** 9438 * Parse the body of the environment, with rows delimited by \\ and 9439 * columns delimited by &, and create a nested list in row-major order 9440 * with one group per cell. If given an optional argument style 9441 * ("text", "display", etc.), then each cell is cast into that style. 9442 */ 9443 9444 9445function parseArray(parser, _ref, style) { 9446 let hskipBeforeAndAfter = _ref.hskipBeforeAndAfter, 9447 addJot = _ref.addJot, 9448 cols = _ref.cols, 9449 arraystretch = _ref.arraystretch, 9450 colSeparationType = _ref.colSeparationType; 9451 // Parse body of array with \\ temporarily mapped to \cr 9452 parser.gullet.beginGroup(); 9453 parser.gullet.macros.set("\\\\", "\\cr"); // Get current arraystretch if it's not set by the environment 9454 9455 if (!arraystretch) { 9456 const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); 9457 9458 if (stretch == null) { 9459 // Default \arraystretch from lttab.dtx 9460 arraystretch = 1; 9461 } else { 9462 arraystretch = parseFloat(stretch); 9463 9464 if (!arraystretch || arraystretch < 0) { 9465 throw new ParseError(`Invalid \\arraystretch: ${stretch}`); 9466 } 9467 } 9468 } // Start group for first cell 9469 9470 9471 parser.gullet.beginGroup(); 9472 let row = []; 9473 const body = [row]; 9474 const rowGaps = []; 9475 const hLinesBeforeRow = []; // Test for \hline at the top of the array. 9476 9477 hLinesBeforeRow.push(getHLines(parser)); 9478 9479 while (true) { 9480 // eslint-disable-line no-constant-condition 9481 // Parse each cell in its own group (namespace) 9482 let cell = parser.parseExpression(false, "\\cr"); 9483 parser.gullet.endGroup(); 9484 parser.gullet.beginGroup(); 9485 cell = { 9486 type: "ordgroup", 9487 mode: parser.mode, 9488 body: cell 9489 }; 9490 9491 if (style) { 9492 cell = { 9493 type: "styling", 9494 mode: parser.mode, 9495 style, 9496 body: [cell] 9497 }; 9498 } 9499 9500 row.push(cell); 9501 const next = parser.fetch().text; 9502 9503 if (next === "&") { 9504 parser.consume(); 9505 } else if (next === "\\end") { 9506 // Arrays terminate newlines with `\crcr` which consumes a `\cr` if 9507 // the last line is empty. 9508 // NOTE: Currently, `cell` is the last item added into `row`. 9509 if (row.length === 1 && cell.type === "styling" && cell.body[0].body.length === 0) { 9510 body.pop(); 9511 } 9512 9513 if (hLinesBeforeRow.length < body.length + 1) { 9514 hLinesBeforeRow.push([]); 9515 } 9516 9517 break; 9518 } else if (next === "\\cr") { 9519 const cr = assertNodeType(parser.parseFunction(), "cr"); 9520 rowGaps.push(cr.size); // check for \hline(s) following the row separator 9521 9522 hLinesBeforeRow.push(getHLines(parser)); 9523 row = []; 9524 body.push(row); 9525 } else { 9526 throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); 9527 } 9528 } // End cell group 9529 9530 9531 parser.gullet.endGroup(); // End array group defining \\ 9532 9533 parser.gullet.endGroup(); 9534 return { 9535 type: "array", 9536 mode: parser.mode, 9537 addJot, 9538 arraystretch, 9539 body, 9540 cols, 9541 rowGaps, 9542 hskipBeforeAndAfter, 9543 hLinesBeforeRow, 9544 colSeparationType 9545 }; 9546} // Decides on a style for cells in an array according to whether the given 9547// environment name starts with the letter 'd'. 9548 9549 9550function dCellStyle(envName) { 9551 if (envName.substr(0, 1) === "d") { 9552 return "display"; 9553 } else { 9554 return "text"; 9555 } 9556} 9557 9558const htmlBuilder$3 = function htmlBuilder(group, options) { 9559 let r; 9560 let c; 9561 const nr = group.body.length; 9562 const hLinesBeforeRow = group.hLinesBeforeRow; 9563 let nc = 0; 9564 let body = new Array(nr); 9565 const hlines = []; 9566 const ruleThickness = Math.max( // From LaTeX \showthe\arrayrulewidth. Equals 0.04 em. 9567 options.fontMetrics().arrayRuleWidth, options.minRuleThickness // User override. 9568 ); // Horizontal spacing 9569 9570 const pt = 1 / options.fontMetrics().ptPerEm; 9571 let arraycolsep = 5 * pt; // default value, i.e. \arraycolsep in article.cls 9572 9573 if (group.colSeparationType && group.colSeparationType === "small") { 9574 // We're in a {smallmatrix}. Default column space is \thickspace, 9575 // i.e. 5/18em = 0.2778em, per amsmath.dtx for {smallmatrix}. 9576 // But that needs adjustment because LaTeX applies \scriptstyle to the 9577 // entire array, including the colspace, but this function applies 9578 // \scriptstyle only inside each element. 9579 const localMultiplier = options.havingStyle(Style$1.SCRIPT).sizeMultiplier; 9580 arraycolsep = 0.2778 * (localMultiplier / options.sizeMultiplier); 9581 } // Vertical spacing 9582 9583 9584 const baselineskip = 12 * pt; // see size10.clo 9585 // Default \jot from ltmath.dtx 9586 // TODO(edemaine): allow overriding \jot via \setlength (#687) 9587 9588 const jot = 3 * pt; 9589 const arrayskip = group.arraystretch * baselineskip; 9590 const arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and 9591 9592 const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx 9593 9594 let totalHeight = 0; // Set a position for \hline(s) at the top of the array, if any. 9595 9596 function setHLinePos(hlinesInGap) { 9597 for (let i = 0; i < hlinesInGap.length; ++i) { 9598 if (i > 0) { 9599 totalHeight += 0.25; 9600 } 9601 9602 hlines.push({ 9603 pos: totalHeight, 9604 isDashed: hlinesInGap[i] 9605 }); 9606 } 9607 } 9608 9609 setHLinePos(hLinesBeforeRow[0]); 9610 9611 for (r = 0; r < group.body.length; ++r) { 9612 const inrow = group.body[r]; 9613 let height = arstrutHeight; // \@array adds an \@arstrut 9614 9615 let depth = arstrutDepth; // to each tow (via the template) 9616 9617 if (nc < inrow.length) { 9618 nc = inrow.length; 9619 } 9620 9621 const outrow = new Array(inrow.length); 9622 9623 for (c = 0; c < inrow.length; ++c) { 9624 const elt = buildGroup(inrow[c], options); 9625 9626 if (depth < elt.depth) { 9627 depth = elt.depth; 9628 } 9629 9630 if (height < elt.height) { 9631 height = elt.height; 9632 } 9633 9634 outrow[c] = elt; 9635 } 9636 9637 const rowGap = group.rowGaps[r]; 9638 let gap = 0; 9639 9640 if (rowGap) { 9641 gap = calculateSize(rowGap, options); 9642 9643 if (gap > 0) { 9644 // \@argarraycr 9645 gap += arstrutDepth; 9646 9647 if (depth < gap) { 9648 depth = gap; // \@xargarraycr 9649 } 9650 9651 gap = 0; 9652 } 9653 } // In AMS multiline environments such as aligned and gathered, rows 9654 // correspond to lines that have additional \jot added to the 9655 // \baselineskip via \openup. 9656 9657 9658 if (group.addJot) { 9659 depth += jot; 9660 } 9661 9662 outrow.height = height; 9663 outrow.depth = depth; 9664 totalHeight += height; 9665 outrow.pos = totalHeight; 9666 totalHeight += depth + gap; // \@yargarraycr 9667 9668 body[r] = outrow; // Set a position for \hline(s), if any. 9669 9670 setHLinePos(hLinesBeforeRow[r + 1]); 9671 } 9672 9673 const offset = totalHeight / 2 + options.fontMetrics().axisHeight; 9674 const colDescriptions = group.cols || []; 9675 const cols = []; 9676 let colSep; 9677 let colDescrNum; 9678 9679 for (c = 0, colDescrNum = 0; // Continue while either there are more columns or more column 9680 // descriptions, so trailing separators don't get lost. 9681 c < nc || colDescrNum < colDescriptions.length; ++c, ++colDescrNum) { 9682 let colDescr = colDescriptions[colDescrNum] || {}; 9683 let firstSeparator = true; 9684 9685 while (colDescr.type === "separator") { 9686 // If there is more than one separator in a row, add a space 9687 // between them. 9688 if (!firstSeparator) { 9689 colSep = buildCommon.makeSpan(["arraycolsep"], []); 9690 colSep.style.width = options.fontMetrics().doubleRuleSep + "em"; 9691 cols.push(colSep); 9692 } 9693 9694 if (colDescr.separator === "|" || colDescr.separator === ":") { 9695 const lineType = colDescr.separator === "|" ? "solid" : "dashed"; 9696 const separator = buildCommon.makeSpan(["vertical-separator"], [], options); 9697 separator.style.height = totalHeight + "em"; 9698 separator.style.borderRightWidth = `${ruleThickness}em`; 9699 separator.style.borderRightStyle = lineType; 9700 separator.style.margin = `0 -${ruleThickness / 2}em`; 9701 separator.style.verticalAlign = -(totalHeight - offset) + "em"; 9702 cols.push(separator); 9703 } else { 9704 throw new ParseError("Invalid separator type: " + colDescr.separator); 9705 } 9706 9707 colDescrNum++; 9708 colDescr = colDescriptions[colDescrNum] || {}; 9709 firstSeparator = false; 9710 } 9711 9712 if (c >= nc) { 9713 continue; 9714 } 9715 9716 let sepwidth; 9717 9718 if (c > 0 || group.hskipBeforeAndAfter) { 9719 sepwidth = utils.deflt(colDescr.pregap, arraycolsep); 9720 9721 if (sepwidth !== 0) { 9722 colSep = buildCommon.makeSpan(["arraycolsep"], []); 9723 colSep.style.width = sepwidth + "em"; 9724 cols.push(colSep); 9725 } 9726 } 9727 9728 let col = []; 9729 9730 for (r = 0; r < nr; ++r) { 9731 const row = body[r]; 9732 const elem = row[c]; 9733 9734 if (!elem) { 9735 continue; 9736 } 9737 9738 const shift = row.pos - offset; 9739 elem.depth = row.depth; 9740 elem.height = row.height; 9741 col.push({ 9742 type: "elem", 9743 elem: elem, 9744 shift: shift 9745 }); 9746 } 9747 9748 col = buildCommon.makeVList({ 9749 positionType: "individualShift", 9750 children: col 9751 }, options); 9752 col = buildCommon.makeSpan(["col-align-" + (colDescr.align || "c")], [col]); 9753 cols.push(col); 9754 9755 if (c < nc - 1 || group.hskipBeforeAndAfter) { 9756 sepwidth = utils.deflt(colDescr.postgap, arraycolsep); 9757 9758 if (sepwidth !== 0) { 9759 colSep = buildCommon.makeSpan(["arraycolsep"], []); 9760 colSep.style.width = sepwidth + "em"; 9761 cols.push(colSep); 9762 } 9763 } 9764 } 9765 9766 body = buildCommon.makeSpan(["mtable"], cols); // Add \hline(s), if any. 9767 9768 if (hlines.length > 0) { 9769 const line = buildCommon.makeLineSpan("hline", options, ruleThickness); 9770 const dashes = buildCommon.makeLineSpan("hdashline", options, ruleThickness); 9771 const vListElems = [{ 9772 type: "elem", 9773 elem: body, 9774 shift: 0 9775 }]; 9776 9777 while (hlines.length > 0) { 9778 const hline = hlines.pop(); 9779 const lineShift = hline.pos - offset; 9780 9781 if (hline.isDashed) { 9782 vListElems.push({ 9783 type: "elem", 9784 elem: dashes, 9785 shift: lineShift 9786 }); 9787 } else { 9788 vListElems.push({ 9789 type: "elem", 9790 elem: line, 9791 shift: lineShift 9792 }); 9793 } 9794 } 9795 9796 body = buildCommon.makeVList({ 9797 positionType: "individualShift", 9798 children: vListElems 9799 }, options); 9800 } 9801 9802 return buildCommon.makeSpan(["mord"], [body], options); 9803}; 9804 9805const alignMap = { 9806 c: "center ", 9807 l: "left ", 9808 r: "right " 9809}; 9810 9811const mathmlBuilder$3 = function mathmlBuilder(group, options) { 9812 let table = new mathMLTree.MathNode("mtable", group.body.map(function (row) { 9813 return new mathMLTree.MathNode("mtr", row.map(function (cell) { 9814 return new mathMLTree.MathNode("mtd", [buildGroup$1(cell, options)]); 9815 })); 9816 })); // Set column alignment, row spacing, column spacing, and 9817 // array lines by setting attributes on the table element. 9818 // Set the row spacing. In MathML, we specify a gap distance. 9819 // We do not use rowGap[] because MathML automatically increases 9820 // cell height with the height/depth of the element content. 9821 // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. 9822 // We simulate this by adding (arraystretch - 1)em to the gap. This 9823 // does a reasonable job of adjusting arrays containing 1 em tall content. 9824 // The 0.16 and 0.09 values are found emprically. They produce an array 9825 // similar to LaTeX and in which content does not interfere with \hines. 9826 9827 const gap = group.arraystretch === 0.5 ? 0.1 // {smallmatrix}, {subarray} 9828 : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); 9829 table.setAttribute("rowspacing", gap + "em"); // MathML table lines go only between cells. 9830 // To place a line on an edge we'll use <menclose>, if necessary. 9831 9832 let menclose = ""; 9833 let align = ""; 9834 9835 if (group.cols) { 9836 // Find column alignment, column spacing, and vertical lines. 9837 const cols = group.cols; 9838 let columnLines = ""; 9839 let prevTypeWasAlign = false; 9840 let iStart = 0; 9841 let iEnd = cols.length; 9842 9843 if (cols[0].type === "separator") { 9844 menclose += "top "; 9845 iStart = 1; 9846 } 9847 9848 if (cols[cols.length - 1].type === "separator") { 9849 menclose += "bottom "; 9850 iEnd -= 1; 9851 } 9852 9853 for (let i = iStart; i < iEnd; i++) { 9854 if (cols[i].type === "align") { 9855 align += alignMap[cols[i].align]; 9856 9857 if (prevTypeWasAlign) { 9858 columnLines += "none "; 9859 } 9860 9861 prevTypeWasAlign = true; 9862 } else if (cols[i].type === "separator") { 9863 // MathML accepts only single lines between cells. 9864 // So we read only the first of consecutive separators. 9865 if (prevTypeWasAlign) { 9866 columnLines += cols[i].separator === "|" ? "solid " : "dashed "; 9867 prevTypeWasAlign = false; 9868 } 9869 } 9870 } 9871 9872 table.setAttribute("columnalign", align.trim()); 9873 9874 if (/[sd]/.test(columnLines)) { 9875 table.setAttribute("columnlines", columnLines.trim()); 9876 } 9877 } // Set column spacing. 9878 9879 9880 if (group.colSeparationType === "align") { 9881 const cols = group.cols || []; 9882 let spacing = ""; 9883 9884 for (let i = 1; i < cols.length; i++) { 9885 spacing += i % 2 ? "0em " : "1em "; 9886 } 9887 9888 table.setAttribute("columnspacing", spacing.trim()); 9889 } else if (group.colSeparationType === "alignat") { 9890 table.setAttribute("columnspacing", "0em"); 9891 } else if (group.colSeparationType === "small") { 9892 table.setAttribute("columnspacing", "0.2778em"); 9893 } else { 9894 table.setAttribute("columnspacing", "1em"); 9895 } // Address \hline and \hdashline 9896 9897 9898 let rowLines = ""; 9899 const hlines = group.hLinesBeforeRow; 9900 menclose += hlines[0].length > 0 ? "left " : ""; 9901 menclose += hlines[hlines.length - 1].length > 0 ? "right " : ""; 9902 9903 for (let i = 1; i < hlines.length - 1; i++) { 9904 rowLines += hlines[i].length === 0 ? "none " // MathML accepts only a single line between rows. Read one element. 9905 : hlines[i][0] ? "dashed " : "solid "; 9906 } 9907 9908 if (/[sd]/.test(rowLines)) { 9909 table.setAttribute("rowlines", rowLines.trim()); 9910 } 9911 9912 if (menclose !== "") { 9913 table = new mathMLTree.MathNode("menclose", [table]); 9914 table.setAttribute("notation", menclose.trim()); 9915 } 9916 9917 if (group.arraystretch && group.arraystretch < 1) { 9918 // A small array. Wrap in scriptstyle so row gap is not too large. 9919 table = new mathMLTree.MathNode("mstyle", [table]); 9920 table.setAttribute("scriptlevel", "1"); 9921 } 9922 9923 return table; 9924}; // Convenience function for aligned and alignedat environments. 9925 9926 9927const alignedHandler = function alignedHandler(context, args) { 9928 const cols = []; 9929 const res = parseArray(context.parser, { 9930 cols, 9931 addJot: true 9932 }, "display"); // Determining number of columns. 9933 // 1. If the first argument is given, we use it as a number of columns, 9934 // and makes sure that each row doesn't exceed that number. 9935 // 2. Otherwise, just count number of columns = maximum number 9936 // of cells in each row ("aligned" mode -- isAligned will be true). 9937 // 9938 // At the same time, prepend empty group {} at beginning of every second 9939 // cell in each row (starting with second cell) so that operators become 9940 // binary. This behavior is implemented in amsmath's \start@aligned. 9941 9942 let numMaths; 9943 let numCols = 0; 9944 const emptyGroup = { 9945 type: "ordgroup", 9946 mode: context.mode, 9947 body: [] 9948 }; 9949 const ordgroup = checkNodeType(args[0], "ordgroup"); 9950 9951 if (ordgroup) { 9952 let arg0 = ""; 9953 9954 for (let i = 0; i < ordgroup.body.length; i++) { 9955 const textord = assertNodeType(ordgroup.body[i], "textord"); 9956 arg0 += textord.text; 9957 } 9958 9959 numMaths = Number(arg0); 9960 numCols = numMaths * 2; 9961 } 9962 9963 const isAligned = !numCols; 9964 res.body.forEach(function (row) { 9965 for (let i = 1; i < row.length; i += 2) { 9966 // Modify ordgroup node within styling node 9967 const styling = assertNodeType(row[i], "styling"); 9968 const ordgroup = assertNodeType(styling.body[0], "ordgroup"); 9969 ordgroup.body.unshift(emptyGroup); 9970 } 9971 9972 if (!isAligned) { 9973 // Case 1 9974 const curMaths = row.length / 2; 9975 9976 if (numMaths < curMaths) { 9977 throw new ParseError("Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, row[0]); 9978 } 9979 } else if (numCols < row.length) { 9980 // Case 2 9981 numCols = row.length; 9982 } 9983 }); // Adjusting alignment. 9984 // In aligned mode, we add one \qquad between columns; 9985 // otherwise we add nothing. 9986 9987 for (let i = 0; i < numCols; ++i) { 9988 let align = "r"; 9989 let pregap = 0; 9990 9991 if (i % 2 === 1) { 9992 align = "l"; 9993 } else if (i > 0 && isAligned) { 9994 // "aligned" mode. 9995 pregap = 1; // add one \quad 9996 } 9997 9998 cols[i] = { 9999 type: "align", 10000 align: align, 10001 pregap: pregap, 10002 postgap: 0 10003 }; 10004 } 10005 10006 res.colSeparationType = isAligned ? "align" : "alignat"; 10007 return res; 10008}; // Arrays are part of LaTeX, defined in lttab.dtx so its documentation 10009// is part of the source2e.pdf file of LaTeX2e source documentation. 10010// {darray} is an {array} environment where cells are set in \displaystyle, 10011// as defined in nccmath.sty. 10012 10013 10014defineEnvironment({ 10015 type: "array", 10016 names: ["array", "darray"], 10017 props: { 10018 numArgs: 1 10019 }, 10020 10021 handler(context, args) { 10022 // Since no types are specified above, the two possibilities are 10023 // - The argument is wrapped in {} or [], in which case Parser's 10024 // parseGroup() returns an "ordgroup" wrapping some symbol node. 10025 // - The argument is a bare symbol node. 10026 const symNode = checkSymbolNodeType(args[0]); 10027 const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; 10028 const cols = colalign.map(function (nde) { 10029 const node = assertSymbolNodeType(nde); 10030 const ca = node.text; 10031 10032 if ("lcr".indexOf(ca) !== -1) { 10033 return { 10034 type: "align", 10035 align: ca 10036 }; 10037 } else if (ca === "|") { 10038 return { 10039 type: "separator", 10040 separator: "|" 10041 }; 10042 } else if (ca === ":") { 10043 return { 10044 type: "separator", 10045 separator: ":" 10046 }; 10047 } 10048 10049 throw new ParseError("Unknown column alignment: " + ca, nde); 10050 }); 10051 const res = { 10052 cols, 10053 hskipBeforeAndAfter: true // \@preamble in lttab.dtx 10054 10055 }; 10056 return parseArray(context.parser, res, dCellStyle(context.envName)); 10057 }, 10058 10059 htmlBuilder: htmlBuilder$3, 10060 mathmlBuilder: mathmlBuilder$3 10061}); // The matrix environments of amsmath builds on the array environment 10062// of LaTeX, which is discussed above. 10063 10064defineEnvironment({ 10065 type: "array", 10066 names: ["matrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"], 10067 props: { 10068 numArgs: 0 10069 }, 10070 10071 handler(context) { 10072 const delimiters = { 10073 "matrix": null, 10074 "pmatrix": ["(", ")"], 10075 "bmatrix": ["[", "]"], 10076 "Bmatrix": ["\\{", "\\}"], 10077 "vmatrix": ["|", "|"], 10078 "Vmatrix": ["\\Vert", "\\Vert"] 10079 }[context.envName]; // \hskip -\arraycolsep in amsmath 10080 10081 const payload = { 10082 hskipBeforeAndAfter: false 10083 }; 10084 const res = parseArray(context.parser, payload, dCellStyle(context.envName)); 10085 return delimiters ? { 10086 type: "leftright", 10087 mode: context.mode, 10088 body: [res], 10089 left: delimiters[0], 10090 right: delimiters[1], 10091 rightColor: undefined // \right uninfluenced by \color in array 10092 10093 } : res; 10094 }, 10095 10096 htmlBuilder: htmlBuilder$3, 10097 mathmlBuilder: mathmlBuilder$3 10098}); 10099defineEnvironment({ 10100 type: "array", 10101 names: ["smallmatrix"], 10102 props: { 10103 numArgs: 0 10104 }, 10105 10106 handler(context) { 10107 const payload = { 10108 arraystretch: 0.5 10109 }; 10110 const res = parseArray(context.parser, payload, "script"); 10111 res.colSeparationType = "small"; 10112 return res; 10113 }, 10114 10115 htmlBuilder: htmlBuilder$3, 10116 mathmlBuilder: mathmlBuilder$3 10117}); 10118defineEnvironment({ 10119 type: "array", 10120 names: ["subarray"], 10121 props: { 10122 numArgs: 1 10123 }, 10124 10125 handler(context, args) { 10126 // Parsing of {subarray} is similar to {array} 10127 const symNode = checkSymbolNodeType(args[0]); 10128 const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; 10129 const cols = colalign.map(function (nde) { 10130 const node = assertSymbolNodeType(nde); 10131 const ca = node.text; // {subarray} only recognizes "l" & "c" 10132 10133 if ("lc".indexOf(ca) !== -1) { 10134 return { 10135 type: "align", 10136 align: ca 10137 }; 10138 } 10139 10140 throw new ParseError("Unknown column alignment: " + ca, nde); 10141 }); 10142 10143 if (cols.length > 1) { 10144 throw new ParseError("{subarray} can contain only one column"); 10145 } 10146 10147 let res = { 10148 cols, 10149 hskipBeforeAndAfter: false, 10150 arraystretch: 0.5 10151 }; 10152 res = parseArray(context.parser, res, "script"); 10153 10154 if (res.body[0].length > 1) { 10155 throw new ParseError("{subarray} can contain only one column"); 10156 } 10157 10158 return res; 10159 }, 10160 10161 htmlBuilder: htmlBuilder$3, 10162 mathmlBuilder: mathmlBuilder$3 10163}); // A cases environment (in amsmath.sty) is almost equivalent to 10164// \def\arraystretch{1.2}% 10165// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. 10166// {dcases} is a {cases} environment where cells are set in \displaystyle, 10167// as defined in mathtools.sty. 10168 10169defineEnvironment({ 10170 type: "array", 10171 names: ["cases", "dcases"], 10172 props: { 10173 numArgs: 0 10174 }, 10175 10176 handler(context) { 10177 const payload = { 10178 arraystretch: 1.2, 10179 cols: [{ 10180 type: "align", 10181 align: "l", 10182 pregap: 0, 10183 // TODO(kevinb) get the current style. 10184 // For now we use the metrics for TEXT style which is what we were 10185 // doing before. Before attempting to get the current style we 10186 // should look at TeX's behavior especially for \over and matrices. 10187 postgap: 1.0 10188 /* 1em quad */ 10189 10190 }, { 10191 type: "align", 10192 align: "l", 10193 pregap: 0, 10194 postgap: 0 10195 }] 10196 }; 10197 const res = parseArray(context.parser, payload, dCellStyle(context.envName)); 10198 return { 10199 type: "leftright", 10200 mode: context.mode, 10201 body: [res], 10202 left: "\\{", 10203 right: ".", 10204 rightColor: undefined 10205 }; 10206 }, 10207 10208 htmlBuilder: htmlBuilder$3, 10209 mathmlBuilder: mathmlBuilder$3 10210}); // An aligned environment is like the align* environment 10211// except it operates within math mode. 10212// Note that we assume \nomallineskiplimit to be zero, 10213// so that \strut@ is the same as \strut. 10214 10215defineEnvironment({ 10216 type: "array", 10217 names: ["aligned"], 10218 props: { 10219 numArgs: 0 10220 }, 10221 handler: alignedHandler, 10222 htmlBuilder: htmlBuilder$3, 10223 mathmlBuilder: mathmlBuilder$3 10224}); // A gathered environment is like an array environment with one centered 10225// column, but where rows are considered lines so get \jot line spacing 10226// and contents are set in \displaystyle. 10227 10228defineEnvironment({ 10229 type: "array", 10230 names: ["gathered"], 10231 props: { 10232 numArgs: 0 10233 }, 10234 10235 handler(context) { 10236 const res = { 10237 cols: [{ 10238 type: "align", 10239 align: "c" 10240 }], 10241 addJot: true 10242 }; 10243 return parseArray(context.parser, res, "display"); 10244 }, 10245 10246 htmlBuilder: htmlBuilder$3, 10247 mathmlBuilder: mathmlBuilder$3 10248}); // alignat environment is like an align environment, but one must explicitly 10249// specify maximum number of columns in each row, and can adjust spacing between 10250// each columns. 10251 10252defineEnvironment({ 10253 type: "array", 10254 names: ["alignedat"], 10255 // One for numbered and for unnumbered; 10256 // but, KaTeX doesn't supports math numbering yet, 10257 // they make no difference for now. 10258 props: { 10259 numArgs: 1 10260 }, 10261 handler: alignedHandler, 10262 htmlBuilder: htmlBuilder$3, 10263 mathmlBuilder: mathmlBuilder$3 10264}); // Catch \hline outside array environment 10265 10266defineFunction({ 10267 type: "text", 10268 // Doesn't matter what this is. 10269 names: ["\\hline", "\\hdashline"], 10270 props: { 10271 numArgs: 0, 10272 allowedInText: true, 10273 allowedInMath: true 10274 }, 10275 10276 handler(context, args) { 10277 throw new ParseError(`${context.funcName} valid only within array environment`); 10278 } 10279 10280}); 10281 10282const environments = _environments; 10283 10284// defineEnvironment definitions. 10285// $FlowFixMe, "environment" handler returns an environment ParseNode 10286 10287defineFunction({ 10288 type: "environment", 10289 names: ["\\begin", "\\end"], 10290 props: { 10291 numArgs: 1, 10292 argTypes: ["text"] 10293 }, 10294 10295 handler(_ref, args) { 10296 let parser = _ref.parser, 10297 funcName = _ref.funcName; 10298 const nameGroup = args[0]; 10299 10300 if (nameGroup.type !== "ordgroup") { 10301 throw new ParseError("Invalid environment name", nameGroup); 10302 } 10303 10304 let envName = ""; 10305 10306 for (let i = 0; i < nameGroup.body.length; ++i) { 10307 envName += assertNodeType(nameGroup.body[i], "textord").text; 10308 } 10309 10310 if (funcName === "\\begin") { 10311 // begin...end is similar to left...right 10312 if (!environments.hasOwnProperty(envName)) { 10313 throw new ParseError("No such environment: " + envName, nameGroup); 10314 } // Build the environment object. Arguments and other information will 10315 // be made available to the begin and end methods using properties. 10316 10317 10318 const env = environments[envName]; 10319 10320 const _parser$parseArgument = parser.parseArguments("\\begin{" + envName + "}", env), 10321 args = _parser$parseArgument.args, 10322 optArgs = _parser$parseArgument.optArgs; 10323 10324 const context = { 10325 mode: parser.mode, 10326 envName, 10327 parser 10328 }; 10329 const result = env.handler(context, args, optArgs); 10330 parser.expect("\\end", false); 10331 const endNameToken = parser.nextToken; 10332 const end = assertNodeType(parser.parseFunction(), "environment"); 10333 10334 if (end.name !== envName) { 10335 throw new ParseError(`Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, endNameToken); 10336 } 10337 10338 return result; 10339 } 10340 10341 return { 10342 type: "environment", 10343 mode: parser.mode, 10344 name: envName, 10345 nameGroup 10346 }; 10347 } 10348 10349}); 10350 10351const makeSpan$2 = buildCommon.makeSpan; 10352 10353function htmlBuilder$4(group, options) { 10354 const elements = buildExpression(group.body, options, true); 10355 return makeSpan$2([group.mclass], elements, options); 10356} 10357 10358function mathmlBuilder$4(group, options) { 10359 let node; 10360 const inner = buildExpression$1(group.body, options); 10361 10362 if (group.mclass === "minner") { 10363 return mathMLTree.newDocumentFragment(inner); 10364 } else if (group.mclass === "mord") { 10365 if (group.isCharacterBox) { 10366 node = inner[0]; 10367 node.type = "mi"; 10368 } else { 10369 node = new mathMLTree.MathNode("mi", inner); 10370 } 10371 } else { 10372 if (group.isCharacterBox) { 10373 node = inner[0]; 10374 node.type = "mo"; 10375 } else { 10376 node = new mathMLTree.MathNode("mo", inner); 10377 } // Set spacing based on what is the most likely adjacent atom type. 10378 // See TeXbook p170. 10379 10380 10381 if (group.mclass === "mbin") { 10382 node.attributes.lspace = "0.22em"; // medium space 10383 10384 node.attributes.rspace = "0.22em"; 10385 } else if (group.mclass === "mpunct") { 10386 node.attributes.lspace = "0em"; 10387 node.attributes.rspace = "0.17em"; // thinspace 10388 } else if (group.mclass === "mopen" || group.mclass === "mclose") { 10389 node.attributes.lspace = "0em"; 10390 node.attributes.rspace = "0em"; 10391 } // MathML <mo> default space is 5/18 em, so <mrel> needs no action. 10392 // Ref: https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo 10393 10394 } 10395 10396 return node; 10397} // Math class commands except \mathop 10398 10399 10400defineFunction({ 10401 type: "mclass", 10402 names: ["\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", "\\mathclose", "\\mathpunct", "\\mathinner"], 10403 props: { 10404 numArgs: 1 10405 }, 10406 10407 handler(_ref, args) { 10408 let parser = _ref.parser, 10409 funcName = _ref.funcName; 10410 const body = args[0]; 10411 return { 10412 type: "mclass", 10413 mode: parser.mode, 10414 mclass: "m" + funcName.substr(5), 10415 // TODO(kevinb): don't prefix with 'm' 10416 body: ordargument(body), 10417 isCharacterBox: utils.isCharacterBox(body) 10418 }; 10419 }, 10420 10421 htmlBuilder: htmlBuilder$4, 10422 mathmlBuilder: mathmlBuilder$4 10423}); 10424const binrelClass = arg => { 10425 // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. 10426 // (by rendering separately and with {}s before and after, and measuring 10427 // the change in spacing). We'll do roughly the same by detecting the 10428 // atom type directly. 10429 const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; 10430 10431 if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { 10432 return "m" + atom.family; 10433 } else { 10434 return "mord"; 10435 } 10436}; // \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. 10437// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. 10438 10439defineFunction({ 10440 type: "mclass", 10441 names: ["\\@binrel"], 10442 props: { 10443 numArgs: 2 10444 }, 10445 10446 handler(_ref2, args) { 10447 let parser = _ref2.parser; 10448 return { 10449 type: "mclass", 10450 mode: parser.mode, 10451 mclass: binrelClass(args[0]), 10452 body: [args[1]], 10453 isCharacterBox: utils.isCharacterBox(args[1]) 10454 }; 10455 } 10456 10457}); // Build a relation or stacked op by placing one symbol on top of another 10458 10459defineFunction({ 10460 type: "mclass", 10461 names: ["\\stackrel", "\\overset", "\\underset"], 10462 props: { 10463 numArgs: 2 10464 }, 10465 10466 handler(_ref3, args) { 10467 let parser = _ref3.parser, 10468 funcName = _ref3.funcName; 10469 const baseArg = args[1]; 10470 const shiftedArg = args[0]; 10471 let mclass; 10472 10473 if (funcName !== "\\stackrel") { 10474 // LaTeX applies \binrel spacing to \overset and \underset. 10475 mclass = binrelClass(baseArg); 10476 } else { 10477 mclass = "mrel"; // for \stackrel 10478 } 10479 10480 const baseOp = { 10481 type: "op", 10482 mode: baseArg.mode, 10483 limits: true, 10484 alwaysHandleSupSub: true, 10485 parentIsSupSub: false, 10486 symbol: false, 10487 suppressBaseShift: funcName !== "\\stackrel", 10488 body: ordargument(baseArg) 10489 }; 10490 const supsub = { 10491 type: "supsub", 10492 mode: shiftedArg.mode, 10493 base: baseOp, 10494 sup: funcName === "\\underset" ? null : shiftedArg, 10495 sub: funcName === "\\underset" ? shiftedArg : null 10496 }; 10497 return { 10498 type: "mclass", 10499 mode: parser.mode, 10500 mclass, 10501 body: [supsub], 10502 isCharacterBox: utils.isCharacterBox(supsub) 10503 }; 10504 }, 10505 10506 htmlBuilder: htmlBuilder$4, 10507 mathmlBuilder: mathmlBuilder$4 10508}); 10509 10510// TODO(kevinb): implement \\sl and \\sc 10511 10512const htmlBuilder$5 = (group, options) => { 10513 const font = group.font; 10514 const newOptions = options.withFont(font); 10515 return buildGroup(group.body, newOptions); 10516}; 10517 10518const mathmlBuilder$5 = (group, options) => { 10519 const font = group.font; 10520 const newOptions = options.withFont(font); 10521 return buildGroup$1(group.body, newOptions); 10522}; 10523 10524const fontAliases = { 10525 "\\Bbb": "\\mathbb", 10526 "\\bold": "\\mathbf", 10527 "\\frak": "\\mathfrak", 10528 "\\bm": "\\boldsymbol" 10529}; 10530defineFunction({ 10531 type: "font", 10532 names: [// styles, except \boldsymbol defined below 10533 "\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal", // families 10534 "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf", "\\mathtt", // aliases, except \bm defined below 10535 "\\Bbb", "\\bold", "\\frak"], 10536 props: { 10537 numArgs: 1, 10538 greediness: 2 10539 }, 10540 handler: (_ref, args) => { 10541 let parser = _ref.parser, 10542 funcName = _ref.funcName; 10543 const body = args[0]; 10544 let func = funcName; 10545 10546 if (func in fontAliases) { 10547 func = fontAliases[func]; 10548 } 10549 10550 return { 10551 type: "font", 10552 mode: parser.mode, 10553 font: func.slice(1), 10554 body 10555 }; 10556 }, 10557 htmlBuilder: htmlBuilder$5, 10558 mathmlBuilder: mathmlBuilder$5 10559}); 10560defineFunction({ 10561 type: "mclass", 10562 names: ["\\boldsymbol", "\\bm"], 10563 props: { 10564 numArgs: 1, 10565 greediness: 2 10566 }, 10567 handler: (_ref2, args) => { 10568 let parser = _ref2.parser; 10569 const body = args[0]; 10570 const isCharacterBox = utils.isCharacterBox(body); // amsbsy.sty's \boldsymbol uses \binrel spacing to inherit the 10571 // argument's bin|rel|ord status 10572 10573 return { 10574 type: "mclass", 10575 mode: parser.mode, 10576 mclass: binrelClass(body), 10577 body: [{ 10578 type: "font", 10579 mode: parser.mode, 10580 font: "boldsymbol", 10581 body 10582 }], 10583 isCharacterBox: isCharacterBox 10584 }; 10585 } 10586}); // Old font changing functions 10587 10588defineFunction({ 10589 type: "font", 10590 names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it"], 10591 props: { 10592 numArgs: 0, 10593 allowedInText: true 10594 }, 10595 handler: (_ref3, args) => { 10596 let parser = _ref3.parser, 10597 funcName = _ref3.funcName, 10598 breakOnTokenText = _ref3.breakOnTokenText; 10599 const mode = parser.mode; 10600 const body = parser.parseExpression(true, breakOnTokenText); 10601 const style = `math${funcName.slice(1)}`; 10602 return { 10603 type: "font", 10604 mode: mode, 10605 font: style, 10606 body: { 10607 type: "ordgroup", 10608 mode: parser.mode, 10609 body 10610 } 10611 }; 10612 }, 10613 htmlBuilder: htmlBuilder$5, 10614 mathmlBuilder: mathmlBuilder$5 10615}); 10616 10617const adjustStyle = (size, originalStyle) => { 10618 // Figure out what style this fraction should be in based on the 10619 // function used 10620 let style = originalStyle; 10621 10622 if (size === "display") { 10623 // Get display style as a default. 10624 // If incoming style is sub/sup, use style.text() to get correct size. 10625 style = style.id >= Style$1.SCRIPT.id ? style.text() : Style$1.DISPLAY; 10626 } else if (size === "text" && style.size === Style$1.DISPLAY.size) { 10627 // We're in a \tfrac but incoming style is displaystyle, so: 10628 style = Style$1.TEXT; 10629 } else if (size === "script") { 10630 style = Style$1.SCRIPT; 10631 } else if (size === "scriptscript") { 10632 style = Style$1.SCRIPTSCRIPT; 10633 } 10634 10635 return style; 10636}; 10637 10638const htmlBuilder$6 = (group, options) => { 10639 // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e). 10640 const style = adjustStyle(group.size, options.style); 10641 const nstyle = style.fracNum(); 10642 const dstyle = style.fracDen(); 10643 let newOptions; 10644 newOptions = options.havingStyle(nstyle); 10645 const numerm = buildGroup(group.numer, newOptions, options); 10646 10647 if (group.continued) { 10648 // \cfrac inserts a \strut into the numerator. 10649 // Get \strut dimensions from TeXbook page 353. 10650 const hStrut = 8.5 / options.fontMetrics().ptPerEm; 10651 const dStrut = 3.5 / options.fontMetrics().ptPerEm; 10652 numerm.height = numerm.height < hStrut ? hStrut : numerm.height; 10653 numerm.depth = numerm.depth < dStrut ? dStrut : numerm.depth; 10654 } 10655 10656 newOptions = options.havingStyle(dstyle); 10657 const denomm = buildGroup(group.denom, newOptions, options); 10658 let rule; 10659 let ruleWidth; 10660 let ruleSpacing; 10661 10662 if (group.hasBarLine) { 10663 if (group.barSize) { 10664 ruleWidth = calculateSize(group.barSize, options); 10665 rule = buildCommon.makeLineSpan("frac-line", options, ruleWidth); 10666 } else { 10667 rule = buildCommon.makeLineSpan("frac-line", options); 10668 } 10669 10670 ruleWidth = rule.height; 10671 ruleSpacing = rule.height; 10672 } else { 10673 rule = null; 10674 ruleWidth = 0; 10675 ruleSpacing = options.fontMetrics().defaultRuleThickness; 10676 } // Rule 15b 10677 10678 10679 let numShift; 10680 let clearance; 10681 let denomShift; 10682 10683 if (style.size === Style$1.DISPLAY.size || group.size === "display") { 10684 numShift = options.fontMetrics().num1; 10685 10686 if (ruleWidth > 0) { 10687 clearance = 3 * ruleSpacing; 10688 } else { 10689 clearance = 7 * ruleSpacing; 10690 } 10691 10692 denomShift = options.fontMetrics().denom1; 10693 } else { 10694 if (ruleWidth > 0) { 10695 numShift = options.fontMetrics().num2; 10696 clearance = ruleSpacing; 10697 } else { 10698 numShift = options.fontMetrics().num3; 10699 clearance = 3 * ruleSpacing; 10700 } 10701 10702 denomShift = options.fontMetrics().denom2; 10703 } 10704 10705 let frac; 10706 10707 if (!rule) { 10708 // Rule 15c 10709 const candidateClearance = numShift - numerm.depth - (denomm.height - denomShift); 10710 10711 if (candidateClearance < clearance) { 10712 numShift += 0.5 * (clearance - candidateClearance); 10713 denomShift += 0.5 * (clearance - candidateClearance); 10714 } 10715 10716 frac = buildCommon.makeVList({ 10717 positionType: "individualShift", 10718 children: [{ 10719 type: "elem", 10720 elem: denomm, 10721 shift: denomShift 10722 }, { 10723 type: "elem", 10724 elem: numerm, 10725 shift: -numShift 10726 }] 10727 }, options); 10728 } else { 10729 // Rule 15d 10730 const axisHeight = options.fontMetrics().axisHeight; 10731 10732 if (numShift - numerm.depth - (axisHeight + 0.5 * ruleWidth) < clearance) { 10733 numShift += clearance - (numShift - numerm.depth - (axisHeight + 0.5 * ruleWidth)); 10734 } 10735 10736 if (axisHeight - 0.5 * ruleWidth - (denomm.height - denomShift) < clearance) { 10737 denomShift += clearance - (axisHeight - 0.5 * ruleWidth - (denomm.height - denomShift)); 10738 } 10739 10740 const midShift = -(axisHeight - 0.5 * ruleWidth); 10741 frac = buildCommon.makeVList({ 10742 positionType: "individualShift", 10743 children: [{ 10744 type: "elem", 10745 elem: denomm, 10746 shift: denomShift 10747 }, { 10748 type: "elem", 10749 elem: rule, 10750 shift: midShift 10751 }, { 10752 type: "elem", 10753 elem: numerm, 10754 shift: -numShift 10755 }] 10756 }, options); 10757 } // Since we manually change the style sometimes (with \dfrac or \tfrac), 10758 // account for the possible size change here. 10759 10760 10761 newOptions = options.havingStyle(style); 10762 frac.height *= newOptions.sizeMultiplier / options.sizeMultiplier; 10763 frac.depth *= newOptions.sizeMultiplier / options.sizeMultiplier; // Rule 15e 10764 10765 let delimSize; 10766 10767 if (style.size === Style$1.DISPLAY.size) { 10768 delimSize = options.fontMetrics().delim1; 10769 } else { 10770 delimSize = options.fontMetrics().delim2; 10771 } 10772 10773 let leftDelim; 10774 let rightDelim; 10775 10776 if (group.leftDelim == null) { 10777 leftDelim = makeNullDelimiter(options, ["mopen"]); 10778 } else { 10779 leftDelim = delimiter.customSizedDelim(group.leftDelim, delimSize, true, options.havingStyle(style), group.mode, ["mopen"]); 10780 } 10781 10782 if (group.continued) { 10783 rightDelim = buildCommon.makeSpan([]); // zero width for \cfrac 10784 } else if (group.rightDelim == null) { 10785 rightDelim = makeNullDelimiter(options, ["mclose"]); 10786 } else { 10787 rightDelim = delimiter.customSizedDelim(group.rightDelim, delimSize, true, options.havingStyle(style), group.mode, ["mclose"]); 10788 } 10789 10790 return buildCommon.makeSpan(["mord"].concat(newOptions.sizingClasses(options)), [leftDelim, buildCommon.makeSpan(["mfrac"], [frac]), rightDelim], options); 10791}; 10792 10793const mathmlBuilder$6 = (group, options) => { 10794 let node = new mathMLTree.MathNode("mfrac", [buildGroup$1(group.numer, options), buildGroup$1(group.denom, options)]); 10795 10796 if (!group.hasBarLine) { 10797 node.setAttribute("linethickness", "0px"); 10798 } else if (group.barSize) { 10799 const ruleWidth = calculateSize(group.barSize, options); 10800 node.setAttribute("linethickness", ruleWidth + "em"); 10801 } 10802 10803 const style = adjustStyle(group.size, options.style); 10804 10805 if (style.size !== options.style.size) { 10806 node = new mathMLTree.MathNode("mstyle", [node]); 10807 const isDisplay = style.size === Style$1.DISPLAY.size ? "true" : "false"; 10808 node.setAttribute("displaystyle", isDisplay); 10809 node.setAttribute("scriptlevel", "0"); 10810 } 10811 10812 if (group.leftDelim != null || group.rightDelim != null) { 10813 const withDelims = []; 10814 10815 if (group.leftDelim != null) { 10816 const leftOp = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(group.leftDelim.replace("\\", ""))]); 10817 leftOp.setAttribute("fence", "true"); 10818 withDelims.push(leftOp); 10819 } 10820 10821 withDelims.push(node); 10822 10823 if (group.rightDelim != null) { 10824 const rightOp = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(group.rightDelim.replace("\\", ""))]); 10825 rightOp.setAttribute("fence", "true"); 10826 withDelims.push(rightOp); 10827 } 10828 10829 return makeRow(withDelims); 10830 } 10831 10832 return node; 10833}; 10834 10835defineFunction({ 10836 type: "genfrac", 10837 names: ["\\cfrac", "\\dfrac", "\\frac", "\\tfrac", "\\dbinom", "\\binom", "\\tbinom", "\\\\atopfrac", // can’t be entered directly 10838 "\\\\bracefrac", "\\\\brackfrac"], 10839 props: { 10840 numArgs: 2, 10841 greediness: 2 10842 }, 10843 handler: (_ref, args) => { 10844 let parser = _ref.parser, 10845 funcName = _ref.funcName; 10846 const numer = args[0]; 10847 const denom = args[1]; 10848 let hasBarLine; 10849 let leftDelim = null; 10850 let rightDelim = null; 10851 let size = "auto"; 10852 10853 switch (funcName) { 10854 case "\\cfrac": 10855 case "\\dfrac": 10856 case "\\frac": 10857 case "\\tfrac": 10858 hasBarLine = true; 10859 break; 10860 10861 case "\\\\atopfrac": 10862 hasBarLine = false; 10863 break; 10864 10865 case "\\dbinom": 10866 case "\\binom": 10867 case "\\tbinom": 10868 hasBarLine = false; 10869 leftDelim = "("; 10870 rightDelim = ")"; 10871 break; 10872 10873 case "\\\\bracefrac": 10874 hasBarLine = false; 10875 leftDelim = "\\{"; 10876 rightDelim = "\\}"; 10877 break; 10878 10879 case "\\\\brackfrac": 10880 hasBarLine = false; 10881 leftDelim = "["; 10882 rightDelim = "]"; 10883 break; 10884 10885 default: 10886 throw new Error("Unrecognized genfrac command"); 10887 } 10888 10889 switch (funcName) { 10890 case "\\cfrac": 10891 case "\\dfrac": 10892 case "\\dbinom": 10893 size = "display"; 10894 break; 10895 10896 case "\\tfrac": 10897 case "\\tbinom": 10898 size = "text"; 10899 break; 10900 } 10901 10902 return { 10903 type: "genfrac", 10904 mode: parser.mode, 10905 continued: funcName === "\\cfrac", 10906 numer, 10907 denom, 10908 hasBarLine, 10909 leftDelim, 10910 rightDelim, 10911 size, 10912 barSize: null 10913 }; 10914 }, 10915 htmlBuilder: htmlBuilder$6, 10916 mathmlBuilder: mathmlBuilder$6 10917}); // Infix generalized fractions -- these are not rendered directly, but replaced 10918// immediately by one of the variants above. 10919 10920defineFunction({ 10921 type: "infix", 10922 names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], 10923 props: { 10924 numArgs: 0, 10925 infix: true 10926 }, 10927 10928 handler(_ref2) { 10929 let parser = _ref2.parser, 10930 funcName = _ref2.funcName, 10931 token = _ref2.token; 10932 let replaceWith; 10933 10934 switch (funcName) { 10935 case "\\over": 10936 replaceWith = "\\frac"; 10937 break; 10938 10939 case "\\choose": 10940 replaceWith = "\\binom"; 10941 break; 10942 10943 case "\\atop": 10944 replaceWith = "\\\\atopfrac"; 10945 break; 10946 10947 case "\\brace": 10948 replaceWith = "\\\\bracefrac"; 10949 break; 10950 10951 case "\\brack": 10952 replaceWith = "\\\\brackfrac"; 10953 break; 10954 10955 default: 10956 throw new Error("Unrecognized infix genfrac command"); 10957 } 10958 10959 return { 10960 type: "infix", 10961 mode: parser.mode, 10962 replaceWith, 10963 token 10964 }; 10965 } 10966 10967}); 10968const stylArray = ["display", "text", "script", "scriptscript"]; 10969 10970const delimFromValue = function delimFromValue(delimString) { 10971 let delim = null; 10972 10973 if (delimString.length > 0) { 10974 delim = delimString; 10975 delim = delim === "." ? null : delim; 10976 } 10977 10978 return delim; 10979}; 10980 10981defineFunction({ 10982 type: "genfrac", 10983 names: ["\\genfrac"], 10984 props: { 10985 numArgs: 6, 10986 greediness: 6, 10987 argTypes: ["math", "math", "size", "text", "math", "math"] 10988 }, 10989 10990 handler(_ref3, args) { 10991 let parser = _ref3.parser; 10992 const numer = args[4]; 10993 const denom = args[5]; // Look into the parse nodes to get the desired delimiters. 10994 10995 let leftNode = checkNodeType(args[0], "atom"); 10996 10997 if (leftNode) { 10998 leftNode = assertAtomFamily(args[0], "open"); 10999 } 11000 11001 const leftDelim = leftNode ? delimFromValue(leftNode.text) : null; 11002 let rightNode = checkNodeType(args[1], "atom"); 11003 11004 if (rightNode) { 11005 rightNode = assertAtomFamily(args[1], "close"); 11006 } 11007 11008 const rightDelim = rightNode ? delimFromValue(rightNode.text) : null; 11009 const barNode = assertNodeType(args[2], "size"); 11010 let hasBarLine; 11011 let barSize = null; 11012 11013 if (barNode.isBlank) { 11014 // \genfrac acts differently than \above. 11015 // \genfrac treats an empty size group as a signal to use a 11016 // standard bar size. \above would see size = 0 and omit the bar. 11017 hasBarLine = true; 11018 } else { 11019 barSize = barNode.value; 11020 hasBarLine = barSize.number > 0; 11021 } // Find out if we want displaystyle, textstyle, etc. 11022 11023 11024 let size = "auto"; 11025 let styl = checkNodeType(args[3], "ordgroup"); 11026 11027 if (styl) { 11028 if (styl.body.length > 0) { 11029 const textOrd = assertNodeType(styl.body[0], "textord"); 11030 size = stylArray[Number(textOrd.text)]; 11031 } 11032 } else { 11033 styl = assertNodeType(args[3], "textord"); 11034 size = stylArray[Number(styl.text)]; 11035 } 11036 11037 return { 11038 type: "genfrac", 11039 mode: parser.mode, 11040 numer, 11041 denom, 11042 continued: false, 11043 hasBarLine, 11044 barSize, 11045 leftDelim, 11046 rightDelim, 11047 size 11048 }; 11049 }, 11050 11051 htmlBuilder: htmlBuilder$6, 11052 mathmlBuilder: mathmlBuilder$6 11053}); // \above is an infix fraction that also defines a fraction bar size. 11054 11055defineFunction({ 11056 type: "infix", 11057 names: ["\\above"], 11058 props: { 11059 numArgs: 1, 11060 argTypes: ["size"], 11061 infix: true 11062 }, 11063 11064 handler(_ref4, args) { 11065 let parser = _ref4.parser, 11066 funcName = _ref4.funcName, 11067 token = _ref4.token; 11068 return { 11069 type: "infix", 11070 mode: parser.mode, 11071 replaceWith: "\\\\abovefrac", 11072 size: assertNodeType(args[0], "size").value, 11073 token 11074 }; 11075 } 11076 11077}); 11078defineFunction({ 11079 type: "genfrac", 11080 names: ["\\\\abovefrac"], 11081 props: { 11082 numArgs: 3, 11083 argTypes: ["math", "size", "math"] 11084 }, 11085 handler: (_ref5, args) => { 11086 let parser = _ref5.parser, 11087 funcName = _ref5.funcName; 11088 const numer = args[0]; 11089 const barSize = assert(assertNodeType(args[1], "infix").size); 11090 const denom = args[2]; 11091 const hasBarLine = barSize.number > 0; 11092 return { 11093 type: "genfrac", 11094 mode: parser.mode, 11095 numer, 11096 denom, 11097 continued: false, 11098 hasBarLine, 11099 barSize, 11100 leftDelim: null, 11101 rightDelim: null, 11102 size: "auto" 11103 }; 11104 }, 11105 htmlBuilder: htmlBuilder$6, 11106 mathmlBuilder: mathmlBuilder$6 11107}); 11108 11109// NOTE: Unlike most `htmlBuilder`s, this one handles not only "horizBrace", but 11110const htmlBuilder$7 = (grp, options) => { 11111 const style = options.style; // Pull out the `ParseNode<"horizBrace">` if `grp` is a "supsub" node. 11112 11113 let supSubGroup; 11114 let group; 11115 const supSub = checkNodeType(grp, "supsub"); 11116 11117 if (supSub) { 11118 // Ref: LaTeX source2e: }}}}\limits} 11119 // i.e. LaTeX treats the brace similar to an op and passes it 11120 // with \limits, so we need to assign supsub style. 11121 supSubGroup = supSub.sup ? buildGroup(supSub.sup, options.havingStyle(style.sup()), options) : buildGroup(supSub.sub, options.havingStyle(style.sub()), options); 11122 group = assertNodeType(supSub.base, "horizBrace"); 11123 } else { 11124 group = assertNodeType(grp, "horizBrace"); 11125 } // Build the base group 11126 11127 11128 const body = buildGroup(group.base, options.havingBaseStyle(Style$1.DISPLAY)); // Create the stretchy element 11129 11130 const braceBody = stretchy.svgSpan(group, options); // Generate the vlist, with the appropriate kerns ┏━━━━━━━━┓ 11131 // This first vlist contains the content and the brace: equation 11132 11133 let vlist; 11134 11135 if (group.isOver) { 11136 vlist = buildCommon.makeVList({ 11137 positionType: "firstBaseline", 11138 children: [{ 11139 type: "elem", 11140 elem: body 11141 }, { 11142 type: "kern", 11143 size: 0.1 11144 }, { 11145 type: "elem", 11146 elem: braceBody 11147 }] 11148 }, options); // $FlowFixMe: Replace this with passing "svg-align" into makeVList. 11149 11150 vlist.children[0].children[0].children[1].classes.push("svg-align"); 11151 } else { 11152 vlist = buildCommon.makeVList({ 11153 positionType: "bottom", 11154 positionData: body.depth + 0.1 + braceBody.height, 11155 children: [{ 11156 type: "elem", 11157 elem: braceBody 11158 }, { 11159 type: "kern", 11160 size: 0.1 11161 }, { 11162 type: "elem", 11163 elem: body 11164 }] 11165 }, options); // $FlowFixMe: Replace this with passing "svg-align" into makeVList. 11166 11167 vlist.children[0].children[0].children[0].classes.push("svg-align"); 11168 } 11169 11170 if (supSubGroup) { 11171 // To write the supsub, wrap the first vlist in another vlist: 11172 // They can't all go in the same vlist, because the note might be 11173 // wider than the equation. We want the equation to control the 11174 // brace width. 11175 // note long note long note 11176 // ┏━━━━━━━━┓ or ┏━━━┓ not ┏━━━━━━━━━┓ 11177 // equation eqn eqn 11178 const vSpan = buildCommon.makeSpan(["mord", group.isOver ? "mover" : "munder"], [vlist], options); 11179 11180 if (group.isOver) { 11181 vlist = buildCommon.makeVList({ 11182 positionType: "firstBaseline", 11183 children: [{ 11184 type: "elem", 11185 elem: vSpan 11186 }, { 11187 type: "kern", 11188 size: 0.2 11189 }, { 11190 type: "elem", 11191 elem: supSubGroup 11192 }] 11193 }, options); 11194 } else { 11195 vlist = buildCommon.makeVList({ 11196 positionType: "bottom", 11197 positionData: vSpan.depth + 0.2 + supSubGroup.height + supSubGroup.depth, 11198 children: [{ 11199 type: "elem", 11200 elem: supSubGroup 11201 }, { 11202 type: "kern", 11203 size: 0.2 11204 }, { 11205 type: "elem", 11206 elem: vSpan 11207 }] 11208 }, options); 11209 } 11210 } 11211 11212 return buildCommon.makeSpan(["mord", group.isOver ? "mover" : "munder"], [vlist], options); 11213}; 11214 11215const mathmlBuilder$7 = (group, options) => { 11216 const accentNode = stretchy.mathMLnode(group.label); 11217 return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [buildGroup$1(group.base, options), accentNode]); 11218}; // Horizontal stretchy braces 11219 11220 11221defineFunction({ 11222 type: "horizBrace", 11223 names: ["\\overbrace", "\\underbrace"], 11224 props: { 11225 numArgs: 1 11226 }, 11227 11228 handler(_ref, args) { 11229 let parser = _ref.parser, 11230 funcName = _ref.funcName; 11231 return { 11232 type: "horizBrace", 11233 mode: parser.mode, 11234 label: funcName, 11235 isOver: /^\\over/.test(funcName), 11236 base: args[0] 11237 }; 11238 }, 11239 11240 htmlBuilder: htmlBuilder$7, 11241 mathmlBuilder: mathmlBuilder$7 11242}); 11243 11244defineFunction({ 11245 type: "href", 11246 names: ["\\href"], 11247 props: { 11248 numArgs: 2, 11249 argTypes: ["url", "original"], 11250 allowedInText: true 11251 }, 11252 handler: (_ref, args) => { 11253 let parser = _ref.parser; 11254 const body = args[1]; 11255 const href = assertNodeType(args[0], "url").url; 11256 11257 if (!parser.settings.isTrusted({ 11258 command: "\\href", 11259 url: href 11260 })) { 11261 return parser.formatUnsupportedCmd("\\href"); 11262 } 11263 11264 return { 11265 type: "href", 11266 mode: parser.mode, 11267 href, 11268 body: ordargument(body) 11269 }; 11270 }, 11271 htmlBuilder: (group, options) => { 11272 const elements = buildExpression(group.body, options, false); 11273 return buildCommon.makeAnchor(group.href, [], elements, options); 11274 }, 11275 mathmlBuilder: (group, options) => { 11276 let math = buildExpressionRow(group.body, options); 11277 11278 if (!(math instanceof MathNode)) { 11279 math = new MathNode("mrow", [math]); 11280 } 11281 11282 math.setAttribute("href", group.href); 11283 return math; 11284 } 11285}); 11286defineFunction({ 11287 type: "href", 11288 names: ["\\url"], 11289 props: { 11290 numArgs: 1, 11291 argTypes: ["url"], 11292 allowedInText: true 11293 }, 11294 handler: (_ref2, args) => { 11295 let parser = _ref2.parser; 11296 const href = assertNodeType(args[0], "url").url; 11297 11298 if (!parser.settings.isTrusted({ 11299 command: "\\url", 11300 url: href 11301 })) { 11302 return parser.formatUnsupportedCmd("\\url"); 11303 } 11304 11305 const chars = []; 11306 11307 for (let i = 0; i < href.length; i++) { 11308 let c = href[i]; 11309 11310 if (c === "~") { 11311 c = "\\textasciitilde"; 11312 } 11313 11314 chars.push({ 11315 type: "textord", 11316 mode: "text", 11317 text: c 11318 }); 11319 } 11320 11321 const body = { 11322 type: "text", 11323 mode: parser.mode, 11324 font: "\\texttt", 11325 body: chars 11326 }; 11327 return { 11328 type: "href", 11329 mode: parser.mode, 11330 href, 11331 body: ordargument(body) 11332 }; 11333 } 11334}); 11335 11336defineFunction({ 11337 type: "htmlmathml", 11338 names: ["\\html@mathml"], 11339 props: { 11340 numArgs: 2, 11341 allowedInText: true 11342 }, 11343 handler: (_ref, args) => { 11344 let parser = _ref.parser; 11345 return { 11346 type: "htmlmathml", 11347 mode: parser.mode, 11348 html: ordargument(args[0]), 11349 mathml: ordargument(args[1]) 11350 }; 11351 }, 11352 htmlBuilder: (group, options) => { 11353 const elements = buildExpression(group.html, options, false); 11354 return buildCommon.makeFragment(elements); 11355 }, 11356 mathmlBuilder: (group, options) => { 11357 return buildExpressionRow(group.mathml, options); 11358 } 11359}); 11360 11361const sizeData = function sizeData(str) { 11362 if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { 11363 // str is a number with no unit specified. 11364 // default unit is bp, per graphix package. 11365 return { 11366 number: +str, 11367 unit: "bp" 11368 }; 11369 } else { 11370 const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); 11371 11372 if (!match) { 11373 throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); 11374 } 11375 11376 const data = { 11377 number: +(match[1] + match[2]), 11378 // sign + magnitude, cast to number 11379 unit: match[3] 11380 }; 11381 11382 if (!validUnit(data)) { 11383 throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); 11384 } 11385 11386 return data; 11387 } 11388}; 11389 11390defineFunction({ 11391 type: "includegraphics", 11392 names: ["\\includegraphics"], 11393 props: { 11394 numArgs: 1, 11395 numOptionalArgs: 1, 11396 argTypes: ["raw", "url"], 11397 allowedInText: false 11398 }, 11399 handler: (_ref, args, optArgs) => { 11400 let parser = _ref.parser; 11401 let width = { 11402 number: 0, 11403 unit: "em" 11404 }; 11405 let height = { 11406 number: 0.9, 11407 unit: "em" 11408 }; // sorta character sized. 11409 11410 let totalheight = { 11411 number: 0, 11412 unit: "em" 11413 }; 11414 let alt = ""; 11415 11416 if (optArgs[0]) { 11417 const attributeStr = assertNodeType(optArgs[0], "raw").string; // Parser.js does not parse key/value pairs. We get a string. 11418 11419 const attributes = attributeStr.split(","); 11420 11421 for (let i = 0; i < attributes.length; i++) { 11422 const keyVal = attributes[i].split("="); 11423 11424 if (keyVal.length === 2) { 11425 const str = keyVal[1].trim(); 11426 11427 switch (keyVal[0].trim()) { 11428 case "alt": 11429 alt = str; 11430 break; 11431 11432 case "width": 11433 width = sizeData(str); 11434 break; 11435 11436 case "height": 11437 height = sizeData(str); 11438 break; 11439 11440 case "totalheight": 11441 totalheight = sizeData(str); 11442 break; 11443 11444 default: 11445 throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics."); 11446 } 11447 } 11448 } 11449 } 11450 11451 const src = assertNodeType(args[0], "url").url; 11452 11453 if (alt === "") { 11454 // No alt given. Use the file name. Strip away the path. 11455 alt = src; 11456 alt = alt.replace(/^.*[\\/]/, ''); 11457 alt = alt.substring(0, alt.lastIndexOf('.')); 11458 } 11459 11460 if (!parser.settings.isTrusted({ 11461 command: "\\includegraphics", 11462 url: src 11463 })) { 11464 return parser.formatUnsupportedCmd("\\includegraphics"); 11465 } 11466 11467 return { 11468 type: "includegraphics", 11469 mode: parser.mode, 11470 alt: alt, 11471 width: width, 11472 height: height, 11473 totalheight: totalheight, 11474 src: src 11475 }; 11476 }, 11477 htmlBuilder: (group, options) => { 11478 const height = calculateSize(group.height, options); 11479 let depth = 0; 11480 11481 if (group.totalheight.number > 0) { 11482 depth = calculateSize(group.totalheight, options) - height; 11483 depth = Number(depth.toFixed(2)); 11484 } 11485 11486 let width = 0; 11487 11488 if (group.width.number > 0) { 11489 width = calculateSize(group.width, options); 11490 } 11491 11492 const style = { 11493 height: height + depth + "em" 11494 }; 11495 11496 if (width > 0) { 11497 style.width = width + "em"; 11498 } 11499 11500 if (depth > 0) { 11501 style.verticalAlign = -depth + "em"; 11502 } 11503 11504 const node = new Img(group.src, group.alt, style); 11505 node.height = height; 11506 node.depth = depth; 11507 return node; 11508 }, 11509 mathmlBuilder: (group, options) => { 11510 const node = new mathMLTree.MathNode("mglyph", []); 11511 node.setAttribute("alt", group.alt); 11512 const height = calculateSize(group.height, options); 11513 let depth = 0; 11514 11515 if (group.totalheight.number > 0) { 11516 depth = calculateSize(group.totalheight, options) - height; 11517 depth = depth.toFixed(2); 11518 node.setAttribute("valign", "-" + depth + "em"); 11519 } 11520 11521 node.setAttribute("height", height + depth + "em"); 11522 11523 if (group.width.number > 0) { 11524 const width = calculateSize(group.width, options); 11525 node.setAttribute("width", width + "em"); 11526 } 11527 11528 node.setAttribute("src", group.src); 11529 return node; 11530 } 11531}); 11532 11533// Horizontal spacing commands 11534 11535defineFunction({ 11536 type: "kern", 11537 names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], 11538 props: { 11539 numArgs: 1, 11540 argTypes: ["size"], 11541 allowedInText: true 11542 }, 11543 11544 handler(_ref, args) { 11545 let parser = _ref.parser, 11546 funcName = _ref.funcName; 11547 const size = assertNodeType(args[0], "size"); 11548 11549 if (parser.settings.strict) { 11550 const mathFunction = funcName[1] === 'm'; // \mkern, \mskip 11551 11552 const muUnit = size.value.unit === 'mu'; 11553 11554 if (mathFunction) { 11555 if (!muUnit) { 11556 parser.settings.reportNonstrict("mathVsTextUnits", `LaTeX's ${funcName} supports only mu units, ` + `not ${size.value.unit} units`); 11557 } 11558 11559 if (parser.mode !== "math") { 11560 parser.settings.reportNonstrict("mathVsTextUnits", `LaTeX's ${funcName} works only in math mode`); 11561 } 11562 } else { 11563 // !mathFunction 11564 if (muUnit) { 11565 parser.settings.reportNonstrict("mathVsTextUnits", `LaTeX's ${funcName} doesn't support mu units`); 11566 } 11567 } 11568 } 11569 11570 return { 11571 type: "kern", 11572 mode: parser.mode, 11573 dimension: size.value 11574 }; 11575 }, 11576 11577 htmlBuilder(group, options) { 11578 return buildCommon.makeGlue(group.dimension, options); 11579 }, 11580 11581 mathmlBuilder(group, options) { 11582 const dimension = calculateSize(group.dimension, options); 11583 return new mathMLTree.SpaceNode(dimension); 11584 } 11585 11586}); 11587 11588// Horizontal overlap functions 11589defineFunction({ 11590 type: "lap", 11591 names: ["\\mathllap", "\\mathrlap", "\\mathclap"], 11592 props: { 11593 numArgs: 1, 11594 allowedInText: true 11595 }, 11596 handler: (_ref, args) => { 11597 let parser = _ref.parser, 11598 funcName = _ref.funcName; 11599 const body = args[0]; 11600 return { 11601 type: "lap", 11602 mode: parser.mode, 11603 alignment: funcName.slice(5), 11604 body 11605 }; 11606 }, 11607 htmlBuilder: (group, options) => { 11608 // mathllap, mathrlap, mathclap 11609 let inner; 11610 11611 if (group.alignment === "clap") { 11612 // ref: https://www.math.lsu.edu/~aperlis/publications/mathclap/ 11613 inner = buildCommon.makeSpan([], [buildGroup(group.body, options)]); // wrap, since CSS will center a .clap > .inner > span 11614 11615 inner = buildCommon.makeSpan(["inner"], [inner], options); 11616 } else { 11617 inner = buildCommon.makeSpan(["inner"], [buildGroup(group.body, options)]); 11618 } 11619 11620 const fix = buildCommon.makeSpan(["fix"], []); 11621 let node = buildCommon.makeSpan([group.alignment], [inner, fix], options); // At this point, we have correctly set horizontal alignment of the 11622 // two items involved in the lap. 11623 // Next, use a strut to set the height of the HTML bounding box. 11624 // Otherwise, a tall argument may be misplaced. 11625 11626 const strut = buildCommon.makeSpan(["strut"]); 11627 strut.style.height = node.height + node.depth + "em"; 11628 strut.style.verticalAlign = -node.depth + "em"; 11629 node.children.unshift(strut); // Next, prevent vertical misplacement when next to something tall. 11630 11631 node = buildCommon.makeVList({ 11632 positionType: "firstBaseline", 11633 children: [{ 11634 type: "elem", 11635 elem: node 11636 }] 11637 }, options); // Get the horizontal spacing correct relative to adjacent items. 11638 11639 return buildCommon.makeSpan(["mord"], [node], options); 11640 }, 11641 mathmlBuilder: (group, options) => { 11642 // mathllap, mathrlap, mathclap 11643 const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, options)]); 11644 11645 if (group.alignment !== "rlap") { 11646 const offset = group.alignment === "llap" ? "-1" : "-0.5"; 11647 node.setAttribute("lspace", offset + "width"); 11648 } 11649 11650 node.setAttribute("width", "0px"); 11651 return node; 11652 } 11653}); 11654 11655defineFunction({ 11656 type: "styling", 11657 names: ["\\(", "$"], 11658 props: { 11659 numArgs: 0, 11660 allowedInText: true, 11661 allowedInMath: false 11662 }, 11663 11664 handler(_ref, args) { 11665 let funcName = _ref.funcName, 11666 parser = _ref.parser; 11667 const outerMode = parser.mode; 11668 parser.switchMode("math"); 11669 const close = funcName === "\\(" ? "\\)" : "$"; 11670 const body = parser.parseExpression(false, close); 11671 parser.expect(close); 11672 parser.switchMode(outerMode); 11673 return { 11674 type: "styling", 11675 mode: parser.mode, 11676 style: "text", 11677 body 11678 }; 11679 } 11680 11681}); // Check for extra closing math delimiters 11682 11683defineFunction({ 11684 type: "text", 11685 // Doesn't matter what this is. 11686 names: ["\\)", "\\]"], 11687 props: { 11688 numArgs: 0, 11689 allowedInText: true, 11690 allowedInMath: false 11691 }, 11692 11693 handler(context, args) { 11694 throw new ParseError(`Mismatched ${context.funcName}`); 11695 } 11696 11697}); 11698 11699const chooseMathStyle = (group, options) => { 11700 switch (options.style.size) { 11701 case Style$1.DISPLAY.size: 11702 return group.display; 11703 11704 case Style$1.TEXT.size: 11705 return group.text; 11706 11707 case Style$1.SCRIPT.size: 11708 return group.script; 11709 11710 case Style$1.SCRIPTSCRIPT.size: 11711 return group.scriptscript; 11712 11713 default: 11714 return group.text; 11715 } 11716}; 11717 11718defineFunction({ 11719 type: "mathchoice", 11720 names: ["\\mathchoice"], 11721 props: { 11722 numArgs: 4 11723 }, 11724 handler: (_ref, args) => { 11725 let parser = _ref.parser; 11726 return { 11727 type: "mathchoice", 11728 mode: parser.mode, 11729 display: ordargument(args[0]), 11730 text: ordargument(args[1]), 11731 script: ordargument(args[2]), 11732 scriptscript: ordargument(args[3]) 11733 }; 11734 }, 11735 htmlBuilder: (group, options) => { 11736 const body = chooseMathStyle(group, options); 11737 const elements = buildExpression(body, options, false); 11738 return buildCommon.makeFragment(elements); 11739 }, 11740 mathmlBuilder: (group, options) => { 11741 const body = chooseMathStyle(group, options); 11742 return buildExpressionRow(body, options); 11743 } 11744}); 11745 11746// For an operator with limits, assemble the base, sup, and sub into a span. 11747const assembleSupSub = (base, supGroup, subGroup, options, style, slant, baseShift) => { 11748 // IE 8 clips \int if it is in a display: inline-block. We wrap it 11749 // in a new span so it is an inline, and works. 11750 base = buildCommon.makeSpan([], [base]); 11751 let sub; 11752 let sup; // We manually have to handle the superscripts and subscripts. This, 11753 // aside from the kern calculations, is copied from supsub. 11754 11755 if (supGroup) { 11756 const elem = buildGroup(supGroup, options.havingStyle(style.sup()), options); 11757 sup = { 11758 elem, 11759 kern: Math.max(options.fontMetrics().bigOpSpacing1, options.fontMetrics().bigOpSpacing3 - elem.depth) 11760 }; 11761 } 11762 11763 if (subGroup) { 11764 const elem = buildGroup(subGroup, options.havingStyle(style.sub()), options); 11765 sub = { 11766 elem, 11767 kern: Math.max(options.fontMetrics().bigOpSpacing2, options.fontMetrics().bigOpSpacing4 - elem.height) 11768 }; 11769 } // Build the final group as a vlist of the possible subscript, base, 11770 // and possible superscript. 11771 11772 11773 let finalGroup; 11774 11775 if (sup && sub) { 11776 const bottom = options.fontMetrics().bigOpSpacing5 + sub.elem.height + sub.elem.depth + sub.kern + base.depth + baseShift; 11777 finalGroup = buildCommon.makeVList({ 11778 positionType: "bottom", 11779 positionData: bottom, 11780 children: [{ 11781 type: "kern", 11782 size: options.fontMetrics().bigOpSpacing5 11783 }, { 11784 type: "elem", 11785 elem: sub.elem, 11786 marginLeft: -slant + "em" 11787 }, { 11788 type: "kern", 11789 size: sub.kern 11790 }, { 11791 type: "elem", 11792 elem: base 11793 }, { 11794 type: "kern", 11795 size: sup.kern 11796 }, { 11797 type: "elem", 11798 elem: sup.elem, 11799 marginLeft: slant + "em" 11800 }, { 11801 type: "kern", 11802 size: options.fontMetrics().bigOpSpacing5 11803 }] 11804 }, options); 11805 } else if (sub) { 11806 const top = base.height - baseShift; // Shift the limits by the slant of the symbol. Note 11807 // that we are supposed to shift the limits by 1/2 of the slant, 11808 // but since we are centering the limits adding a full slant of 11809 // margin will shift by 1/2 that. 11810 11811 finalGroup = buildCommon.makeVList({ 11812 positionType: "top", 11813 positionData: top, 11814 children: [{ 11815 type: "kern", 11816 size: options.fontMetrics().bigOpSpacing5 11817 }, { 11818 type: "elem", 11819 elem: sub.elem, 11820 marginLeft: -slant + "em" 11821 }, { 11822 type: "kern", 11823 size: sub.kern 11824 }, { 11825 type: "elem", 11826 elem: base 11827 }] 11828 }, options); 11829 } else if (sup) { 11830 const bottom = base.depth + baseShift; 11831 finalGroup = buildCommon.makeVList({ 11832 positionType: "bottom", 11833 positionData: bottom, 11834 children: [{ 11835 type: "elem", 11836 elem: base 11837 }, { 11838 type: "kern", 11839 size: sup.kern 11840 }, { 11841 type: "elem", 11842 elem: sup.elem, 11843 marginLeft: slant + "em" 11844 }, { 11845 type: "kern", 11846 size: options.fontMetrics().bigOpSpacing5 11847 }] 11848 }, options); 11849 } else { 11850 // This case probably shouldn't occur (this would mean the 11851 // supsub was sending us a group with no superscript or 11852 // subscript) but be safe. 11853 return base; 11854 } 11855 11856 return buildCommon.makeSpan(["mop", "op-limits"], [finalGroup], options); 11857}; 11858 11859// Limits, symbols 11860// Most operators have a large successor symbol, but these don't. 11861const noSuccessor = ["\\smallint"]; // NOTE: Unlike most `htmlBuilder`s, this one handles not only "op", but also 11862// "supsub" since some of them (like \int) can affect super/subscripting. 11863 11864const htmlBuilder$8 = (grp, options) => { 11865 // Operators are handled in the TeXbook pg. 443-444, rule 13(a). 11866 let supGroup; 11867 let subGroup; 11868 let hasLimits = false; 11869 let group; 11870 const supSub = checkNodeType(grp, "supsub"); 11871 11872 if (supSub) { 11873 // If we have limits, supsub will pass us its group to handle. Pull 11874 // out the superscript and subscript and set the group to the op in 11875 // its base. 11876 supGroup = supSub.sup; 11877 subGroup = supSub.sub; 11878 group = assertNodeType(supSub.base, "op"); 11879 hasLimits = true; 11880 } else { 11881 group = assertNodeType(grp, "op"); 11882 } 11883 11884 const style = options.style; 11885 let large = false; 11886 11887 if (style.size === Style$1.DISPLAY.size && group.symbol && !utils.contains(noSuccessor, group.name)) { 11888 // Most symbol operators get larger in displaystyle (rule 13) 11889 large = true; 11890 } 11891 11892 let base; 11893 11894 if (group.symbol) { 11895 // If this is a symbol, create the symbol. 11896 const fontName = large ? "Size2-Regular" : "Size1-Regular"; 11897 let stash = ""; 11898 11899 if (group.name === "\\oiint" || group.name === "\\oiiint") { 11900 // No font glyphs yet, so use a glyph w/o the oval. 11901 // TODO: When font glyphs are available, delete this code. 11902 stash = group.name.substr(1); // $FlowFixMe 11903 11904 group.name = stash === "oiint" ? "\\iint" : "\\iiint"; 11905 } 11906 11907 base = buildCommon.makeSymbol(group.name, fontName, "math", options, ["mop", "op-symbol", large ? "large-op" : "small-op"]); 11908 11909 if (stash.length > 0) { 11910 // We're in \oiint or \oiiint. Overlay the oval. 11911 // TODO: When font glyphs are available, delete this code. 11912 const italic = base.italic; 11913 const oval = buildCommon.staticSvg(stash + "Size" + (large ? "2" : "1"), options); 11914 base = buildCommon.makeVList({ 11915 positionType: "individualShift", 11916 children: [{ 11917 type: "elem", 11918 elem: base, 11919 shift: 0 11920 }, { 11921 type: "elem", 11922 elem: oval, 11923 shift: large ? 0.08 : 0 11924 }] 11925 }, options); // $FlowFixMe 11926 11927 group.name = "\\" + stash; 11928 base.classes.unshift("mop"); // $FlowFixMe 11929 11930 base.italic = italic; 11931 } 11932 } else if (group.body) { 11933 // If this is a list, compose that list. 11934 const inner = buildExpression(group.body, options, true); 11935 11936 if (inner.length === 1 && inner[0] instanceof SymbolNode) { 11937 base = inner[0]; 11938 base.classes[0] = "mop"; // replace old mclass 11939 } else { 11940 base = buildCommon.makeSpan(["mop"], buildCommon.tryCombineChars(inner), options); 11941 } 11942 } else { 11943 // Otherwise, this is a text operator. Build the text from the 11944 // operator's name. 11945 // TODO(emily): Add a space in the middle of some of these 11946 // operators, like \limsup 11947 const output = []; 11948 11949 for (let i = 1; i < group.name.length; i++) { 11950 output.push(buildCommon.mathsym(group.name[i], group.mode, options)); 11951 } 11952 11953 base = buildCommon.makeSpan(["mop"], output, options); 11954 } // If content of op is a single symbol, shift it vertically. 11955 11956 11957 let baseShift = 0; 11958 let slant = 0; 11959 11960 if ((base instanceof SymbolNode || group.name === "\\oiint" || group.name === "\\oiiint") && !group.suppressBaseShift) { 11961 // We suppress the shift of the base of \overset and \underset. Otherwise, 11962 // shift the symbol so its center lies on the axis (rule 13). It 11963 // appears that our fonts have the centers of the symbols already 11964 // almost on the axis, so these numbers are very small. Note we 11965 // don't actually apply this here, but instead it is used either in 11966 // the vlist creation or separately when there are no limits. 11967 baseShift = (base.height - base.depth) / 2 - options.fontMetrics().axisHeight; // The slant of the symbol is just its italic correction. 11968 // $FlowFixMe 11969 11970 slant = base.italic; 11971 } 11972 11973 if (hasLimits) { 11974 return assembleSupSub(base, supGroup, subGroup, options, style, slant, baseShift); 11975 } else { 11976 if (baseShift) { 11977 base.style.position = "relative"; 11978 base.style.top = baseShift + "em"; 11979 } 11980 11981 return base; 11982 } 11983}; 11984 11985const mathmlBuilder$8 = (group, options) => { 11986 let node; 11987 11988 if (group.symbol) { 11989 // This is a symbol. Just add the symbol. 11990 node = new MathNode("mo", [makeText(group.name, group.mode)]); 11991 11992 if (utils.contains(noSuccessor, group.name)) { 11993 node.setAttribute("largeop", "false"); 11994 } 11995 } else if (group.body) { 11996 // This is an operator with children. Add them. 11997 node = new MathNode("mo", buildExpression$1(group.body, options)); 11998 } else { 11999 // This is a text operator. Add all of the characters from the 12000 // operator's name. 12001 node = new MathNode("mi", [new TextNode(group.name.slice(1))]); // Append an <mo>⁡</mo>. 12002 // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 12003 12004 const operator = new MathNode("mo", [makeText("\u2061", "text")]); 12005 12006 if (group.parentIsSupSub) { 12007 node = new MathNode("mo", [node, operator]); 12008 } else { 12009 node = newDocumentFragment([node, operator]); 12010 } 12011 } 12012 12013 return node; 12014}; 12015 12016const singleCharBigOps = { 12017 "\u220F": "\\prod", 12018 "\u2210": "\\coprod", 12019 "\u2211": "\\sum", 12020 "\u22c0": "\\bigwedge", 12021 "\u22c1": "\\bigvee", 12022 "\u22c2": "\\bigcap", 12023 "\u22c3": "\\bigcup", 12024 "\u2a00": "\\bigodot", 12025 "\u2a01": "\\bigoplus", 12026 "\u2a02": "\\bigotimes", 12027 "\u2a04": "\\biguplus", 12028 "\u2a06": "\\bigsqcup" 12029}; 12030defineFunction({ 12031 type: "op", 12032 names: ["\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap", "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes", "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint", "\u220F", "\u2210", "\u2211", "\u22c0", "\u22c1", "\u22c2", "\u22c3", "\u2a00", "\u2a01", "\u2a02", "\u2a04", "\u2a06"], 12033 props: { 12034 numArgs: 0 12035 }, 12036 handler: (_ref, args) => { 12037 let parser = _ref.parser, 12038 funcName = _ref.funcName; 12039 let fName = funcName; 12040 12041 if (fName.length === 1) { 12042 fName = singleCharBigOps[fName]; 12043 } 12044 12045 return { 12046 type: "op", 12047 mode: parser.mode, 12048 limits: true, 12049 parentIsSupSub: false, 12050 symbol: true, 12051 name: fName 12052 }; 12053 }, 12054 htmlBuilder: htmlBuilder$8, 12055 mathmlBuilder: mathmlBuilder$8 12056}); // Note: calling defineFunction with a type that's already been defined only 12057// works because the same htmlBuilder and mathmlBuilder are being used. 12058 12059defineFunction({ 12060 type: "op", 12061 names: ["\\mathop"], 12062 props: { 12063 numArgs: 1 12064 }, 12065 handler: (_ref2, args) => { 12066 let parser = _ref2.parser; 12067 const body = args[0]; 12068 return { 12069 type: "op", 12070 mode: parser.mode, 12071 limits: false, 12072 parentIsSupSub: false, 12073 symbol: false, 12074 body: ordargument(body) 12075 }; 12076 }, 12077 htmlBuilder: htmlBuilder$8, 12078 mathmlBuilder: mathmlBuilder$8 12079}); // There are 2 flags for operators; whether they produce limits in 12080// displaystyle, and whether they are symbols and should grow in 12081// displaystyle. These four groups cover the four possible choices. 12082 12083const singleCharIntegrals = { 12084 "\u222b": "\\int", 12085 "\u222c": "\\iint", 12086 "\u222d": "\\iiint", 12087 "\u222e": "\\oint", 12088 "\u222f": "\\oiint", 12089 "\u2230": "\\oiiint" 12090}; // No limits, not symbols 12091 12092defineFunction({ 12093 type: "op", 12094 names: ["\\arcsin", "\\arccos", "\\arctan", "\\arctg", "\\arcctg", "\\arg", "\\ch", "\\cos", "\\cosec", "\\cosh", "\\cot", "\\cotg", "\\coth", "\\csc", "\\ctg", "\\cth", "\\deg", "\\dim", "\\exp", "\\hom", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh", "\\sh", "\\tan", "\\tanh", "\\tg", "\\th"], 12095 props: { 12096 numArgs: 0 12097 }, 12098 12099 handler(_ref3) { 12100 let parser = _ref3.parser, 12101 funcName = _ref3.funcName; 12102 return { 12103 type: "op", 12104 mode: parser.mode, 12105 limits: false, 12106 parentIsSupSub: false, 12107 symbol: false, 12108 name: funcName 12109 }; 12110 }, 12111 12112 htmlBuilder: htmlBuilder$8, 12113 mathmlBuilder: mathmlBuilder$8 12114}); // Limits, not symbols 12115 12116defineFunction({ 12117 type: "op", 12118 names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], 12119 props: { 12120 numArgs: 0 12121 }, 12122 12123 handler(_ref4) { 12124 let parser = _ref4.parser, 12125 funcName = _ref4.funcName; 12126 return { 12127 type: "op", 12128 mode: parser.mode, 12129 limits: true, 12130 parentIsSupSub: false, 12131 symbol: false, 12132 name: funcName 12133 }; 12134 }, 12135 12136 htmlBuilder: htmlBuilder$8, 12137 mathmlBuilder: mathmlBuilder$8 12138}); // No limits, symbols 12139 12140defineFunction({ 12141 type: "op", 12142 names: ["\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint", "\u222b", "\u222c", "\u222d", "\u222e", "\u222f", "\u2230"], 12143 props: { 12144 numArgs: 0 12145 }, 12146 12147 handler(_ref5) { 12148 let parser = _ref5.parser, 12149 funcName = _ref5.funcName; 12150 let fName = funcName; 12151 12152 if (fName.length === 1) { 12153 fName = singleCharIntegrals[fName]; 12154 } 12155 12156 return { 12157 type: "op", 12158 mode: parser.mode, 12159 limits: false, 12160 parentIsSupSub: false, 12161 symbol: true, 12162 name: fName 12163 }; 12164 }, 12165 12166 htmlBuilder: htmlBuilder$8, 12167 mathmlBuilder: mathmlBuilder$8 12168}); 12169 12170// NOTE: Unlike most `htmlBuilder`s, this one handles not only 12171// "operatorname", but also "supsub" since \operatorname* can 12172const htmlBuilder$9 = (grp, options) => { 12173 // Operators are handled in the TeXbook pg. 443-444, rule 13(a). 12174 let supGroup; 12175 let subGroup; 12176 let hasLimits = false; 12177 let group; 12178 const supSub = checkNodeType(grp, "supsub"); 12179 12180 if (supSub) { 12181 // If we have limits, supsub will pass us its group to handle. Pull 12182 // out the superscript and subscript and set the group to the op in 12183 // its base. 12184 supGroup = supSub.sup; 12185 subGroup = supSub.sub; 12186 group = assertNodeType(supSub.base, "operatorname"); 12187 hasLimits = true; 12188 } else { 12189 group = assertNodeType(grp, "operatorname"); 12190 } 12191 12192 let base; 12193 12194 if (group.body.length > 0) { 12195 const body = group.body.map(child => { 12196 // $FlowFixMe: Check if the node has a string `text` property. 12197 const childText = child.text; 12198 12199 if (typeof childText === "string") { 12200 return { 12201 type: "textord", 12202 mode: child.mode, 12203 text: childText 12204 }; 12205 } else { 12206 return child; 12207 } 12208 }); // Consolidate function names into symbol characters. 12209 12210 const expression = buildExpression(body, options.withFont("mathrm"), true); 12211 12212 for (let i = 0; i < expression.length; i++) { 12213 const child = expression[i]; 12214 12215 if (child instanceof SymbolNode) { 12216 // Per amsopn package, 12217 // change minus to hyphen and \ast to asterisk 12218 child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); 12219 } 12220 } 12221 12222 base = buildCommon.makeSpan(["mop"], expression, options); 12223 } else { 12224 base = buildCommon.makeSpan(["mop"], [], options); 12225 } 12226 12227 if (hasLimits) { 12228 return assembleSupSub(base, supGroup, subGroup, options, options.style, 0, 0); 12229 } else { 12230 return base; 12231 } 12232}; 12233 12234const mathmlBuilder$9 = (group, options) => { 12235 // The steps taken here are similar to the html version. 12236 let expression = buildExpression$1(group.body, options.withFont("mathrm")); // Is expression a string or has it something like a fraction? 12237 12238 let isAllString = true; // default 12239 12240 for (let i = 0; i < expression.length; i++) { 12241 const node = expression[i]; 12242 12243 if (node instanceof mathMLTree.SpaceNode) ; else if (node instanceof mathMLTree.MathNode) { 12244 switch (node.type) { 12245 case "mi": 12246 case "mn": 12247 case "ms": 12248 case "mspace": 12249 case "mtext": 12250 break; 12251 // Do nothing yet. 12252 12253 case "mo": 12254 { 12255 const child = node.children[0]; 12256 12257 if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { 12258 child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); 12259 } else { 12260 isAllString = false; 12261 } 12262 12263 break; 12264 } 12265 12266 default: 12267 isAllString = false; 12268 } 12269 } else { 12270 isAllString = false; 12271 } 12272 } 12273 12274 if (isAllString) { 12275 // Write a single TextNode instead of multiple nested tags. 12276 const word = expression.map(node => node.toText()).join(""); 12277 expression = [new mathMLTree.TextNode(word)]; 12278 } 12279 12280 const identifier = new mathMLTree.MathNode("mi", expression); 12281 identifier.setAttribute("mathvariant", "normal"); // \u2061 is the same as ⁡ 12282 // ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp 12283 12284 const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); 12285 12286 if (group.parentIsSupSub) { 12287 return new mathMLTree.MathNode("mo", [identifier, operator]); 12288 } else { 12289 return mathMLTree.newDocumentFragment([identifier, operator]); 12290 } 12291}; // \operatorname 12292// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ 12293 12294 12295defineFunction({ 12296 type: "operatorname", 12297 names: ["\\operatorname", "\\operatorname*"], 12298 props: { 12299 numArgs: 1 12300 }, 12301 handler: (_ref, args) => { 12302 let parser = _ref.parser, 12303 funcName = _ref.funcName; 12304 const body = args[0]; 12305 return { 12306 type: "operatorname", 12307 mode: parser.mode, 12308 body: ordargument(body), 12309 alwaysHandleSupSub: funcName === "\\operatorname*", 12310 limits: false, 12311 parentIsSupSub: false 12312 }; 12313 }, 12314 htmlBuilder: htmlBuilder$9, 12315 mathmlBuilder: mathmlBuilder$9 12316}); 12317 12318defineFunctionBuilders({ 12319 type: "ordgroup", 12320 12321 htmlBuilder(group, options) { 12322 if (group.semisimple) { 12323 return buildCommon.makeFragment(buildExpression(group.body, options, false)); 12324 } 12325 12326 return buildCommon.makeSpan(["mord"], buildExpression(group.body, options, true), options); 12327 }, 12328 12329 mathmlBuilder(group, options) { 12330 return buildExpressionRow(group.body, options, true); 12331 } 12332 12333}); 12334 12335defineFunction({ 12336 type: "overline", 12337 names: ["\\overline"], 12338 props: { 12339 numArgs: 1 12340 }, 12341 12342 handler(_ref, args) { 12343 let parser = _ref.parser; 12344 const body = args[0]; 12345 return { 12346 type: "overline", 12347 mode: parser.mode, 12348 body 12349 }; 12350 }, 12351 12352 htmlBuilder(group, options) { 12353 // Overlines are handled in the TeXbook pg 443, Rule 9. 12354 // Build the inner group in the cramped style. 12355 const innerGroup = buildGroup(group.body, options.havingCrampedStyle()); // Create the line above the body 12356 12357 const line = buildCommon.makeLineSpan("overline-line", options); // Generate the vlist, with the appropriate kerns 12358 12359 const defaultRuleThickness = options.fontMetrics().defaultRuleThickness; 12360 const vlist = buildCommon.makeVList({ 12361 positionType: "firstBaseline", 12362 children: [{ 12363 type: "elem", 12364 elem: innerGroup 12365 }, { 12366 type: "kern", 12367 size: 3 * defaultRuleThickness 12368 }, { 12369 type: "elem", 12370 elem: line 12371 }, { 12372 type: "kern", 12373 size: defaultRuleThickness 12374 }] 12375 }, options); 12376 return buildCommon.makeSpan(["mord", "overline"], [vlist], options); 12377 }, 12378 12379 mathmlBuilder(group, options) { 12380 const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203e")]); 12381 operator.setAttribute("stretchy", "true"); 12382 const node = new mathMLTree.MathNode("mover", [buildGroup$1(group.body, options), operator]); 12383 node.setAttribute("accent", "true"); 12384 return node; 12385 } 12386 12387}); 12388 12389defineFunction({ 12390 type: "phantom", 12391 names: ["\\phantom"], 12392 props: { 12393 numArgs: 1, 12394 allowedInText: true 12395 }, 12396 handler: (_ref, args) => { 12397 let parser = _ref.parser; 12398 const body = args[0]; 12399 return { 12400 type: "phantom", 12401 mode: parser.mode, 12402 body: ordargument(body) 12403 }; 12404 }, 12405 htmlBuilder: (group, options) => { 12406 const elements = buildExpression(group.body, options.withPhantom(), false); // \phantom isn't supposed to affect the elements it contains. 12407 // See "color" for more details. 12408 12409 return buildCommon.makeFragment(elements); 12410 }, 12411 mathmlBuilder: (group, options) => { 12412 const inner = buildExpression$1(group.body, options); 12413 return new mathMLTree.MathNode("mphantom", inner); 12414 } 12415}); 12416defineFunction({ 12417 type: "hphantom", 12418 names: ["\\hphantom"], 12419 props: { 12420 numArgs: 1, 12421 allowedInText: true 12422 }, 12423 handler: (_ref2, args) => { 12424 let parser = _ref2.parser; 12425 const body = args[0]; 12426 return { 12427 type: "hphantom", 12428 mode: parser.mode, 12429 body 12430 }; 12431 }, 12432 htmlBuilder: (group, options) => { 12433 let node = buildCommon.makeSpan([], [buildGroup(group.body, options.withPhantom())]); 12434 node.height = 0; 12435 node.depth = 0; 12436 12437 if (node.children) { 12438 for (let i = 0; i < node.children.length; i++) { 12439 node.children[i].height = 0; 12440 node.children[i].depth = 0; 12441 } 12442 } // See smash for comment re: use of makeVList 12443 12444 12445 node = buildCommon.makeVList({ 12446 positionType: "firstBaseline", 12447 children: [{ 12448 type: "elem", 12449 elem: node 12450 }] 12451 }, options); // For spacing, TeX treats \smash as a math group (same spacing as ord). 12452 12453 return buildCommon.makeSpan(["mord"], [node], options); 12454 }, 12455 mathmlBuilder: (group, options) => { 12456 const inner = buildExpression$1(ordargument(group.body), options); 12457 const phantom = new mathMLTree.MathNode("mphantom", inner); 12458 const node = new mathMLTree.MathNode("mpadded", [phantom]); 12459 node.setAttribute("height", "0px"); 12460 node.setAttribute("depth", "0px"); 12461 return node; 12462 } 12463}); 12464defineFunction({ 12465 type: "vphantom", 12466 names: ["\\vphantom"], 12467 props: { 12468 numArgs: 1, 12469 allowedInText: true 12470 }, 12471 handler: (_ref3, args) => { 12472 let parser = _ref3.parser; 12473 const body = args[0]; 12474 return { 12475 type: "vphantom", 12476 mode: parser.mode, 12477 body 12478 }; 12479 }, 12480 htmlBuilder: (group, options) => { 12481 const inner = buildCommon.makeSpan(["inner"], [buildGroup(group.body, options.withPhantom())]); 12482 const fix = buildCommon.makeSpan(["fix"], []); 12483 return buildCommon.makeSpan(["mord", "rlap"], [inner, fix], options); 12484 }, 12485 mathmlBuilder: (group, options) => { 12486 const inner = buildExpression$1(ordargument(group.body), options); 12487 const phantom = new mathMLTree.MathNode("mphantom", inner); 12488 const node = new mathMLTree.MathNode("mpadded", [phantom]); 12489 node.setAttribute("width", "0px"); 12490 return node; 12491 } 12492}); 12493 12494defineFunction({ 12495 type: "raisebox", 12496 names: ["\\raisebox"], 12497 props: { 12498 numArgs: 2, 12499 argTypes: ["size", "hbox"], 12500 allowedInText: true 12501 }, 12502 12503 handler(_ref, args) { 12504 let parser = _ref.parser; 12505 const amount = assertNodeType(args[0], "size").value; 12506 const body = args[1]; 12507 return { 12508 type: "raisebox", 12509 mode: parser.mode, 12510 dy: amount, 12511 body 12512 }; 12513 }, 12514 12515 htmlBuilder(group, options) { 12516 const body = buildGroup(group.body, options); 12517 const dy = calculateSize(group.dy, options); 12518 return buildCommon.makeVList({ 12519 positionType: "shift", 12520 positionData: -dy, 12521 children: [{ 12522 type: "elem", 12523 elem: body 12524 }] 12525 }, options); 12526 }, 12527 12528 mathmlBuilder(group, options) { 12529 const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, options)]); 12530 const dy = group.dy.number + group.dy.unit; 12531 node.setAttribute("voffset", dy); 12532 return node; 12533 } 12534 12535}); 12536 12537defineFunction({ 12538 type: "rule", 12539 names: ["\\rule"], 12540 props: { 12541 numArgs: 2, 12542 numOptionalArgs: 1, 12543 argTypes: ["size", "size", "size"] 12544 }, 12545 12546 handler(_ref, args, optArgs) { 12547 let parser = _ref.parser; 12548 const shift = optArgs[0]; 12549 const width = assertNodeType(args[0], "size"); 12550 const height = assertNodeType(args[1], "size"); 12551 return { 12552 type: "rule", 12553 mode: parser.mode, 12554 shift: shift && assertNodeType(shift, "size").value, 12555 width: width.value, 12556 height: height.value 12557 }; 12558 }, 12559 12560 htmlBuilder(group, options) { 12561 // Make an empty span for the rule 12562 const rule = buildCommon.makeSpan(["mord", "rule"], [], options); // Calculate the shift, width, and height of the rule, and account for units 12563 12564 const width = calculateSize(group.width, options); 12565 const height = calculateSize(group.height, options); 12566 const shift = group.shift ? calculateSize(group.shift, options) : 0; // Style the rule to the right size 12567 12568 rule.style.borderRightWidth = width + "em"; 12569 rule.style.borderTopWidth = height + "em"; 12570 rule.style.bottom = shift + "em"; // Record the height and width 12571 12572 rule.width = width; 12573 rule.height = height + shift; 12574 rule.depth = -shift; // Font size is the number large enough that the browser will 12575 // reserve at least `absHeight` space above the baseline. 12576 // The 1.125 factor was empirically determined 12577 12578 rule.maxFontSize = height * 1.125 * options.sizeMultiplier; 12579 return rule; 12580 }, 12581 12582 mathmlBuilder(group, options) { 12583 const width = calculateSize(group.width, options); 12584 const height = calculateSize(group.height, options); 12585 const shift = group.shift ? calculateSize(group.shift, options) : 0; 12586 const color = options.color && options.getColor() || "black"; 12587 const rule = new mathMLTree.MathNode("mspace"); 12588 rule.setAttribute("mathbackground", color); 12589 rule.setAttribute("width", width + "em"); 12590 rule.setAttribute("height", height + "em"); 12591 const wrapper = new mathMLTree.MathNode("mpadded", [rule]); 12592 12593 if (shift >= 0) { 12594 wrapper.setAttribute("height", "+" + shift + "em"); 12595 } else { 12596 wrapper.setAttribute("height", shift + "em"); 12597 wrapper.setAttribute("depth", "+" + -shift + "em"); 12598 } 12599 12600 wrapper.setAttribute("voffset", shift + "em"); 12601 return wrapper; 12602 } 12603 12604}); 12605 12606function sizingGroup(value, options, baseOptions) { 12607 const inner = buildExpression(value, options, false); 12608 const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; // Add size-resetting classes to the inner list and set maxFontSize 12609 // manually. Handle nested size changes. 12610 12611 for (let i = 0; i < inner.length; i++) { 12612 const pos = inner[i].classes.indexOf("sizing"); 12613 12614 if (pos < 0) { 12615 Array.prototype.push.apply(inner[i].classes, options.sizingClasses(baseOptions)); 12616 } else if (inner[i].classes[pos + 1] === "reset-size" + options.size) { 12617 // This is a nested size change: e.g., inner[i] is the "b" in 12618 // `\Huge a \small b`. Override the old size (the `reset-` class) 12619 // but not the new size. 12620 inner[i].classes[pos + 1] = "reset-size" + baseOptions.size; 12621 } 12622 12623 inner[i].height *= multiplier; 12624 inner[i].depth *= multiplier; 12625 } 12626 12627 return buildCommon.makeFragment(inner); 12628} 12629const sizeFuncs = ["\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"]; 12630const htmlBuilder$a = (group, options) => { 12631 // Handle sizing operators like \Huge. Real TeX doesn't actually allow 12632 // these functions inside of math expressions, so we do some special 12633 // handling. 12634 const newOptions = options.havingSize(group.size); 12635 return sizingGroup(group.body, newOptions, options); 12636}; 12637defineFunction({ 12638 type: "sizing", 12639 names: sizeFuncs, 12640 props: { 12641 numArgs: 0, 12642 allowedInText: true 12643 }, 12644 handler: (_ref, args) => { 12645 let breakOnTokenText = _ref.breakOnTokenText, 12646 funcName = _ref.funcName, 12647 parser = _ref.parser; 12648 const body = parser.parseExpression(false, breakOnTokenText); 12649 return { 12650 type: "sizing", 12651 mode: parser.mode, 12652 // Figure out what size to use based on the list of functions above 12653 size: sizeFuncs.indexOf(funcName) + 1, 12654 body 12655 }; 12656 }, 12657 htmlBuilder: htmlBuilder$a, 12658 mathmlBuilder: (group, options) => { 12659 const newOptions = options.havingSize(group.size); 12660 const inner = buildExpression$1(group.body, newOptions); 12661 const node = new mathMLTree.MathNode("mstyle", inner); // TODO(emily): This doesn't produce the correct size for nested size 12662 // changes, because we don't keep state of what style we're currently 12663 // in, so we can't reset the size to normal before changing it. Now 12664 // that we're passing an options parameter we should be able to fix 12665 // this. 12666 12667 node.setAttribute("mathsize", newOptions.sizeMultiplier + "em"); 12668 return node; 12669 } 12670}); 12671 12672// smash, with optional [tb], as in AMS 12673defineFunction({ 12674 type: "smash", 12675 names: ["\\smash"], 12676 props: { 12677 numArgs: 1, 12678 numOptionalArgs: 1, 12679 allowedInText: true 12680 }, 12681 handler: (_ref, args, optArgs) => { 12682 let parser = _ref.parser; 12683 let smashHeight = false; 12684 let smashDepth = false; 12685 const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); 12686 12687 if (tbArg) { 12688 // Optional [tb] argument is engaged. 12689 // ref: amsmath: \renewcommand{\smash}[1][tb]{% 12690 // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% 12691 let letter = ""; 12692 12693 for (let i = 0; i < tbArg.body.length; ++i) { 12694 const node = tbArg.body[i]; // $FlowFixMe: Not every node type has a `text` property. 12695 12696 letter = node.text; 12697 12698 if (letter === "t") { 12699 smashHeight = true; 12700 } else if (letter === "b") { 12701 smashDepth = true; 12702 } else { 12703 smashHeight = false; 12704 smashDepth = false; 12705 break; 12706 } 12707 } 12708 } else { 12709 smashHeight = true; 12710 smashDepth = true; 12711 } 12712 12713 const body = args[0]; 12714 return { 12715 type: "smash", 12716 mode: parser.mode, 12717 body, 12718 smashHeight, 12719 smashDepth 12720 }; 12721 }, 12722 htmlBuilder: (group, options) => { 12723 const node = buildCommon.makeSpan([], [buildGroup(group.body, options)]); 12724 12725 if (!group.smashHeight && !group.smashDepth) { 12726 return node; 12727 } 12728 12729 if (group.smashHeight) { 12730 node.height = 0; // In order to influence makeVList, we have to reset the children. 12731 12732 if (node.children) { 12733 for (let i = 0; i < node.children.length; i++) { 12734 node.children[i].height = 0; 12735 } 12736 } 12737 } 12738 12739 if (group.smashDepth) { 12740 node.depth = 0; 12741 12742 if (node.children) { 12743 for (let i = 0; i < node.children.length; i++) { 12744 node.children[i].depth = 0; 12745 } 12746 } 12747 } // At this point, we've reset the TeX-like height and depth values. 12748 // But the span still has an HTML line height. 12749 // makeVList applies "display: table-cell", which prevents the browser 12750 // from acting on that line height. So we'll call makeVList now. 12751 12752 12753 const smashedNode = buildCommon.makeVList({ 12754 positionType: "firstBaseline", 12755 children: [{ 12756 type: "elem", 12757 elem: node 12758 }] 12759 }, options); // For spacing, TeX treats \hphantom as a math group (same spacing as ord). 12760 12761 return buildCommon.makeSpan(["mord"], [smashedNode], options); 12762 }, 12763 mathmlBuilder: (group, options) => { 12764 const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, options)]); 12765 12766 if (group.smashHeight) { 12767 node.setAttribute("height", "0px"); 12768 } 12769 12770 if (group.smashDepth) { 12771 node.setAttribute("depth", "0px"); 12772 } 12773 12774 return node; 12775 } 12776}); 12777 12778defineFunction({ 12779 type: "sqrt", 12780 names: ["\\sqrt"], 12781 props: { 12782 numArgs: 1, 12783 numOptionalArgs: 1 12784 }, 12785 12786 handler(_ref, args, optArgs) { 12787 let parser = _ref.parser; 12788 const index = optArgs[0]; 12789 const body = args[0]; 12790 return { 12791 type: "sqrt", 12792 mode: parser.mode, 12793 body, 12794 index 12795 }; 12796 }, 12797 12798 htmlBuilder(group, options) { 12799 // Square roots are handled in the TeXbook pg. 443, Rule 11. 12800 // First, we do the same steps as in overline to build the inner group 12801 // and line 12802 let inner = buildGroup(group.body, options.havingCrampedStyle()); 12803 12804 if (inner.height === 0) { 12805 // Render a small surd. 12806 inner.height = options.fontMetrics().xHeight; 12807 } // Some groups can return document fragments. Handle those by wrapping 12808 // them in a span. 12809 12810 12811 inner = buildCommon.wrapFragment(inner, options); // Calculate the minimum size for the \surd delimiter 12812 12813 const metrics = options.fontMetrics(); 12814 const theta = metrics.defaultRuleThickness; 12815 let phi = theta; 12816 12817 if (options.style.id < Style$1.TEXT.id) { 12818 phi = options.fontMetrics().xHeight; 12819 } // Calculate the clearance between the body and line 12820 12821 12822 let lineClearance = theta + phi / 4; 12823 const minDelimiterHeight = inner.height + inner.depth + lineClearance + theta; // Create a sqrt SVG of the required minimum size 12824 12825 const _delimiter$sqrtImage = delimiter.sqrtImage(minDelimiterHeight, options), 12826 img = _delimiter$sqrtImage.span, 12827 ruleWidth = _delimiter$sqrtImage.ruleWidth, 12828 advanceWidth = _delimiter$sqrtImage.advanceWidth; 12829 12830 const delimDepth = img.height - ruleWidth; // Adjust the clearance based on the delimiter size 12831 12832 if (delimDepth > inner.height + inner.depth + lineClearance) { 12833 lineClearance = (lineClearance + delimDepth - inner.height - inner.depth) / 2; 12834 } // Shift the sqrt image 12835 12836 12837 const imgShift = img.height - inner.height - lineClearance - ruleWidth; 12838 inner.style.paddingLeft = advanceWidth + "em"; // Overlay the image and the argument. 12839 12840 const body = buildCommon.makeVList({ 12841 positionType: "firstBaseline", 12842 children: [{ 12843 type: "elem", 12844 elem: inner, 12845 wrapperClasses: ["svg-align"] 12846 }, { 12847 type: "kern", 12848 size: -(inner.height + imgShift) 12849 }, { 12850 type: "elem", 12851 elem: img 12852 }, { 12853 type: "kern", 12854 size: ruleWidth 12855 }] 12856 }, options); 12857 12858 if (!group.index) { 12859 return buildCommon.makeSpan(["mord", "sqrt"], [body], options); 12860 } else { 12861 // Handle the optional root index 12862 // The index is always in scriptscript style 12863 const newOptions = options.havingStyle(Style$1.SCRIPTSCRIPT); 12864 const rootm = buildGroup(group.index, newOptions, options); // The amount the index is shifted by. This is taken from the TeX 12865 // source, in the definition of `\r@@t`. 12866 12867 const toShift = 0.6 * (body.height - body.depth); // Build a VList with the superscript shifted up correctly 12868 12869 const rootVList = buildCommon.makeVList({ 12870 positionType: "shift", 12871 positionData: -toShift, 12872 children: [{ 12873 type: "elem", 12874 elem: rootm 12875 }] 12876 }, options); // Add a class surrounding it so we can add on the appropriate 12877 // kerning 12878 12879 const rootVListWrap = buildCommon.makeSpan(["root"], [rootVList]); 12880 return buildCommon.makeSpan(["mord", "sqrt"], [rootVListWrap, body], options); 12881 } 12882 }, 12883 12884 mathmlBuilder(group, options) { 12885 const body = group.body, 12886 index = group.index; 12887 return index ? new mathMLTree.MathNode("mroot", [buildGroup$1(body, options), buildGroup$1(index, options)]) : new mathMLTree.MathNode("msqrt", [buildGroup$1(body, options)]); 12888 } 12889 12890}); 12891 12892const styleMap$1 = { 12893 "display": Style$1.DISPLAY, 12894 "text": Style$1.TEXT, 12895 "script": Style$1.SCRIPT, 12896 "scriptscript": Style$1.SCRIPTSCRIPT 12897}; 12898defineFunction({ 12899 type: "styling", 12900 names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], 12901 props: { 12902 numArgs: 0, 12903 allowedInText: true 12904 }, 12905 12906 handler(_ref, args) { 12907 let breakOnTokenText = _ref.breakOnTokenText, 12908 funcName = _ref.funcName, 12909 parser = _ref.parser; 12910 // parse out the implicit body 12911 const body = parser.parseExpression(true, breakOnTokenText); // TODO: Refactor to avoid duplicating styleMap in multiple places (e.g. 12912 // here and in buildHTML and de-dupe the enumeration of all the styles). 12913 // $FlowFixMe: The names above exactly match the styles. 12914 12915 const style = funcName.slice(1, funcName.length - 5); 12916 return { 12917 type: "styling", 12918 mode: parser.mode, 12919 // Figure out what style to use by pulling out the style from 12920 // the function name 12921 style, 12922 body 12923 }; 12924 }, 12925 12926 htmlBuilder(group, options) { 12927 // Style changes are handled in the TeXbook on pg. 442, Rule 3. 12928 const newStyle = styleMap$1[group.style]; 12929 const newOptions = options.havingStyle(newStyle).withFont(''); 12930 return sizingGroup(group.body, newOptions, options); 12931 }, 12932 12933 mathmlBuilder(group, options) { 12934 // Figure out what style we're changing to. 12935 const newStyle = styleMap$1[group.style]; 12936 const newOptions = options.havingStyle(newStyle); 12937 const inner = buildExpression$1(group.body, newOptions); 12938 const node = new mathMLTree.MathNode("mstyle", inner); 12939 const styleAttributes = { 12940 "display": ["0", "true"], 12941 "text": ["0", "false"], 12942 "script": ["1", "false"], 12943 "scriptscript": ["2", "false"] 12944 }; 12945 const attr = styleAttributes[group.style]; 12946 node.setAttribute("scriptlevel", attr[0]); 12947 node.setAttribute("displaystyle", attr[1]); 12948 return node; 12949 } 12950 12951}); 12952 12953/** 12954 * Sometimes, groups perform special rules when they have superscripts or 12955 * subscripts attached to them. This function lets the `supsub` group know that 12956 * Sometimes, groups perform special rules when they have superscripts or 12957 * its inner element should handle the superscripts and subscripts instead of 12958 * handling them itself. 12959 */ 12960const htmlBuilderDelegate = function htmlBuilderDelegate(group, options) { 12961 const base = group.base; 12962 12963 if (!base) { 12964 return null; 12965 } else if (base.type === "op") { 12966 // Operators handle supsubs differently when they have limits 12967 // (e.g. `\displaystyle\sum_2^3`) 12968 const delegate = base.limits && (options.style.size === Style$1.DISPLAY.size || base.alwaysHandleSupSub); 12969 return delegate ? htmlBuilder$8 : null; 12970 } else if (base.type === "operatorname") { 12971 const delegate = base.alwaysHandleSupSub && (options.style.size === Style$1.DISPLAY.size || base.limits); 12972 return delegate ? htmlBuilder$9 : null; 12973 } else if (base.type === "accent") { 12974 return utils.isCharacterBox(base.base) ? htmlBuilder : null; 12975 } else if (base.type === "horizBrace") { 12976 const isSup = !group.sub; 12977 return isSup === base.isOver ? htmlBuilder$7 : null; 12978 } else { 12979 return null; 12980 } 12981}; // Super scripts and subscripts, whose precise placement can depend on other 12982// functions that precede them. 12983 12984 12985defineFunctionBuilders({ 12986 type: "supsub", 12987 12988 htmlBuilder(group, options) { 12989 // Superscript and subscripts are handled in the TeXbook on page 12990 // 445-446, rules 18(a-f). 12991 // Here is where we defer to the inner group if it should handle 12992 // superscripts and subscripts itself. 12993 const builderDelegate = htmlBuilderDelegate(group, options); 12994 12995 if (builderDelegate) { 12996 return builderDelegate(group, options); 12997 } 12998 12999 const valueBase = group.base, 13000 valueSup = group.sup, 13001 valueSub = group.sub; 13002 const base = buildGroup(valueBase, options); 13003 let supm; 13004 let subm; 13005 const metrics = options.fontMetrics(); // Rule 18a 13006 13007 let supShift = 0; 13008 let subShift = 0; 13009 const isCharacterBox = valueBase && utils.isCharacterBox(valueBase); 13010 13011 if (valueSup) { 13012 const newOptions = options.havingStyle(options.style.sup()); 13013 supm = buildGroup(valueSup, newOptions, options); 13014 13015 if (!isCharacterBox) { 13016 supShift = base.height - newOptions.fontMetrics().supDrop * newOptions.sizeMultiplier / options.sizeMultiplier; 13017 } 13018 } 13019 13020 if (valueSub) { 13021 const newOptions = options.havingStyle(options.style.sub()); 13022 subm = buildGroup(valueSub, newOptions, options); 13023 13024 if (!isCharacterBox) { 13025 subShift = base.depth + newOptions.fontMetrics().subDrop * newOptions.sizeMultiplier / options.sizeMultiplier; 13026 } 13027 } // Rule 18c 13028 13029 13030 let minSupShift; 13031 13032 if (options.style === Style$1.DISPLAY) { 13033 minSupShift = metrics.sup1; 13034 } else if (options.style.cramped) { 13035 minSupShift = metrics.sup3; 13036 } else { 13037 minSupShift = metrics.sup2; 13038 } // scriptspace is a font-size-independent size, so scale it 13039 // appropriately for use as the marginRight. 13040 13041 13042 const multiplier = options.sizeMultiplier; 13043 const marginRight = 0.5 / metrics.ptPerEm / multiplier + "em"; 13044 let marginLeft = null; 13045 13046 if (subm) { 13047 // Subscripts shouldn't be shifted by the base's italic correction. 13048 // Account for that by shifting the subscript back the appropriate 13049 // amount. Note we only do this when the base is a single symbol. 13050 const isOiint = group.base && group.base.type === "op" && group.base.name && (group.base.name === "\\oiint" || group.base.name === "\\oiiint"); 13051 13052 if (base instanceof SymbolNode || isOiint) { 13053 // $FlowFixMe 13054 marginLeft = -base.italic + "em"; 13055 } 13056 } 13057 13058 let supsub; 13059 13060 if (supm && subm) { 13061 supShift = Math.max(supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight); 13062 subShift = Math.max(subShift, metrics.sub2); 13063 const ruleWidth = metrics.defaultRuleThickness; // Rule 18e 13064 13065 const maxWidth = 4 * ruleWidth; 13066 13067 if (supShift - supm.depth - (subm.height - subShift) < maxWidth) { 13068 subShift = maxWidth - (supShift - supm.depth) + subm.height; 13069 const psi = 0.8 * metrics.xHeight - (supShift - supm.depth); 13070 13071 if (psi > 0) { 13072 supShift += psi; 13073 subShift -= psi; 13074 } 13075 } 13076 13077 const vlistElem = [{ 13078 type: "elem", 13079 elem: subm, 13080 shift: subShift, 13081 marginRight, 13082 marginLeft 13083 }, { 13084 type: "elem", 13085 elem: supm, 13086 shift: -supShift, 13087 marginRight 13088 }]; 13089 supsub = buildCommon.makeVList({ 13090 positionType: "individualShift", 13091 children: vlistElem 13092 }, options); 13093 } else if (subm) { 13094 // Rule 18b 13095 subShift = Math.max(subShift, metrics.sub1, subm.height - 0.8 * metrics.xHeight); 13096 const vlistElem = [{ 13097 type: "elem", 13098 elem: subm, 13099 marginLeft, 13100 marginRight 13101 }]; 13102 supsub = buildCommon.makeVList({ 13103 positionType: "shift", 13104 positionData: subShift, 13105 children: vlistElem 13106 }, options); 13107 } else if (supm) { 13108 // Rule 18c, d 13109 supShift = Math.max(supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight); 13110 supsub = buildCommon.makeVList({ 13111 positionType: "shift", 13112 positionData: -supShift, 13113 children: [{ 13114 type: "elem", 13115 elem: supm, 13116 marginRight 13117 }] 13118 }, options); 13119 } else { 13120 throw new Error("supsub must have either sup or sub."); 13121 } // Wrap the supsub vlist in a span.msupsub to reset text-align. 13122 13123 13124 const mclass = getTypeOfDomTree(base, "right") || "mord"; 13125 return buildCommon.makeSpan([mclass], [base, buildCommon.makeSpan(["msupsub"], [supsub])], options); 13126 }, 13127 13128 mathmlBuilder(group, options) { 13129 // Is the inner group a relevant horizonal brace? 13130 let isBrace = false; 13131 let isOver; 13132 let isSup; 13133 const horizBrace = checkNodeType(group.base, "horizBrace"); 13134 13135 if (horizBrace) { 13136 isSup = !!group.sup; 13137 13138 if (isSup === horizBrace.isOver) { 13139 isBrace = true; 13140 isOver = horizBrace.isOver; 13141 } 13142 } 13143 13144 if (group.base && (group.base.type === "op" || group.base.type === "operatorname")) { 13145 group.base.parentIsSupSub = true; 13146 } 13147 13148 const children = [buildGroup$1(group.base, options)]; 13149 13150 if (group.sub) { 13151 children.push(buildGroup$1(group.sub, options)); 13152 } 13153 13154 if (group.sup) { 13155 children.push(buildGroup$1(group.sup, options)); 13156 } 13157 13158 let nodeType; 13159 13160 if (isBrace) { 13161 nodeType = isOver ? "mover" : "munder"; 13162 } else if (!group.sub) { 13163 const base = group.base; 13164 13165 if (base && base.type === "op" && base.limits && (options.style === Style$1.DISPLAY || base.alwaysHandleSupSub)) { 13166 nodeType = "mover"; 13167 } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (base.limits || options.style === Style$1.DISPLAY)) { 13168 nodeType = "mover"; 13169 } else { 13170 nodeType = "msup"; 13171 } 13172 } else if (!group.sup) { 13173 const base = group.base; 13174 13175 if (base && base.type === "op" && base.limits && (options.style === Style$1.DISPLAY || base.alwaysHandleSupSub)) { 13176 nodeType = "munder"; 13177 } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (base.limits || options.style === Style$1.DISPLAY)) { 13178 nodeType = "munder"; 13179 } else { 13180 nodeType = "msub"; 13181 } 13182 } else { 13183 const base = group.base; 13184 13185 if (base && base.type === "op" && base.limits && options.style === Style$1.DISPLAY) { 13186 nodeType = "munderover"; 13187 } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (options.style === Style$1.DISPLAY || base.limits)) { 13188 nodeType = "munderover"; 13189 } else { 13190 nodeType = "msubsup"; 13191 } 13192 } 13193 13194 const node = new mathMLTree.MathNode(nodeType, children); 13195 return node; 13196 } 13197 13198}); 13199 13200defineFunctionBuilders({ 13201 type: "atom", 13202 13203 htmlBuilder(group, options) { 13204 return buildCommon.mathsym(group.text, group.mode, options, ["m" + group.family]); 13205 }, 13206 13207 mathmlBuilder(group, options) { 13208 const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); 13209 13210 if (group.family === "bin") { 13211 const variant = getVariant(group, options); 13212 13213 if (variant === "bold-italic") { 13214 node.setAttribute("mathvariant", variant); 13215 } 13216 } else if (group.family === "punct") { 13217 node.setAttribute("separator", "true"); 13218 } else if (group.family === "open" || group.family === "close") { 13219 // Delims built here should not stretch vertically. 13220 // See delimsizing.js for stretchy delims. 13221 node.setAttribute("stretchy", "false"); 13222 } 13223 13224 return node; 13225 } 13226 13227}); 13228 13229// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in 13230const defaultVariant = { 13231 "mi": "italic", 13232 "mn": "normal", 13233 "mtext": "normal" 13234}; 13235defineFunctionBuilders({ 13236 type: "mathord", 13237 13238 htmlBuilder(group, options) { 13239 return buildCommon.makeOrd(group, options, "mathord"); 13240 }, 13241 13242 mathmlBuilder(group, options) { 13243 const node = new mathMLTree.MathNode("mi", [makeText(group.text, group.mode, options)]); 13244 const variant = getVariant(group, options) || "italic"; 13245 13246 if (variant !== defaultVariant[node.type]) { 13247 node.setAttribute("mathvariant", variant); 13248 } 13249 13250 return node; 13251 } 13252 13253}); 13254defineFunctionBuilders({ 13255 type: "textord", 13256 13257 htmlBuilder(group, options) { 13258 return buildCommon.makeOrd(group, options, "textord"); 13259 }, 13260 13261 mathmlBuilder(group, options) { 13262 const text = makeText(group.text, group.mode, options); 13263 const variant = getVariant(group, options) || "normal"; 13264 let node; 13265 13266 if (group.mode === 'text') { 13267 node = new mathMLTree.MathNode("mtext", [text]); 13268 } else if (/[0-9]/.test(group.text)) { 13269 // TODO(kevinb) merge adjacent <mn> nodes 13270 // do it as a post processing step 13271 node = new mathMLTree.MathNode("mn", [text]); 13272 } else if (group.text === "\\prime") { 13273 node = new mathMLTree.MathNode("mo", [text]); 13274 } else { 13275 node = new mathMLTree.MathNode("mi", [text]); 13276 } 13277 13278 if (variant !== defaultVariant[node.type]) { 13279 node.setAttribute("mathvariant", variant); 13280 } 13281 13282 return node; 13283 } 13284 13285}); 13286 13287const cssSpace = { 13288 "\\nobreak": "nobreak", 13289 "\\allowbreak": "allowbreak" 13290}; // A lookup table to determine whether a spacing function/symbol should be 13291// treated like a regular space character. If a symbol or command is a key 13292// in this table, then it should be a regular space character. Furthermore, 13293// the associated value may have a `className` specifying an extra CSS class 13294// to add to the created `span`. 13295 13296const regularSpace = { 13297 " ": {}, 13298 "\\ ": {}, 13299 "~": { 13300 className: "nobreak" 13301 }, 13302 "\\space": {}, 13303 "\\nobreakspace": { 13304 className: "nobreak" 13305 } 13306}; // ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in 13307// src/symbols.js. 13308 13309defineFunctionBuilders({ 13310 type: "spacing", 13311 13312 htmlBuilder(group, options) { 13313 if (regularSpace.hasOwnProperty(group.text)) { 13314 const className = regularSpace[group.text].className || ""; // Spaces are generated by adding an actual space. Each of these 13315 // things has an entry in the symbols table, so these will be turned 13316 // into appropriate outputs. 13317 13318 if (group.mode === "text") { 13319 const ord = buildCommon.makeOrd(group, options, "textord"); 13320 ord.classes.push(className); 13321 return ord; 13322 } else { 13323 return buildCommon.makeSpan(["mspace", className], [buildCommon.mathsym(group.text, group.mode, options)], options); 13324 } 13325 } else if (cssSpace.hasOwnProperty(group.text)) { 13326 // Spaces based on just a CSS class. 13327 return buildCommon.makeSpan(["mspace", cssSpace[group.text]], [], options); 13328 } else { 13329 throw new ParseError(`Unknown type of space "${group.text}"`); 13330 } 13331 }, 13332 13333 mathmlBuilder(group, options) { 13334 let node; 13335 13336 if (regularSpace.hasOwnProperty(group.text)) { 13337 node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); 13338 } else if (cssSpace.hasOwnProperty(group.text)) { 13339 // CSS-based MathML spaces (\nobreak, \allowbreak) are ignored 13340 return new mathMLTree.MathNode("mspace"); 13341 } else { 13342 throw new ParseError(`Unknown type of space "${group.text}"`); 13343 } 13344 13345 return node; 13346 } 13347 13348}); 13349 13350const pad = () => { 13351 const padNode = new mathMLTree.MathNode("mtd", []); 13352 padNode.setAttribute("width", "50%"); 13353 return padNode; 13354}; 13355 13356defineFunctionBuilders({ 13357 type: "tag", 13358 13359 mathmlBuilder(group, options) { 13360 const table = new mathMLTree.MathNode("mtable", [new mathMLTree.MathNode("mtr", [pad(), new mathMLTree.MathNode("mtd", [buildExpressionRow(group.body, options)]), pad(), new mathMLTree.MathNode("mtd", [buildExpressionRow(group.tag, options)])])]); 13361 table.setAttribute("width", "100%"); 13362 return table; // TODO: Left-aligned tags. 13363 // Currently, the group and options passed here do not contain 13364 // enough info to set tag alignment. `leqno` is in Settings but it is 13365 // not passed to Options. On the HTML side, leqno is 13366 // set by a CSS class applied in buildTree.js. That would have worked 13367 // in MathML if browsers supported <mlabeledtr>. Since they don't, we 13368 // need to rewrite the way this function is called. 13369 } 13370 13371}); 13372 13373const textFontFamilies = { 13374 "\\text": undefined, 13375 "\\textrm": "textrm", 13376 "\\textsf": "textsf", 13377 "\\texttt": "texttt", 13378 "\\textnormal": "textrm" 13379}; 13380const textFontWeights = { 13381 "\\textbf": "textbf", 13382 "\\textmd": "textmd" 13383}; 13384const textFontShapes = { 13385 "\\textit": "textit", 13386 "\\textup": "textup" 13387}; 13388 13389const optionsWithFont = (group, options) => { 13390 const font = group.font; // Checks if the argument is a font family or a font style. 13391 13392 if (!font) { 13393 return options; 13394 } else if (textFontFamilies[font]) { 13395 return options.withTextFontFamily(textFontFamilies[font]); 13396 } else if (textFontWeights[font]) { 13397 return options.withTextFontWeight(textFontWeights[font]); 13398 } else { 13399 return options.withTextFontShape(textFontShapes[font]); 13400 } 13401}; 13402 13403defineFunction({ 13404 type: "text", 13405 names: [// Font families 13406 "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal", // Font weights 13407 "\\textbf", "\\textmd", // Font Shapes 13408 "\\textit", "\\textup"], 13409 props: { 13410 numArgs: 1, 13411 argTypes: ["text"], 13412 greediness: 2, 13413 allowedInText: true 13414 }, 13415 13416 handler(_ref, args) { 13417 let parser = _ref.parser, 13418 funcName = _ref.funcName; 13419 const body = args[0]; 13420 return { 13421 type: "text", 13422 mode: parser.mode, 13423 body: ordargument(body), 13424 font: funcName 13425 }; 13426 }, 13427 13428 htmlBuilder(group, options) { 13429 const newOptions = optionsWithFont(group, options); 13430 const inner = buildExpression(group.body, newOptions, true); 13431 return buildCommon.makeSpan(["mord", "text"], buildCommon.tryCombineChars(inner), newOptions); 13432 }, 13433 13434 mathmlBuilder(group, options) { 13435 const newOptions = optionsWithFont(group, options); 13436 return buildExpressionRow(group.body, newOptions); 13437 } 13438 13439}); 13440 13441defineFunction({ 13442 type: "underline", 13443 names: ["\\underline"], 13444 props: { 13445 numArgs: 1, 13446 allowedInText: true 13447 }, 13448 13449 handler(_ref, args) { 13450 let parser = _ref.parser; 13451 return { 13452 type: "underline", 13453 mode: parser.mode, 13454 body: args[0] 13455 }; 13456 }, 13457 13458 htmlBuilder(group, options) { 13459 // Underlines are handled in the TeXbook pg 443, Rule 10. 13460 // Build the inner group. 13461 const innerGroup = buildGroup(group.body, options); // Create the line to go below the body 13462 13463 const line = buildCommon.makeLineSpan("underline-line", options); // Generate the vlist, with the appropriate kerns 13464 13465 const defaultRuleThickness = options.fontMetrics().defaultRuleThickness; 13466 const vlist = buildCommon.makeVList({ 13467 positionType: "top", 13468 positionData: innerGroup.height, 13469 children: [{ 13470 type: "kern", 13471 size: defaultRuleThickness 13472 }, { 13473 type: "elem", 13474 elem: line 13475 }, { 13476 type: "kern", 13477 size: 3 * defaultRuleThickness 13478 }, { 13479 type: "elem", 13480 elem: innerGroup 13481 }] 13482 }, options); 13483 return buildCommon.makeSpan(["mord", "underline"], [vlist], options); 13484 }, 13485 13486 mathmlBuilder(group, options) { 13487 const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203e")]); 13488 operator.setAttribute("stretchy", "true"); 13489 const node = new mathMLTree.MathNode("munder", [buildGroup$1(group.body, options), operator]); 13490 node.setAttribute("accentunder", "true"); 13491 return node; 13492 } 13493 13494}); 13495 13496defineFunction({ 13497 type: "verb", 13498 names: ["\\verb"], 13499 props: { 13500 numArgs: 0, 13501 allowedInText: true 13502 }, 13503 13504 handler(context, args, optArgs) { 13505 // \verb and \verb* are dealt with directly in Parser.js. 13506 // If we end up here, it's because of a failure to match the two delimiters 13507 // in the regex in Lexer.js. LaTeX raises the following error when \verb is 13508 // terminated by end of line (or file). 13509 throw new ParseError("\\verb ended by end of line instead of matching delimiter"); 13510 }, 13511 13512 htmlBuilder(group, options) { 13513 const text = makeVerb(group); 13514 const body = []; // \verb enters text mode and therefore is sized like \textstyle 13515 13516 const newOptions = options.havingStyle(options.style.text()); 13517 13518 for (let i = 0; i < text.length; i++) { 13519 let c = text[i]; 13520 13521 if (c === '~') { 13522 c = '\\textasciitilde'; 13523 } 13524 13525 body.push(buildCommon.makeSymbol(c, "Typewriter-Regular", group.mode, newOptions, ["mord", "texttt"])); 13526 } 13527 13528 return buildCommon.makeSpan(["mord", "text"].concat(newOptions.sizingClasses(options)), buildCommon.tryCombineChars(body), newOptions); 13529 }, 13530 13531 mathmlBuilder(group, options) { 13532 const text = new mathMLTree.TextNode(makeVerb(group)); 13533 const node = new mathMLTree.MathNode("mtext", [text]); 13534 node.setAttribute("mathvariant", "monospace"); 13535 return node; 13536 } 13537 13538}); 13539/** 13540 * Converts verb group into body string. 13541 * 13542 * \verb* replaces each space with an open box \u2423 13543 * \verb replaces each space with a no-break space \xA0 13544 */ 13545 13546const makeVerb = group => group.body.replace(/ /g, group.star ? '\u2423' : '\xA0'); 13547 13548/** Include this to ensure that all functions are defined. */ 13549const functions = _functions; 13550 13551/** 13552 * The Lexer class handles tokenizing the input in various ways. Since our 13553 * parser expects us to be able to backtrack, the lexer allows lexing from any 13554 * given starting point. 13555 * 13556 * Its main exposed function is the `lex` function, which takes a position to 13557 * lex from and a type of token to lex. It defers to the appropriate `_innerLex` 13558 * function. 13559 * 13560 * The various `_innerLex` functions perform the actual lexing of different 13561 * kinds. 13562 */ 13563 13564/* The following tokenRegex 13565 * - matches typical whitespace (but not NBSP etc.) using its first group 13566 * - does not match any control character \x00-\x1f except whitespace 13567 * - does not match a bare backslash 13568 * - matches any ASCII character except those just mentioned 13569 * - does not match the BMP private use area \uE000-\uF8FF 13570 * - does not match bare surrogate code units 13571 * - matches any BMP character except for those just described 13572 * - matches any valid Unicode surrogate pair 13573 * - matches a backslash followed by one or more letters 13574 * - matches a backslash followed by any BMP character, including newline 13575 * Just because the Lexer matches something doesn't mean it's valid input: 13576 * If there is no matching function or symbol definition, the Parser will 13577 * still reject the input. 13578 */ 13579const spaceRegexString = "[ \r\n\t]"; 13580const controlWordRegexString = "\\\\[a-zA-Z@]+"; 13581const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; 13582const controlWordWhitespaceRegexString = `${controlWordRegexString}${spaceRegexString}*`; 13583const controlWordWhitespaceRegex = new RegExp(`^(${controlWordRegexString})${spaceRegexString}*$`); 13584const combiningDiacriticalMarkString = "[\u0300-\u036f]"; 13585const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); 13586const tokenRegexString = `(${spaceRegexString}+)|` + // whitespace 13587"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint 13588`${combiningDiacriticalMarkString}*` + // ...plus accents 13589"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair 13590`${combiningDiacriticalMarkString}*` + // ...plus accents 13591"|\\\\verb\\*([^]).*?\\3" + // \verb* 13592"|\\\\verb([^*a-zA-Z]).*?\\4" + // \verb unstarred 13593"|\\\\operatorname\\*" + // \operatorname* 13594`|${controlWordWhitespaceRegexString}` + // \macroName + spaces 13595`|${controlSymbolRegexString})`; // \\, \', etc. 13596 13597/** Main Lexer class */ 13598 13599class Lexer { 13600 // category codes, only supports comment characters (14) for now 13601 constructor(input, settings) { 13602 this.input = void 0; 13603 this.settings = void 0; 13604 this.tokenRegex = void 0; 13605 this.catcodes = void 0; 13606 // Separate accents from characters 13607 this.input = input; 13608 this.settings = settings; 13609 this.tokenRegex = new RegExp(tokenRegexString, 'g'); 13610 this.catcodes = { 13611 "%": 14 // comment character 13612 13613 }; 13614 } 13615 13616 setCatcode(char, code) { 13617 this.catcodes[char] = code; 13618 } 13619 /** 13620 * This function lexes a single token. 13621 */ 13622 13623 13624 lex() { 13625 const input = this.input; 13626 const pos = this.tokenRegex.lastIndex; 13627 13628 if (pos === input.length) { 13629 return new Token("EOF", new SourceLocation(this, pos, pos)); 13630 } 13631 13632 const match = this.tokenRegex.exec(input); 13633 13634 if (match === null || match.index !== pos) { 13635 throw new ParseError(`Unexpected character: '${input[pos]}'`, new Token(input[pos], new SourceLocation(this, pos, pos + 1))); 13636 } 13637 13638 let text = match[2] || " "; 13639 13640 if (this.catcodes[text] === 14) { 13641 // comment character 13642 const nlIndex = input.indexOf('\n', this.tokenRegex.lastIndex); 13643 13644 if (nlIndex === -1) { 13645 this.tokenRegex.lastIndex = input.length; // EOF 13646 13647 this.settings.reportNonstrict("commentAtEnd", "% comment has no terminating newline; LaTeX would " + "fail because of commenting the end of math mode (e.g. $)"); 13648 } else { 13649 this.tokenRegex.lastIndex = nlIndex + 1; 13650 } 13651 13652 return this.lex(); 13653 } // Trim any trailing whitespace from control word match 13654 13655 13656 const controlMatch = text.match(controlWordWhitespaceRegex); 13657 13658 if (controlMatch) { 13659 text = controlMatch[1]; 13660 } 13661 13662 return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); 13663 } 13664 13665} 13666 13667/** 13668 * A `Namespace` refers to a space of nameable things like macros or lengths, 13669 * which can be `set` either globally or local to a nested group, using an 13670 * undo stack similar to how TeX implements this functionality. 13671 * Performance-wise, `get` and local `set` take constant time, while global 13672 * `set` takes time proportional to the depth of group nesting. 13673 */ 13674class Namespace { 13675 /** 13676 * Both arguments are optional. The first argument is an object of 13677 * built-in mappings which never change. The second argument is an object 13678 * of initial (global-level) mappings, which will constantly change 13679 * according to any global/top-level `set`s done. 13680 */ 13681 constructor(builtins, globalMacros) { 13682 if (builtins === void 0) { 13683 builtins = {}; 13684 } 13685 13686 if (globalMacros === void 0) { 13687 globalMacros = {}; 13688 } 13689 13690 this.current = void 0; 13691 this.builtins = void 0; 13692 this.undefStack = void 0; 13693 this.current = globalMacros; 13694 this.builtins = builtins; 13695 this.undefStack = []; 13696 } 13697 /** 13698 * Start a new nested group, affecting future local `set`s. 13699 */ 13700 13701 13702 beginGroup() { 13703 this.undefStack.push({}); 13704 } 13705 /** 13706 * End current nested group, restoring values before the group began. 13707 */ 13708 13709 13710 endGroup() { 13711 if (this.undefStack.length === 0) { 13712 throw new ParseError("Unbalanced namespace destruction: attempt " + "to pop global namespace; please report this as a bug"); 13713 } 13714 13715 const undefs = this.undefStack.pop(); 13716 13717 for (const undef in undefs) { 13718 if (undefs.hasOwnProperty(undef)) { 13719 if (undefs[undef] === undefined) { 13720 delete this.current[undef]; 13721 } else { 13722 this.current[undef] = undefs[undef]; 13723 } 13724 } 13725 } 13726 } 13727 /** 13728 * Detect whether `name` has a definition. Equivalent to 13729 * `get(name) != null`. 13730 */ 13731 13732 13733 has(name) { 13734 return this.current.hasOwnProperty(name) || this.builtins.hasOwnProperty(name); 13735 } 13736 /** 13737 * Get the current value of a name, or `undefined` if there is no value. 13738 * 13739 * Note: Do not use `if (namespace.get(...))` to detect whether a macro 13740 * is defined, as the definition may be the empty string which evaluates 13741 * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or 13742 * `if (namespace.has(...))`. 13743 */ 13744 13745 13746 get(name) { 13747 if (this.current.hasOwnProperty(name)) { 13748 return this.current[name]; 13749 } else { 13750 return this.builtins[name]; 13751 } 13752 } 13753 /** 13754 * Set the current value of a name, and optionally set it globally too. 13755 * Local set() sets the current value and (when appropriate) adds an undo 13756 * operation to the undo stack. Global set() may change the undo 13757 * operation at every level, so takes time linear in their number. 13758 */ 13759 13760 13761 set(name, value, global) { 13762 if (global === void 0) { 13763 global = false; 13764 } 13765 13766 if (global) { 13767 // Global set is equivalent to setting in all groups. Simulate this 13768 // by destroying any undos currently scheduled for this name, 13769 // and adding an undo with the *new* value (in case it later gets 13770 // locally reset within this environment). 13771 for (let i = 0; i < this.undefStack.length; i++) { 13772 delete this.undefStack[i][name]; 13773 } 13774 13775 if (this.undefStack.length > 0) { 13776 this.undefStack[this.undefStack.length - 1][name] = value; 13777 } 13778 } else { 13779 // Undo this set at end of this group (possibly to `undefined`), 13780 // unless an undo is already in place, in which case that older 13781 // value is the correct one. 13782 const top = this.undefStack[this.undefStack.length - 1]; 13783 13784 if (top && !top.hasOwnProperty(name)) { 13785 top[name] = this.current[name]; 13786 } 13787 } 13788 13789 this.current[name] = value; 13790 } 13791 13792} 13793 13794/** 13795 * Predefined macros for KaTeX. 13796 * This can be used to define some commands in terms of others. 13797 */ 13798const builtinMacros = {}; 13799 13800function defineMacro(name, body) { 13801 builtinMacros[name] = body; 13802} ////////////////////////////////////////////////////////////////////// 13803// macro tools 13804// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 13805// TeX source: \long\def\@firstoftwo#1#2{#1} 13806 13807defineMacro("\\@firstoftwo", function (context) { 13808 const args = context.consumeArgs(2); 13809 return { 13810 tokens: args[0], 13811 numArgs: 0 13812 }; 13813}); // LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 13814// TeX source: \long\def\@secondoftwo#1#2{#2} 13815 13816defineMacro("\\@secondoftwo", function (context) { 13817 const args = context.consumeArgs(2); 13818 return { 13819 tokens: args[1], 13820 numArgs: 0 13821 }; 13822}); // LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) 13823// symbol. If it matches #1, then the macro expands to #2; otherwise, #3. 13824// Note, however, that it does not consume the next symbol in either case. 13825 13826defineMacro("\\@ifnextchar", function (context) { 13827 const args = context.consumeArgs(3); // symbol, if, else 13828 13829 const nextToken = context.future(); 13830 13831 if (args[0].length === 1 && args[0][0].text === nextToken.text) { 13832 return { 13833 tokens: args[1], 13834 numArgs: 0 13835 }; 13836 } else { 13837 return { 13838 tokens: args[2], 13839 numArgs: 0 13840 }; 13841 } 13842}); // LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. 13843// If it is `*`, then it consumes the symbol, and the macro expands to #1; 13844// otherwise, the macro expands to #2 (without consuming the symbol). 13845// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} 13846 13847defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); // LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode 13848 13849defineMacro("\\TextOrMath", function (context) { 13850 const args = context.consumeArgs(2); 13851 13852 if (context.mode === 'text') { 13853 return { 13854 tokens: args[0], 13855 numArgs: 0 13856 }; 13857 } else { 13858 return { 13859 tokens: args[1], 13860 numArgs: 0 13861 }; 13862 } 13863}); // Lookup table for parsing numbers in base 8 through 16 13864 13865const digitToNumber = { 13866 "0": 0, 13867 "1": 1, 13868 "2": 2, 13869 "3": 3, 13870 "4": 4, 13871 "5": 5, 13872 "6": 6, 13873 "7": 7, 13874 "8": 8, 13875 "9": 9, 13876 "a": 10, 13877 "A": 10, 13878 "b": 11, 13879 "B": 11, 13880 "c": 12, 13881 "C": 12, 13882 "d": 13, 13883 "D": 13, 13884 "e": 14, 13885 "E": 14, 13886 "f": 15, 13887 "F": 15 13888}; // TeX \char makes a literal character (catcode 12) using the following forms: 13889// (see The TeXBook, p. 43) 13890// \char123 -- decimal 13891// \char'123 -- octal 13892// \char"123 -- hex 13893// \char`x -- character that can be written (i.e. isn't active) 13894// \char`\x -- character that cannot be written (e.g. %) 13895// These all refer to characters from the font, so we turn them into special 13896// calls to a function \@char dealt with in the Parser. 13897 13898defineMacro("\\char", function (context) { 13899 let token = context.popToken(); 13900 let base; 13901 let number = ''; 13902 13903 if (token.text === "'") { 13904 base = 8; 13905 token = context.popToken(); 13906 } else if (token.text === '"') { 13907 base = 16; 13908 token = context.popToken(); 13909 } else if (token.text === "`") { 13910 token = context.popToken(); 13911 13912 if (token.text[0] === "\\") { 13913 number = token.text.charCodeAt(1); 13914 } else if (token.text === "EOF") { 13915 throw new ParseError("\\char` missing argument"); 13916 } else { 13917 number = token.text.charCodeAt(0); 13918 } 13919 } else { 13920 base = 10; 13921 } 13922 13923 if (base) { 13924 // Parse a number in the given base, starting with first `token`. 13925 number = digitToNumber[token.text]; 13926 13927 if (number == null || number >= base) { 13928 throw new ParseError(`Invalid base-${base} digit ${token.text}`); 13929 } 13930 13931 let digit; 13932 13933 while ((digit = digitToNumber[context.future().text]) != null && digit < base) { 13934 number *= base; 13935 number += digit; 13936 context.popToken(); 13937 } 13938 } 13939 13940 return `\\@char{${number}}`; 13941}); // Basic support for macro definitions: 13942// \def\macro{expansion} 13943// \def\macro#1{expansion} 13944// \def\macro#1#2{expansion} 13945// \def\macro#1#2#3#4#5#6#7#8#9{expansion} 13946// Also the \gdef and \global\def equivalents 13947 13948const def = (context, global) => { 13949 let arg = context.consumeArgs(1)[0]; 13950 13951 if (arg.length !== 1) { 13952 throw new ParseError("\\gdef's first argument must be a macro name"); 13953 } 13954 13955 const name = arg[0].text; // Count argument specifiers, and check they are in the order #1 #2 ... 13956 13957 let numArgs = 0; 13958 arg = context.consumeArgs(1)[0]; 13959 13960 while (arg.length === 1 && arg[0].text === "#") { 13961 arg = context.consumeArgs(1)[0]; 13962 13963 if (arg.length !== 1) { 13964 throw new ParseError(`Invalid argument number length "${arg.length}"`); 13965 } 13966 13967 if (!/^[1-9]$/.test(arg[0].text)) { 13968 throw new ParseError(`Invalid argument number "${arg[0].text}"`); 13969 } 13970 13971 numArgs++; 13972 13973 if (parseInt(arg[0].text) !== numArgs) { 13974 throw new ParseError(`Argument number "${arg[0].text}" out of order`); 13975 } 13976 13977 arg = context.consumeArgs(1)[0]; 13978 } // Final arg is the expansion of the macro 13979 13980 13981 context.macros.set(name, { 13982 tokens: arg, 13983 numArgs 13984 }, global); 13985 return ''; 13986}; 13987 13988defineMacro("\\gdef", context => def(context, true)); 13989defineMacro("\\def", context => def(context, false)); 13990defineMacro("\\global", context => { 13991 const next = context.consumeArgs(1)[0]; 13992 13993 if (next.length !== 1) { 13994 throw new ParseError("Invalid command after \\global"); 13995 } 13996 13997 const command = next[0].text; // TODO: Should expand command 13998 13999 if (command === "\\def") { 14000 // \global\def is equivalent to \gdef 14001 return def(context, true); 14002 } else { 14003 throw new ParseError(`Invalid command '${command}' after \\global`); 14004 } 14005}); // \newcommand{\macro}[args]{definition} 14006// \renewcommand{\macro}[args]{definition} 14007// TODO: Optional arguments: \newcommand{\macro}[args][default]{definition} 14008 14009const newcommand = (context, existsOK, nonexistsOK) => { 14010 let arg = context.consumeArgs(1)[0]; 14011 14012 if (arg.length !== 1) { 14013 throw new ParseError("\\newcommand's first argument must be a macro name"); 14014 } 14015 14016 const name = arg[0].text; 14017 const exists = context.isDefined(name); 14018 14019 if (exists && !existsOK) { 14020 throw new ParseError(`\\newcommand{${name}} attempting to redefine ` + `${name}; use \\renewcommand`); 14021 } 14022 14023 if (!exists && !nonexistsOK) { 14024 throw new ParseError(`\\renewcommand{${name}} when command ${name} ` + `does not yet exist; use \\newcommand`); 14025 } 14026 14027 let numArgs = 0; 14028 arg = context.consumeArgs(1)[0]; 14029 14030 if (arg.length === 1 && arg[0].text === "[") { 14031 let argText = ''; 14032 let token = context.expandNextToken(); 14033 14034 while (token.text !== "]" && token.text !== "EOF") { 14035 // TODO: Should properly expand arg, e.g., ignore {}s 14036 argText += token.text; 14037 token = context.expandNextToken(); 14038 } 14039 14040 if (!argText.match(/^\s*[0-9]+\s*$/)) { 14041 throw new ParseError(`Invalid number of arguments: ${argText}`); 14042 } 14043 14044 numArgs = parseInt(argText); 14045 arg = context.consumeArgs(1)[0]; 14046 } // Final arg is the expansion of the macro 14047 14048 14049 context.macros.set(name, { 14050 tokens: arg, 14051 numArgs 14052 }); 14053 return ''; 14054}; 14055 14056defineMacro("\\newcommand", context => newcommand(context, false, true)); 14057defineMacro("\\renewcommand", context => newcommand(context, true, false)); 14058defineMacro("\\providecommand", context => newcommand(context, true, true)); ////////////////////////////////////////////////////////////////////// 14059// Grouping 14060// \let\bgroup={ \let\egroup=} 14061 14062defineMacro("\\bgroup", "{"); 14063defineMacro("\\egroup", "}"); // Symbols from latex.ltx: 14064// \def\lq{`} 14065// \def\rq{'} 14066// \def \aa {\r a} 14067// \def \AA {\r A} 14068 14069defineMacro("\\lq", "`"); 14070defineMacro("\\rq", "'"); 14071defineMacro("\\aa", "\\r a"); 14072defineMacro("\\AA", "\\r A"); // Copyright (C) and registered (R) symbols. Use raw symbol in MathML. 14073// \DeclareTextCommandDefault{\textcopyright}{\textcircled{c}} 14074// \DeclareTextCommandDefault{\textregistered}{\textcircled{% 14075// \check@mathfonts\fontsize\sf@size\z@\math@fontsfalse\selectfont R}} 14076// \DeclareRobustCommand{\copyright}{% 14077// \ifmmode{\nfss@text{\textcopyright}}\else\textcopyright\fi} 14078 14079defineMacro("\\textcopyright", "\\html@mathml{\\textcircled{c}}{\\char`©}"); 14080defineMacro("\\copyright", "\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}"); 14081defineMacro("\\textregistered", "\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`®}"); // Characters omitted from Unicode range 1D400–1D7FF 14082 14083defineMacro("\u212C", "\\mathscr{B}"); // script 14084 14085defineMacro("\u2130", "\\mathscr{E}"); 14086defineMacro("\u2131", "\\mathscr{F}"); 14087defineMacro("\u210B", "\\mathscr{H}"); 14088defineMacro("\u2110", "\\mathscr{I}"); 14089defineMacro("\u2112", "\\mathscr{L}"); 14090defineMacro("\u2133", "\\mathscr{M}"); 14091defineMacro("\u211B", "\\mathscr{R}"); 14092defineMacro("\u212D", "\\mathfrak{C}"); // Fraktur 14093 14094defineMacro("\u210C", "\\mathfrak{H}"); 14095defineMacro("\u2128", "\\mathfrak{Z}"); // Define \Bbbk with a macro that works in both HTML and MathML. 14096 14097defineMacro("\\Bbbk", "\\Bbb{k}"); // Unicode middle dot 14098// The KaTeX fonts do not contain U+00B7. Instead, \cdotp displays 14099// the dot at U+22C5 and gives it punct spacing. 14100 14101defineMacro("\u00b7", "\\cdotp"); // \llap and \rlap render their contents in text mode 14102 14103defineMacro("\\llap", "\\mathllap{\\textrm{#1}}"); 14104defineMacro("\\rlap", "\\mathrlap{\\textrm{#1}}"); 14105defineMacro("\\clap", "\\mathclap{\\textrm{#1}}"); // \not is defined by base/fontmath.ltx via 14106// \DeclareMathSymbol{\not}{\mathrel}{symbols}{"36} 14107// It's thus treated like a \mathrel, but defined by a symbol that has zero 14108// width but extends to the right. We use \rlap to get that spacing. 14109// For MathML we write U+0338 here. buildMathML.js will then do the overlay. 14110 14111defineMacro("\\not", '\\html@mathml{\\mathrel{\\mathrlap\\@not}}{\\char"338}'); // Negated symbols from base/fontmath.ltx: 14112// \def\neq{\not=} \let\ne=\neq 14113// \DeclareRobustCommand 14114// \notin{\mathrel{\m@th\mathpalette\c@ncel\in}} 14115// \def\c@ncel#1#2{\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}} 14116 14117defineMacro("\\neq", "\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}"); 14118defineMacro("\\ne", "\\neq"); 14119defineMacro("\u2260", "\\neq"); 14120defineMacro("\\notin", "\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}" + "{\\mathrel{\\char`∉}}"); 14121defineMacro("\u2209", "\\notin"); // Unicode stacked relations 14122 14123defineMacro("\u2258", "\\html@mathml{" + "\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}" + "}{\\mathrel{\\char`\u2258}}"); 14124defineMacro("\u2259", "\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`\u2258}}"); 14125defineMacro("\u225A", "\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`\u225A}}"); 14126defineMacro("\u225B", "\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}" + "{\\mathrel{\\char`\u225B}}"); 14127defineMacro("\u225D", "\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}" + "{\\mathrel{\\char`\u225D}}"); 14128defineMacro("\u225E", "\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}" + "{\\mathrel{\\char`\u225E}}"); 14129defineMacro("\u225F", "\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`\u225F}}"); // Misc Unicode 14130 14131defineMacro("\u27C2", "\\perp"); 14132defineMacro("\u203C", "\\mathclose{!\\mkern-0.8mu!}"); 14133defineMacro("\u220C", "\\notni"); 14134defineMacro("\u231C", "\\ulcorner"); 14135defineMacro("\u231D", "\\urcorner"); 14136defineMacro("\u231E", "\\llcorner"); 14137defineMacro("\u231F", "\\lrcorner"); 14138defineMacro("\u00A9", "\\copyright"); 14139defineMacro("\u00AE", "\\textregistered"); 14140defineMacro("\uFE0F", "\\textregistered"); ////////////////////////////////////////////////////////////////////// 14141// LaTeX_2ε 14142// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ 14143// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} 14144// We'll call \varvdots, which gets a glyph from symbols.js. 14145// The zero-width rule gets us an equivalent to the vertical 6pt kern. 14146 14147defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); 14148defineMacro("\u22ee", "\\vdots"); ////////////////////////////////////////////////////////////////////// 14149// amsmath.sty 14150// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf 14151// Italic Greek capital letters. AMS defines these with \DeclareMathSymbol, 14152// but they are equivalent to \mathit{\Letter}. 14153 14154defineMacro("\\varGamma", "\\mathit{\\Gamma}"); 14155defineMacro("\\varDelta", "\\mathit{\\Delta}"); 14156defineMacro("\\varTheta", "\\mathit{\\Theta}"); 14157defineMacro("\\varLambda", "\\mathit{\\Lambda}"); 14158defineMacro("\\varXi", "\\mathit{\\Xi}"); 14159defineMacro("\\varPi", "\\mathit{\\Pi}"); 14160defineMacro("\\varSigma", "\\mathit{\\Sigma}"); 14161defineMacro("\\varUpsilon", "\\mathit{\\Upsilon}"); 14162defineMacro("\\varPhi", "\\mathit{\\Phi}"); 14163defineMacro("\\varPsi", "\\mathit{\\Psi}"); 14164defineMacro("\\varOmega", "\\mathit{\\Omega}"); //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} 14165 14166defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); // \renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript 14167// \mkern-\thinmuskip{:}\mskip6muplus1mu\relax} 14168 14169defineMacro("\\colon", "\\nobreak\\mskip2mu\\mathpunct{}" + "\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu"); // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} 14170 14171defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); // \def\iff{\DOTSB\;\Longleftrightarrow\;} 14172// \def\implies{\DOTSB\;\Longrightarrow\;} 14173// \def\impliedby{\DOTSB\;\Longleftarrow\;} 14174 14175defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); 14176defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); 14177defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); // AMSMath's automatic \dots, based on \mdots@@ macro. 14178 14179const dotsByToken = { 14180 ',': '\\dotsc', 14181 '\\not': '\\dotsb', 14182 // \keybin@ checks for the following: 14183 '+': '\\dotsb', 14184 '=': '\\dotsb', 14185 '<': '\\dotsb', 14186 '>': '\\dotsb', 14187 '-': '\\dotsb', 14188 '*': '\\dotsb', 14189 ':': '\\dotsb', 14190 // Symbols whose definition starts with \DOTSB: 14191 '\\DOTSB': '\\dotsb', 14192 '\\coprod': '\\dotsb', 14193 '\\bigvee': '\\dotsb', 14194 '\\bigwedge': '\\dotsb', 14195 '\\biguplus': '\\dotsb', 14196 '\\bigcap': '\\dotsb', 14197 '\\bigcup': '\\dotsb', 14198 '\\prod': '\\dotsb', 14199 '\\sum': '\\dotsb', 14200 '\\bigotimes': '\\dotsb', 14201 '\\bigoplus': '\\dotsb', 14202 '\\bigodot': '\\dotsb', 14203 '\\bigsqcup': '\\dotsb', 14204 '\\And': '\\dotsb', 14205 '\\longrightarrow': '\\dotsb', 14206 '\\Longrightarrow': '\\dotsb', 14207 '\\longleftarrow': '\\dotsb', 14208 '\\Longleftarrow': '\\dotsb', 14209 '\\longleftrightarrow': '\\dotsb', 14210 '\\Longleftrightarrow': '\\dotsb', 14211 '\\mapsto': '\\dotsb', 14212 '\\longmapsto': '\\dotsb', 14213 '\\hookrightarrow': '\\dotsb', 14214 '\\doteq': '\\dotsb', 14215 // Symbols whose definition starts with \mathbin: 14216 '\\mathbin': '\\dotsb', 14217 // Symbols whose definition starts with \mathrel: 14218 '\\mathrel': '\\dotsb', 14219 '\\relbar': '\\dotsb', 14220 '\\Relbar': '\\dotsb', 14221 '\\xrightarrow': '\\dotsb', 14222 '\\xleftarrow': '\\dotsb', 14223 // Symbols whose definition starts with \DOTSI: 14224 '\\DOTSI': '\\dotsi', 14225 '\\int': '\\dotsi', 14226 '\\oint': '\\dotsi', 14227 '\\iint': '\\dotsi', 14228 '\\iiint': '\\dotsi', 14229 '\\iiiint': '\\dotsi', 14230 '\\idotsint': '\\dotsi', 14231 // Symbols whose definition starts with \DOTSX: 14232 '\\DOTSX': '\\dotsx' 14233}; 14234defineMacro("\\dots", function (context) { 14235 // TODO: If used in text mode, should expand to \textellipsis. 14236 // However, in KaTeX, \textellipsis and \ldots behave the same 14237 // (in text mode), and it's unlikely we'd see any of the math commands 14238 // that affect the behavior of \dots when in text mode. So fine for now 14239 // (until we support \ifmmode ... \else ... \fi). 14240 let thedots = '\\dotso'; 14241 const next = context.expandAfterFuture().text; 14242 14243 if (next in dotsByToken) { 14244 thedots = dotsByToken[next]; 14245 } else if (next.substr(0, 4) === '\\not') { 14246 thedots = '\\dotsb'; 14247 } else if (next in symbols.math) { 14248 if (utils.contains(['bin', 'rel'], symbols.math[next].group)) { 14249 thedots = '\\dotsb'; 14250 } 14251 } 14252 14253 return thedots; 14254}); 14255const spaceAfterDots = { 14256 // \rightdelim@ checks for the following: 14257 ')': true, 14258 ']': true, 14259 '\\rbrack': true, 14260 '\\}': true, 14261 '\\rbrace': true, 14262 '\\rangle': true, 14263 '\\rceil': true, 14264 '\\rfloor': true, 14265 '\\rgroup': true, 14266 '\\rmoustache': true, 14267 '\\right': true, 14268 '\\bigr': true, 14269 '\\biggr': true, 14270 '\\Bigr': true, 14271 '\\Biggr': true, 14272 // \extra@ also tests for the following: 14273 '$': true, 14274 // \extrap@ checks for the following: 14275 ';': true, 14276 '.': true, 14277 ',': true 14278}; 14279defineMacro("\\dotso", function (context) { 14280 const next = context.future().text; 14281 14282 if (next in spaceAfterDots) { 14283 return "\\ldots\\,"; 14284 } else { 14285 return "\\ldots"; 14286 } 14287}); 14288defineMacro("\\dotsc", function (context) { 14289 const next = context.future().text; // \dotsc uses \extra@ but not \extrap@, instead specially checking for 14290 // ';' and '.', but doesn't check for ','. 14291 14292 if (next in spaceAfterDots && next !== ',') { 14293 return "\\ldots\\,"; 14294 } else { 14295 return "\\ldots"; 14296 } 14297}); 14298defineMacro("\\cdots", function (context) { 14299 const next = context.future().text; 14300 14301 if (next in spaceAfterDots) { 14302 return "\\@cdots\\,"; 14303 } else { 14304 return "\\@cdots"; 14305 } 14306}); 14307defineMacro("\\dotsb", "\\cdots"); 14308defineMacro("\\dotsm", "\\cdots"); 14309defineMacro("\\dotsi", "\\!\\cdots"); // amsmath doesn't actually define \dotsx, but \dots followed by a macro 14310// starting with \DOTSX implies \dotso, and then \extra@ detects this case 14311// and forces the added `\,`. 14312 14313defineMacro("\\dotsx", "\\ldots\\,"); // \let\DOTSI\relax 14314// \let\DOTSB\relax 14315// \let\DOTSX\relax 14316 14317defineMacro("\\DOTSI", "\\relax"); 14318defineMacro("\\DOTSB", "\\relax"); 14319defineMacro("\\DOTSX", "\\relax"); // Spacing, based on amsmath.sty's override of LaTeX defaults 14320// \DeclareRobustCommand{\tmspace}[3]{% 14321// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} 14322 14323defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); // \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} 14324// TODO: math mode should use \thinmuskip 14325 14326defineMacro("\\,", "\\tmspace+{3mu}{.1667em}"); // \let\thinspace\, 14327 14328defineMacro("\\thinspace", "\\,"); // \def\>{\mskip\medmuskip} 14329// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} 14330// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu 14331 14332defineMacro("\\>", "\\mskip{4mu}"); 14333defineMacro("\\:", "\\tmspace+{4mu}{.2222em}"); // \let\medspace\: 14334 14335defineMacro("\\medspace", "\\:"); // \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} 14336// TODO: math mode should use \thickmuskip = 5mu plus 5mu 14337 14338defineMacro("\\;", "\\tmspace+{5mu}{.2777em}"); // \let\thickspace\; 14339 14340defineMacro("\\thickspace", "\\;"); // \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} 14341// TODO: math mode should use \thinmuskip 14342 14343defineMacro("\\!", "\\tmspace-{3mu}{.1667em}"); // \let\negthinspace\! 14344 14345defineMacro("\\negthinspace", "\\!"); // \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} 14346// TODO: math mode should use \medmuskip 14347 14348defineMacro("\\negmedspace", "\\tmspace-{4mu}{.2222em}"); // \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} 14349// TODO: math mode should use \thickmuskip 14350 14351defineMacro("\\negthickspace", "\\tmspace-{5mu}{.277em}"); // \def\enspace{\kern.5em } 14352 14353defineMacro("\\enspace", "\\kern.5em "); // \def\enskip{\hskip.5em\relax} 14354 14355defineMacro("\\enskip", "\\hskip.5em\\relax"); // \def\quad{\hskip1em\relax} 14356 14357defineMacro("\\quad", "\\hskip1em\\relax"); // \def\qquad{\hskip2em\relax} 14358 14359defineMacro("\\qquad", "\\hskip2em\\relax"); // \tag@in@display form of \tag 14360 14361defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); 14362defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); 14363defineMacro("\\tag@literal", context => { 14364 if (context.macros.get("\\df@tag")) { 14365 throw new ParseError("Multiple \\tag"); 14366 } 14367 14368 return "\\gdef\\df@tag{\\text{#1}}"; 14369}); // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin 14370// {\operator@font mod}\penalty900 14371// \mkern5mu\nonscript\mskip-\medmuskip} 14372// \newcommand{\pod}[1]{\allowbreak 14373// \if@display\mkern18mu\else\mkern8mu\fi(#1)} 14374// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} 14375// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu 14376// \else\mkern12mu\fi{\operator@font mod}\,\,#1} 14377// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu 14378 14379defineMacro("\\bmod", "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}" + "\\mathbin{\\rm mod}" + "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"); 14380defineMacro("\\pod", "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"); 14381defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); 14382defineMacro("\\mod", "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + "{\\rm mod}\\,\\,#1"); // \pmb -- A simulation of bold. 14383// The version in ambsy.sty works by typesetting three copies of the argument 14384// with small offsets. We use two copies. We omit the vertical offset because 14385// of rendering problems that makeVList encounters in Safari. 14386 14387defineMacro("\\pmb", "\\html@mathml{" + "\\@binrel{#1}{\\mathrlap{#1}\\kern0.5px#1}}" + "{\\mathbf{#1}}"); ////////////////////////////////////////////////////////////////////// 14388// LaTeX source2e 14389// \\ defaults to \newline, but changes to \cr within array environment 14390 14391defineMacro("\\\\", "\\newline"); // \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} 14392// TODO: Doesn't normally work in math mode because \@ fails. KaTeX doesn't 14393// support \@ yet, so that's omitted, and we add \text so that the result 14394// doesn't look funny in math mode. 14395 14396defineMacro("\\TeX", "\\textrm{\\html@mathml{" + "T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX" + "}{TeX}}"); // \DeclareRobustCommand{\LaTeX}{L\kern-.36em% 14397// {\sbox\z@ T% 14398// \vbox to\ht\z@{\hbox{\check@mathfonts 14399// \fontsize\sf@size\z@ 14400// \math@fontsfalse\selectfont 14401// A}% 14402// \vss}% 14403// }% 14404// \kern-.15em% 14405// \TeX} 14406// This code aligns the top of the A with the T (from the perspective of TeX's 14407// boxes, though visually the A appears to extend above slightly). 14408// We compute the corresponding \raisebox when A is rendered in \normalsize 14409// \scriptstyle, which has a scale factor of 0.7 (see Options.js). 14410 14411const latexRaiseA = metricMap['Main-Regular']["T".charCodeAt(0)][1] - 0.7 * metricMap['Main-Regular']["A".charCodeAt(0)][1] + "em"; 14412defineMacro("\\LaTeX", "\\textrm{\\html@mathml{" + `L\\kern-.36em\\raisebox{${latexRaiseA}}{\\scriptstyle A}` + "\\kern-.15em\\TeX}{LaTeX}}"); // New KaTeX logo based on tweaking LaTeX logo 14413 14414defineMacro("\\KaTeX", "\\textrm{\\html@mathml{" + `K\\kern-.17em\\raisebox{${latexRaiseA}}{\\scriptstyle A}` + "\\kern-.15em\\TeX}{KaTeX}}"); // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} 14415// \def\@hspace#1{\hskip #1\relax} 14416// \def\@hspacer#1{\vrule \@width\z@\nobreak 14417// \hskip #1\hskip \z@skip} 14418 14419defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); 14420defineMacro("\\@hspace", "\\hskip #1\\relax"); 14421defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); ////////////////////////////////////////////////////////////////////// 14422// mathtools.sty 14423//\providecommand\ordinarycolon{:} 14424 14425defineMacro("\\ordinarycolon", ":"); //\def\vcentcolon{\mathrel{\mathop\ordinarycolon}} 14426//TODO(edemaine): Not yet centered. Fix via \raisebox or #726 14427 14428defineMacro("\\vcentcolon", "\\mathrel{\\mathop\\ordinarycolon}"); // \providecommand*\dblcolon{\vcentcolon\mathrel{\mkern-.9mu}\vcentcolon} 14429 14430defineMacro("\\dblcolon", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}" + "{\\mathop{\\char\"2237}}"); // \providecommand*\coloneqq{\vcentcolon\mathrel{\mkern-1.2mu}=} 14431 14432defineMacro("\\coloneqq", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}" + "{\\mathop{\\char\"2254}}"); // ≔ 14433// \providecommand*\Coloneqq{\dblcolon\mathrel{\mkern-1.2mu}=} 14434 14435defineMacro("\\Coloneqq", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}" + "{\\mathop{\\char\"2237\\char\"3d}}"); // \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} 14436 14437defineMacro("\\coloneq", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" + "{\\mathop{\\char\"3a\\char\"2212}}"); // \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} 14438 14439defineMacro("\\Coloneq", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" + "{\\mathop{\\char\"2237\\char\"2212}}"); // \providecommand*\eqqcolon{=\mathrel{\mkern-1.2mu}\vcentcolon} 14440 14441defineMacro("\\eqqcolon", "\\html@mathml{" + "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" + "{\\mathop{\\char\"2255}}"); // ≕ 14442// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} 14443 14444defineMacro("\\Eqqcolon", "\\html@mathml{" + "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}" + "{\\mathop{\\char\"3d\\char\"2237}}"); // \providecommand*\eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\vcentcolon} 14445 14446defineMacro("\\eqcolon", "\\html@mathml{" + "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" + "{\\mathop{\\char\"2239}}"); // \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} 14447 14448defineMacro("\\Eqcolon", "\\html@mathml{" + "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}" + "{\\mathop{\\char\"2212\\char\"2237}}"); // \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} 14449 14450defineMacro("\\colonapprox", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}" + "{\\mathop{\\char\"3a\\char\"2248}}"); // \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} 14451 14452defineMacro("\\Colonapprox", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}" + "{\\mathop{\\char\"2237\\char\"2248}}"); // \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} 14453 14454defineMacro("\\colonsim", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}" + "{\\mathop{\\char\"3a\\char\"223c}}"); // \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} 14455 14456defineMacro("\\Colonsim", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}" + "{\\mathop{\\char\"2237\\char\"223c}}"); // Some Unicode characters are implemented with macros to mathtools functions. 14457 14458defineMacro("\u2237", "\\dblcolon"); // :: 14459 14460defineMacro("\u2239", "\\eqcolon"); // -: 14461 14462defineMacro("\u2254", "\\coloneqq"); // := 14463 14464defineMacro("\u2255", "\\eqqcolon"); // =: 14465 14466defineMacro("\u2A74", "\\Coloneqq"); // ::= 14467////////////////////////////////////////////////////////////////////// 14468// colonequals.sty 14469// Alternate names for mathtools's macros: 14470 14471defineMacro("\\ratio", "\\vcentcolon"); 14472defineMacro("\\coloncolon", "\\dblcolon"); 14473defineMacro("\\colonequals", "\\coloneqq"); 14474defineMacro("\\coloncolonequals", "\\Coloneqq"); 14475defineMacro("\\equalscolon", "\\eqqcolon"); 14476defineMacro("\\equalscoloncolon", "\\Eqqcolon"); 14477defineMacro("\\colonminus", "\\coloneq"); 14478defineMacro("\\coloncolonminus", "\\Coloneq"); 14479defineMacro("\\minuscolon", "\\eqcolon"); 14480defineMacro("\\minuscoloncolon", "\\Eqcolon"); // \colonapprox name is same in mathtools and colonequals. 14481 14482defineMacro("\\coloncolonapprox", "\\Colonapprox"); // \colonsim name is same in mathtools and colonequals. 14483 14484defineMacro("\\coloncolonsim", "\\Colonsim"); // Additional macros, implemented by analogy with mathtools definitions: 14485 14486defineMacro("\\simcolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"); 14487defineMacro("\\simcoloncolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"); 14488defineMacro("\\approxcolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"); 14489defineMacro("\\approxcoloncolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"); // Present in newtxmath, pxfonts and txfonts 14490 14491defineMacro("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220C}}"); 14492defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); 14493defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); ////////////////////////////////////////////////////////////////////// 14494// MathML alternates for KaTeX glyphs in the Unicode private area 14495 14496defineMacro("\\gvertneqq", "\\html@mathml{\\@gvertneqq}{\u2269}"); 14497defineMacro("\\lvertneqq", "\\html@mathml{\\@lvertneqq}{\u2268}"); 14498defineMacro("\\ngeqq", "\\html@mathml{\\@ngeqq}{\u2271}"); 14499defineMacro("\\ngeqslant", "\\html@mathml{\\@ngeqslant}{\u2271}"); 14500defineMacro("\\nleqq", "\\html@mathml{\\@nleqq}{\u2270}"); 14501defineMacro("\\nleqslant", "\\html@mathml{\\@nleqslant}{\u2270}"); 14502defineMacro("\\nshortmid", "\\html@mathml{\\@nshortmid}{∤}"); 14503defineMacro("\\nshortparallel", "\\html@mathml{\\@nshortparallel}{∦}"); 14504defineMacro("\\nsubseteqq", "\\html@mathml{\\@nsubseteqq}{\u2288}"); 14505defineMacro("\\nsupseteqq", "\\html@mathml{\\@nsupseteqq}{\u2289}"); 14506defineMacro("\\varsubsetneq", "\\html@mathml{\\@varsubsetneq}{⊊}"); 14507defineMacro("\\varsubsetneqq", "\\html@mathml{\\@varsubsetneqq}{⫋}"); 14508defineMacro("\\varsupsetneq", "\\html@mathml{\\@varsupsetneq}{⊋}"); 14509defineMacro("\\varsupsetneqq", "\\html@mathml{\\@varsupsetneqq}{⫌}"); ////////////////////////////////////////////////////////////////////// 14510// stmaryrd and semantic 14511// The stmaryrd and semantic packages render the next four items by calling a 14512// glyph. Those glyphs do not exist in the KaTeX fonts. Hence the macros. 14513 14514defineMacro("\\llbracket", "\\html@mathml{" + "\\mathopen{[\\mkern-3.2mu[}}" + "{\\mathopen{\\char`\u27e6}}"); 14515defineMacro("\\rrbracket", "\\html@mathml{" + "\\mathclose{]\\mkern-3.2mu]}}" + "{\\mathclose{\\char`\u27e7}}"); 14516defineMacro("\u27e6", "\\llbracket"); // blackboard bold [ 14517 14518defineMacro("\u27e7", "\\rrbracket"); // blackboard bold ] 14519 14520defineMacro("\\lBrace", "\\html@mathml{" + "\\mathopen{\\{\\mkern-3.2mu[}}" + "{\\mathopen{\\char`\u2983}}"); 14521defineMacro("\\rBrace", "\\html@mathml{" + "\\mathclose{]\\mkern-3.2mu\\}}}" + "{\\mathclose{\\char`\u2984}}"); 14522defineMacro("\u2983", "\\lBrace"); // blackboard bold { 14523 14524defineMacro("\u2984", "\\rBrace"); // blackboard bold } 14525// TODO: Create variable sized versions of the last two items. I believe that 14526// will require new font glyphs. 14527////////////////////////////////////////////////////////////////////// 14528// texvc.sty 14529// The texvc package contains macros available in mediawiki pages. 14530// We omit the functions deprecated at 14531// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax 14532// We also omit texvc's \O, which conflicts with \text{\O} 14533 14534defineMacro("\\darr", "\\downarrow"); 14535defineMacro("\\dArr", "\\Downarrow"); 14536defineMacro("\\Darr", "\\Downarrow"); 14537defineMacro("\\lang", "\\langle"); 14538defineMacro("\\rang", "\\rangle"); 14539defineMacro("\\uarr", "\\uparrow"); 14540defineMacro("\\uArr", "\\Uparrow"); 14541defineMacro("\\Uarr", "\\Uparrow"); 14542defineMacro("\\N", "\\mathbb{N}"); 14543defineMacro("\\R", "\\mathbb{R}"); 14544defineMacro("\\Z", "\\mathbb{Z}"); 14545defineMacro("\\alef", "\\aleph"); 14546defineMacro("\\alefsym", "\\aleph"); 14547defineMacro("\\Alpha", "\\mathrm{A}"); 14548defineMacro("\\Beta", "\\mathrm{B}"); 14549defineMacro("\\bull", "\\bullet"); 14550defineMacro("\\Chi", "\\mathrm{X}"); 14551defineMacro("\\clubs", "\\clubsuit"); 14552defineMacro("\\cnums", "\\mathbb{C}"); 14553defineMacro("\\Complex", "\\mathbb{C}"); 14554defineMacro("\\Dagger", "\\ddagger"); 14555defineMacro("\\diamonds", "\\diamondsuit"); 14556defineMacro("\\empty", "\\emptyset"); 14557defineMacro("\\Epsilon", "\\mathrm{E}"); 14558defineMacro("\\Eta", "\\mathrm{H}"); 14559defineMacro("\\exist", "\\exists"); 14560defineMacro("\\harr", "\\leftrightarrow"); 14561defineMacro("\\hArr", "\\Leftrightarrow"); 14562defineMacro("\\Harr", "\\Leftrightarrow"); 14563defineMacro("\\hearts", "\\heartsuit"); 14564defineMacro("\\image", "\\Im"); 14565defineMacro("\\infin", "\\infty"); 14566defineMacro("\\Iota", "\\mathrm{I}"); 14567defineMacro("\\isin", "\\in"); 14568defineMacro("\\Kappa", "\\mathrm{K}"); 14569defineMacro("\\larr", "\\leftarrow"); 14570defineMacro("\\lArr", "\\Leftarrow"); 14571defineMacro("\\Larr", "\\Leftarrow"); 14572defineMacro("\\lrarr", "\\leftrightarrow"); 14573defineMacro("\\lrArr", "\\Leftrightarrow"); 14574defineMacro("\\Lrarr", "\\Leftrightarrow"); 14575defineMacro("\\Mu", "\\mathrm{M}"); 14576defineMacro("\\natnums", "\\mathbb{N}"); 14577defineMacro("\\Nu", "\\mathrm{N}"); 14578defineMacro("\\Omicron", "\\mathrm{O}"); 14579defineMacro("\\plusmn", "\\pm"); 14580defineMacro("\\rarr", "\\rightarrow"); 14581defineMacro("\\rArr", "\\Rightarrow"); 14582defineMacro("\\Rarr", "\\Rightarrow"); 14583defineMacro("\\real", "\\Re"); 14584defineMacro("\\reals", "\\mathbb{R}"); 14585defineMacro("\\Reals", "\\mathbb{R}"); 14586defineMacro("\\Rho", "\\mathrm{P}"); 14587defineMacro("\\sdot", "\\cdot"); 14588defineMacro("\\sect", "\\S"); 14589defineMacro("\\spades", "\\spadesuit"); 14590defineMacro("\\sub", "\\subset"); 14591defineMacro("\\sube", "\\subseteq"); 14592defineMacro("\\supe", "\\supseteq"); 14593defineMacro("\\Tau", "\\mathrm{T}"); 14594defineMacro("\\thetasym", "\\vartheta"); // TODO: defineMacro("\\varcoppa", "\\\mbox{\\coppa}"); 14595 14596defineMacro("\\weierp", "\\wp"); 14597defineMacro("\\Zeta", "\\mathrm{Z}"); ////////////////////////////////////////////////////////////////////// 14598// statmath.sty 14599// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf 14600 14601defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); 14602defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); 14603defineMacro("\\plim", "\\DOTSB\\mathop{\\operatorname{plim}}\\limits"); // Custom Khan Academy colors, should be moved to an optional package 14604 14605defineMacro("\\blue", "\\textcolor{##6495ed}{#1}"); 14606defineMacro("\\orange", "\\textcolor{##ffa500}{#1}"); 14607defineMacro("\\pink", "\\textcolor{##ff00af}{#1}"); 14608defineMacro("\\red", "\\textcolor{##df0030}{#1}"); 14609defineMacro("\\green", "\\textcolor{##28ae7b}{#1}"); 14610defineMacro("\\gray", "\\textcolor{gray}{#1}"); 14611defineMacro("\\purple", "\\textcolor{##9d38bd}{#1}"); 14612defineMacro("\\blueA", "\\textcolor{##ccfaff}{#1}"); 14613defineMacro("\\blueB", "\\textcolor{##80f6ff}{#1}"); 14614defineMacro("\\blueC", "\\textcolor{##63d9ea}{#1}"); 14615defineMacro("\\blueD", "\\textcolor{##11accd}{#1}"); 14616defineMacro("\\blueE", "\\textcolor{##0c7f99}{#1}"); 14617defineMacro("\\tealA", "\\textcolor{##94fff5}{#1}"); 14618defineMacro("\\tealB", "\\textcolor{##26edd5}{#1}"); 14619defineMacro("\\tealC", "\\textcolor{##01d1c1}{#1}"); 14620defineMacro("\\tealD", "\\textcolor{##01a995}{#1}"); 14621defineMacro("\\tealE", "\\textcolor{##208170}{#1}"); 14622defineMacro("\\greenA", "\\textcolor{##b6ffb0}{#1}"); 14623defineMacro("\\greenB", "\\textcolor{##8af281}{#1}"); 14624defineMacro("\\greenC", "\\textcolor{##74cf70}{#1}"); 14625defineMacro("\\greenD", "\\textcolor{##1fab54}{#1}"); 14626defineMacro("\\greenE", "\\textcolor{##0d923f}{#1}"); 14627defineMacro("\\goldA", "\\textcolor{##ffd0a9}{#1}"); 14628defineMacro("\\goldB", "\\textcolor{##ffbb71}{#1}"); 14629defineMacro("\\goldC", "\\textcolor{##ff9c39}{#1}"); 14630defineMacro("\\goldD", "\\textcolor{##e07d10}{#1}"); 14631defineMacro("\\goldE", "\\textcolor{##a75a05}{#1}"); 14632defineMacro("\\redA", "\\textcolor{##fca9a9}{#1}"); 14633defineMacro("\\redB", "\\textcolor{##ff8482}{#1}"); 14634defineMacro("\\redC", "\\textcolor{##f9685d}{#1}"); 14635defineMacro("\\redD", "\\textcolor{##e84d39}{#1}"); 14636defineMacro("\\redE", "\\textcolor{##bc2612}{#1}"); 14637defineMacro("\\maroonA", "\\textcolor{##ffbde0}{#1}"); 14638defineMacro("\\maroonB", "\\textcolor{##ff92c6}{#1}"); 14639defineMacro("\\maroonC", "\\textcolor{##ed5fa6}{#1}"); 14640defineMacro("\\maroonD", "\\textcolor{##ca337c}{#1}"); 14641defineMacro("\\maroonE", "\\textcolor{##9e034e}{#1}"); 14642defineMacro("\\purpleA", "\\textcolor{##ddd7ff}{#1}"); 14643defineMacro("\\purpleB", "\\textcolor{##c6b9fc}{#1}"); 14644defineMacro("\\purpleC", "\\textcolor{##aa87ff}{#1}"); 14645defineMacro("\\purpleD", "\\textcolor{##7854ab}{#1}"); 14646defineMacro("\\purpleE", "\\textcolor{##543b78}{#1}"); 14647defineMacro("\\mintA", "\\textcolor{##f5f9e8}{#1}"); 14648defineMacro("\\mintB", "\\textcolor{##edf2df}{#1}"); 14649defineMacro("\\mintC", "\\textcolor{##e0e5cc}{#1}"); 14650defineMacro("\\grayA", "\\textcolor{##f6f7f7}{#1}"); 14651defineMacro("\\grayB", "\\textcolor{##f0f1f2}{#1}"); 14652defineMacro("\\grayC", "\\textcolor{##e3e5e6}{#1}"); 14653defineMacro("\\grayD", "\\textcolor{##d6d8da}{#1}"); 14654defineMacro("\\grayE", "\\textcolor{##babec2}{#1}"); 14655defineMacro("\\grayF", "\\textcolor{##888d93}{#1}"); 14656defineMacro("\\grayG", "\\textcolor{##626569}{#1}"); 14657defineMacro("\\grayH", "\\textcolor{##3b3e40}{#1}"); 14658defineMacro("\\grayI", "\\textcolor{##21242c}{#1}"); 14659defineMacro("\\kaBlue", "\\textcolor{##314453}{#1}"); 14660defineMacro("\\kaGreen", "\\textcolor{##71B307}{#1}"); 14661 14662/** 14663 * This file contains the “gullet” where macros are expanded 14664 * until only non-macro tokens remain. 14665 */ 14666// List of commands that act like macros but aren't defined as a macro, 14667// function, or symbol. Used in `isDefined`. 14668const implicitCommands = { 14669 "\\relax": true, 14670 // MacroExpander.js 14671 "^": true, 14672 // Parser.js 14673 "_": true, 14674 // Parser.js 14675 "\\limits": true, 14676 // Parser.js 14677 "\\nolimits": true // Parser.js 14678 14679}; 14680class MacroExpander { 14681 constructor(input, settings, mode) { 14682 this.settings = void 0; 14683 this.expansionCount = void 0; 14684 this.lexer = void 0; 14685 this.macros = void 0; 14686 this.stack = void 0; 14687 this.mode = void 0; 14688 this.settings = settings; 14689 this.expansionCount = 0; 14690 this.feed(input); // Make new global namespace 14691 14692 this.macros = new Namespace(builtinMacros, settings.macros); 14693 this.mode = mode; 14694 this.stack = []; // contains tokens in REVERSE order 14695 } 14696 /** 14697 * Feed a new input string to the same MacroExpander 14698 * (with existing macros etc.). 14699 */ 14700 14701 14702 feed(input) { 14703 this.lexer = new Lexer(input, this.settings); 14704 } 14705 /** 14706 * Switches between "text" and "math" modes. 14707 */ 14708 14709 14710 switchMode(newMode) { 14711 this.mode = newMode; 14712 } 14713 /** 14714 * Start a new group nesting within all namespaces. 14715 */ 14716 14717 14718 beginGroup() { 14719 this.macros.beginGroup(); 14720 } 14721 /** 14722 * End current group nesting within all namespaces. 14723 */ 14724 14725 14726 endGroup() { 14727 this.macros.endGroup(); 14728 } 14729 /** 14730 * Returns the topmost token on the stack, without expanding it. 14731 * Similar in behavior to TeX's `\futurelet`. 14732 */ 14733 14734 14735 future() { 14736 if (this.stack.length === 0) { 14737 this.pushToken(this.lexer.lex()); 14738 } 14739 14740 return this.stack[this.stack.length - 1]; 14741 } 14742 /** 14743 * Remove and return the next unexpanded token. 14744 */ 14745 14746 14747 popToken() { 14748 this.future(); // ensure non-empty stack 14749 14750 return this.stack.pop(); 14751 } 14752 /** 14753 * Add a given token to the token stack. In particular, this get be used 14754 * to put back a token returned from one of the other methods. 14755 */ 14756 14757 14758 pushToken(token) { 14759 this.stack.push(token); 14760 } 14761 /** 14762 * Append an array of tokens to the token stack. 14763 */ 14764 14765 14766 pushTokens(tokens) { 14767 this.stack.push(...tokens); 14768 } 14769 /** 14770 * Consume all following space tokens, without expansion. 14771 */ 14772 14773 14774 consumeSpaces() { 14775 for (;;) { 14776 const token = this.future(); 14777 14778 if (token.text === " ") { 14779 this.stack.pop(); 14780 } else { 14781 break; 14782 } 14783 } 14784 } 14785 /** 14786 * Consume the specified number of arguments from the token stream, 14787 * and return the resulting array of arguments. 14788 */ 14789 14790 14791 consumeArgs(numArgs) { 14792 const args = []; // obtain arguments, either single token or balanced {…} group 14793 14794 for (let i = 0; i < numArgs; ++i) { 14795 this.consumeSpaces(); // ignore spaces before each argument 14796 14797 const startOfArg = this.popToken(); 14798 14799 if (startOfArg.text === "{") { 14800 const arg = []; 14801 let depth = 1; 14802 14803 while (depth !== 0) { 14804 const tok = this.popToken(); 14805 arg.push(tok); 14806 14807 if (tok.text === "{") { 14808 ++depth; 14809 } else if (tok.text === "}") { 14810 --depth; 14811 } else if (tok.text === "EOF") { 14812 throw new ParseError("End of input in macro argument", startOfArg); 14813 } 14814 } 14815 14816 arg.pop(); // remove last } 14817 14818 arg.reverse(); // like above, to fit in with stack order 14819 14820 args[i] = arg; 14821 } else if (startOfArg.text === "EOF") { 14822 throw new ParseError("End of input expecting macro argument"); 14823 } else { 14824 args[i] = [startOfArg]; 14825 } 14826 } 14827 14828 return args; 14829 } 14830 /** 14831 * Expand the next token only once if possible. 14832 * 14833 * If the token is expanded, the resulting tokens will be pushed onto 14834 * the stack in reverse order and will be returned as an array, 14835 * also in reverse order. 14836 * 14837 * If not, the next token will be returned without removing it 14838 * from the stack. This case can be detected by a `Token` return value 14839 * instead of an `Array` return value. 14840 * 14841 * In either case, the next token will be on the top of the stack, 14842 * or the stack will be empty. 14843 * 14844 * Used to implement `expandAfterFuture` and `expandNextToken`. 14845 * 14846 * At the moment, macro expansion doesn't handle delimited macros, 14847 * i.e. things like those defined by \def\foo#1\end{…}. 14848 * See the TeX book page 202ff. for details on how those should behave. 14849 */ 14850 14851 14852 expandOnce() { 14853 const topToken = this.popToken(); 14854 const name = topToken.text; 14855 14856 const expansion = this._getExpansion(name); 14857 14858 if (expansion == null) { 14859 // mainly checking for undefined here 14860 // Fully expanded 14861 this.pushToken(topToken); 14862 return topToken; 14863 } 14864 14865 this.expansionCount++; 14866 14867 if (this.expansionCount > this.settings.maxExpand) { 14868 throw new ParseError("Too many expansions: infinite loop or " + "need to increase maxExpand setting"); 14869 } 14870 14871 let tokens = expansion.tokens; 14872 14873 if (expansion.numArgs) { 14874 const args = this.consumeArgs(expansion.numArgs); // paste arguments in place of the placeholders 14875 14876 tokens = tokens.slice(); // make a shallow copy 14877 14878 for (let i = tokens.length - 1; i >= 0; --i) { 14879 let tok = tokens[i]; 14880 14881 if (tok.text === "#") { 14882 if (i === 0) { 14883 throw new ParseError("Incomplete placeholder at end of macro body", tok); 14884 } 14885 14886 tok = tokens[--i]; // next token on stack 14887 14888 if (tok.text === "#") { 14889 // ## → # 14890 tokens.splice(i + 1, 1); // drop first # 14891 } else if (/^[1-9]$/.test(tok.text)) { 14892 // replace the placeholder with the indicated argument 14893 tokens.splice(i, 2, ...args[+tok.text - 1]); 14894 } else { 14895 throw new ParseError("Not a valid argument number", tok); 14896 } 14897 } 14898 } 14899 } // Concatenate expansion onto top of stack. 14900 14901 14902 this.pushTokens(tokens); 14903 return tokens; 14904 } 14905 /** 14906 * Expand the next token only once (if possible), and return the resulting 14907 * top token on the stack (without removing anything from the stack). 14908 * Similar in behavior to TeX's `\expandafter\futurelet`. 14909 * Equivalent to expandOnce() followed by future(). 14910 */ 14911 14912 14913 expandAfterFuture() { 14914 this.expandOnce(); 14915 return this.future(); 14916 } 14917 /** 14918 * Recursively expand first token, then return first non-expandable token. 14919 */ 14920 14921 14922 expandNextToken() { 14923 for (;;) { 14924 const expanded = this.expandOnce(); // expandOnce returns Token if and only if it's fully expanded. 14925 14926 if (expanded instanceof Token) { 14927 // \relax stops the expansion, but shouldn't get returned (a 14928 // null return value couldn't get implemented as a function). 14929 if (expanded.text === "\\relax") { 14930 this.stack.pop(); 14931 } else { 14932 return this.stack.pop(); // === expanded 14933 } 14934 } 14935 } // Flow unable to figure out that this pathway is impossible. 14936 // https://github.com/facebook/flow/issues/4808 14937 14938 14939 throw new Error(); // eslint-disable-line no-unreachable 14940 } 14941 /** 14942 * Fully expand the given macro name and return the resulting list of 14943 * tokens, or return `undefined` if no such macro is defined. 14944 */ 14945 14946 14947 expandMacro(name) { 14948 if (!this.macros.get(name)) { 14949 return undefined; 14950 } 14951 14952 const output = []; 14953 const oldStackLength = this.stack.length; 14954 this.pushToken(new Token(name)); 14955 14956 while (this.stack.length > oldStackLength) { 14957 const expanded = this.expandOnce(); // expandOnce returns Token if and only if it's fully expanded. 14958 14959 if (expanded instanceof Token) { 14960 output.push(this.stack.pop()); 14961 } 14962 } 14963 14964 return output; 14965 } 14966 /** 14967 * Fully expand the given macro name and return the result as a string, 14968 * or return `undefined` if no such macro is defined. 14969 */ 14970 14971 14972 expandMacroAsText(name) { 14973 const tokens = this.expandMacro(name); 14974 14975 if (tokens) { 14976 return tokens.map(token => token.text).join(""); 14977 } else { 14978 return tokens; 14979 } 14980 } 14981 /** 14982 * Returns the expanded macro as a reversed array of tokens and a macro 14983 * argument count. Or returns `null` if no such macro. 14984 */ 14985 14986 14987 _getExpansion(name) { 14988 const definition = this.macros.get(name); 14989 14990 if (definition == null) { 14991 // mainly checking for undefined here 14992 return definition; 14993 } 14994 14995 const expansion = typeof definition === "function" ? definition(this) : definition; 14996 14997 if (typeof expansion === "string") { 14998 let numArgs = 0; 14999 15000 if (expansion.indexOf("#") !== -1) { 15001 const stripped = expansion.replace(/##/g, ""); 15002 15003 while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { 15004 ++numArgs; 15005 } 15006 } 15007 15008 const bodyLexer = new Lexer(expansion, this.settings); 15009 const tokens = []; 15010 let tok = bodyLexer.lex(); 15011 15012 while (tok.text !== "EOF") { 15013 tokens.push(tok); 15014 tok = bodyLexer.lex(); 15015 } 15016 15017 tokens.reverse(); // to fit in with stack using push and pop 15018 15019 const expanded = { 15020 tokens, 15021 numArgs 15022 }; 15023 return expanded; 15024 } 15025 15026 return expansion; 15027 } 15028 /** 15029 * Determine whether a command is currently "defined" (has some 15030 * functionality), meaning that it's a macro (in the current group), 15031 * a function, a symbol, or one of the special commands listed in 15032 * `implicitCommands`. 15033 */ 15034 15035 15036 isDefined(name) { 15037 return this.macros.has(name) || functions.hasOwnProperty(name) || symbols.math.hasOwnProperty(name) || symbols.text.hasOwnProperty(name) || implicitCommands.hasOwnProperty(name); 15038 } 15039 15040} 15041 15042// Mapping of Unicode accent characters to their LaTeX equivalent in text and 15043// math mode (when they exist). 15044var unicodeAccents = { 15045 '\u0301': { 15046 text: "\\'", 15047 math: '\\acute' 15048 }, 15049 '\u0300': { 15050 text: '\\`', 15051 math: '\\grave' 15052 }, 15053 '\u0308': { 15054 text: '\\"', 15055 math: '\\ddot' 15056 }, 15057 '\u0303': { 15058 text: '\\~', 15059 math: '\\tilde' 15060 }, 15061 '\u0304': { 15062 text: '\\=', 15063 math: '\\bar' 15064 }, 15065 '\u0306': { 15066 text: '\\u', 15067 math: '\\breve' 15068 }, 15069 '\u030c': { 15070 text: '\\v', 15071 math: '\\check' 15072 }, 15073 '\u0302': { 15074 text: '\\^', 15075 math: '\\hat' 15076 }, 15077 '\u0307': { 15078 text: '\\.', 15079 math: '\\dot' 15080 }, 15081 '\u030a': { 15082 text: '\\r', 15083 math: '\\mathring' 15084 }, 15085 '\u030b': { 15086 text: '\\H' 15087 } 15088}; 15089 15090// This file is GENERATED by unicodeMake.js. DO NOT MODIFY. 15091var unicodeSymbols = { 15092 "\u00e1": "\u0061\u0301", 15093 // á = \'{a} 15094 "\u00e0": "\u0061\u0300", 15095 // à = \`{a} 15096 "\u00e4": "\u0061\u0308", 15097 // ä = \"{a} 15098 "\u01df": "\u0061\u0308\u0304", 15099 // ǟ = \"\={a} 15100 "\u00e3": "\u0061\u0303", 15101 // ã = \~{a} 15102 "\u0101": "\u0061\u0304", 15103 // ā = \={a} 15104 "\u0103": "\u0061\u0306", 15105 // ă = \u{a} 15106 "\u1eaf": "\u0061\u0306\u0301", 15107 // ắ = \u\'{a} 15108 "\u1eb1": "\u0061\u0306\u0300", 15109 // ằ = \u\`{a} 15110 "\u1eb5": "\u0061\u0306\u0303", 15111 // ẵ = \u\~{a} 15112 "\u01ce": "\u0061\u030c", 15113 // ǎ = \v{a} 15114 "\u00e2": "\u0061\u0302", 15115 // â = \^{a} 15116 "\u1ea5": "\u0061\u0302\u0301", 15117 // ấ = \^\'{a} 15118 "\u1ea7": "\u0061\u0302\u0300", 15119 // ầ = \^\`{a} 15120 "\u1eab": "\u0061\u0302\u0303", 15121 // ẫ = \^\~{a} 15122 "\u0227": "\u0061\u0307", 15123 // ȧ = \.{a} 15124 "\u01e1": "\u0061\u0307\u0304", 15125 // ǡ = \.\={a} 15126 "\u00e5": "\u0061\u030a", 15127 // å = \r{a} 15128 "\u01fb": "\u0061\u030a\u0301", 15129 // ǻ = \r\'{a} 15130 "\u1e03": "\u0062\u0307", 15131 // ḃ = \.{b} 15132 "\u0107": "\u0063\u0301", 15133 // ć = \'{c} 15134 "\u010d": "\u0063\u030c", 15135 // č = \v{c} 15136 "\u0109": "\u0063\u0302", 15137 // ĉ = \^{c} 15138 "\u010b": "\u0063\u0307", 15139 // ċ = \.{c} 15140 "\u010f": "\u0064\u030c", 15141 // ď = \v{d} 15142 "\u1e0b": "\u0064\u0307", 15143 // ḋ = \.{d} 15144 "\u00e9": "\u0065\u0301", 15145 // é = \'{e} 15146 "\u00e8": "\u0065\u0300", 15147 // è = \`{e} 15148 "\u00eb": "\u0065\u0308", 15149 // ë = \"{e} 15150 "\u1ebd": "\u0065\u0303", 15151 // ẽ = \~{e} 15152 "\u0113": "\u0065\u0304", 15153 // ē = \={e} 15154 "\u1e17": "\u0065\u0304\u0301", 15155 // ḗ = \=\'{e} 15156 "\u1e15": "\u0065\u0304\u0300", 15157 // ḕ = \=\`{e} 15158 "\u0115": "\u0065\u0306", 15159 // ĕ = \u{e} 15160 "\u011b": "\u0065\u030c", 15161 // ě = \v{e} 15162 "\u00ea": "\u0065\u0302", 15163 // ê = \^{e} 15164 "\u1ebf": "\u0065\u0302\u0301", 15165 // ế = \^\'{e} 15166 "\u1ec1": "\u0065\u0302\u0300", 15167 // ề = \^\`{e} 15168 "\u1ec5": "\u0065\u0302\u0303", 15169 // ễ = \^\~{e} 15170 "\u0117": "\u0065\u0307", 15171 // ė = \.{e} 15172 "\u1e1f": "\u0066\u0307", 15173 // ḟ = \.{f} 15174 "\u01f5": "\u0067\u0301", 15175 // ǵ = \'{g} 15176 "\u1e21": "\u0067\u0304", 15177 // ḡ = \={g} 15178 "\u011f": "\u0067\u0306", 15179 // ğ = \u{g} 15180 "\u01e7": "\u0067\u030c", 15181 // ǧ = \v{g} 15182 "\u011d": "\u0067\u0302", 15183 // ĝ = \^{g} 15184 "\u0121": "\u0067\u0307", 15185 // ġ = \.{g} 15186 "\u1e27": "\u0068\u0308", 15187 // ḧ = \"{h} 15188 "\u021f": "\u0068\u030c", 15189 // ȟ = \v{h} 15190 "\u0125": "\u0068\u0302", 15191 // ĥ = \^{h} 15192 "\u1e23": "\u0068\u0307", 15193 // ḣ = \.{h} 15194 "\u00ed": "\u0069\u0301", 15195 // í = \'{i} 15196 "\u00ec": "\u0069\u0300", 15197 // ì = \`{i} 15198 "\u00ef": "\u0069\u0308", 15199 // ï = \"{i} 15200 "\u1e2f": "\u0069\u0308\u0301", 15201 // ḯ = \"\'{i} 15202 "\u0129": "\u0069\u0303", 15203 // ĩ = \~{i} 15204 "\u012b": "\u0069\u0304", 15205 // ī = \={i} 15206 "\u012d": "\u0069\u0306", 15207 // ĭ = \u{i} 15208 "\u01d0": "\u0069\u030c", 15209 // ǐ = \v{i} 15210 "\u00ee": "\u0069\u0302", 15211 // î = \^{i} 15212 "\u01f0": "\u006a\u030c", 15213 // ǰ = \v{j} 15214 "\u0135": "\u006a\u0302", 15215 // ĵ = \^{j} 15216 "\u1e31": "\u006b\u0301", 15217 // ḱ = \'{k} 15218 "\u01e9": "\u006b\u030c", 15219 // ǩ = \v{k} 15220 "\u013a": "\u006c\u0301", 15221 // ĺ = \'{l} 15222 "\u013e": "\u006c\u030c", 15223 // ľ = \v{l} 15224 "\u1e3f": "\u006d\u0301", 15225 // ḿ = \'{m} 15226 "\u1e41": "\u006d\u0307", 15227 // ṁ = \.{m} 15228 "\u0144": "\u006e\u0301", 15229 // ń = \'{n} 15230 "\u01f9": "\u006e\u0300", 15231 // ǹ = \`{n} 15232 "\u00f1": "\u006e\u0303", 15233 // ñ = \~{n} 15234 "\u0148": "\u006e\u030c", 15235 // ň = \v{n} 15236 "\u1e45": "\u006e\u0307", 15237 // ṅ = \.{n} 15238 "\u00f3": "\u006f\u0301", 15239 // ó = \'{o} 15240 "\u00f2": "\u006f\u0300", 15241 // ò = \`{o} 15242 "\u00f6": "\u006f\u0308", 15243 // ö = \"{o} 15244 "\u022b": "\u006f\u0308\u0304", 15245 // ȫ = \"\={o} 15246 "\u00f5": "\u006f\u0303", 15247 // õ = \~{o} 15248 "\u1e4d": "\u006f\u0303\u0301", 15249 // ṍ = \~\'{o} 15250 "\u1e4f": "\u006f\u0303\u0308", 15251 // ṏ = \~\"{o} 15252 "\u022d": "\u006f\u0303\u0304", 15253 // ȭ = \~\={o} 15254 "\u014d": "\u006f\u0304", 15255 // ō = \={o} 15256 "\u1e53": "\u006f\u0304\u0301", 15257 // ṓ = \=\'{o} 15258 "\u1e51": "\u006f\u0304\u0300", 15259 // ṑ = \=\`{o} 15260 "\u014f": "\u006f\u0306", 15261 // ŏ = \u{o} 15262 "\u01d2": "\u006f\u030c", 15263 // ǒ = \v{o} 15264 "\u00f4": "\u006f\u0302", 15265 // ô = \^{o} 15266 "\u1ed1": "\u006f\u0302\u0301", 15267 // ố = \^\'{o} 15268 "\u1ed3": "\u006f\u0302\u0300", 15269 // ồ = \^\`{o} 15270 "\u1ed7": "\u006f\u0302\u0303", 15271 // ỗ = \^\~{o} 15272 "\u022f": "\u006f\u0307", 15273 // ȯ = \.{o} 15274 "\u0231": "\u006f\u0307\u0304", 15275 // ȱ = \.\={o} 15276 "\u0151": "\u006f\u030b", 15277 // ő = \H{o} 15278 "\u1e55": "\u0070\u0301", 15279 // ṕ = \'{p} 15280 "\u1e57": "\u0070\u0307", 15281 // ṗ = \.{p} 15282 "\u0155": "\u0072\u0301", 15283 // ŕ = \'{r} 15284 "\u0159": "\u0072\u030c", 15285 // ř = \v{r} 15286 "\u1e59": "\u0072\u0307", 15287 // ṙ = \.{r} 15288 "\u015b": "\u0073\u0301", 15289 // ś = \'{s} 15290 "\u1e65": "\u0073\u0301\u0307", 15291 // ṥ = \'\.{s} 15292 "\u0161": "\u0073\u030c", 15293 // š = \v{s} 15294 "\u1e67": "\u0073\u030c\u0307", 15295 // ṧ = \v\.{s} 15296 "\u015d": "\u0073\u0302", 15297 // ŝ = \^{s} 15298 "\u1e61": "\u0073\u0307", 15299 // ṡ = \.{s} 15300 "\u1e97": "\u0074\u0308", 15301 // ẗ = \"{t} 15302 "\u0165": "\u0074\u030c", 15303 // ť = \v{t} 15304 "\u1e6b": "\u0074\u0307", 15305 // ṫ = \.{t} 15306 "\u00fa": "\u0075\u0301", 15307 // ú = \'{u} 15308 "\u00f9": "\u0075\u0300", 15309 // ù = \`{u} 15310 "\u00fc": "\u0075\u0308", 15311 // ü = \"{u} 15312 "\u01d8": "\u0075\u0308\u0301", 15313 // ǘ = \"\'{u} 15314 "\u01dc": "\u0075\u0308\u0300", 15315 // ǜ = \"\`{u} 15316 "\u01d6": "\u0075\u0308\u0304", 15317 // ǖ = \"\={u} 15318 "\u01da": "\u0075\u0308\u030c", 15319 // ǚ = \"\v{u} 15320 "\u0169": "\u0075\u0303", 15321 // ũ = \~{u} 15322 "\u1e79": "\u0075\u0303\u0301", 15323 // ṹ = \~\'{u} 15324 "\u016b": "\u0075\u0304", 15325 // ū = \={u} 15326 "\u1e7b": "\u0075\u0304\u0308", 15327 // ṻ = \=\"{u} 15328 "\u016d": "\u0075\u0306", 15329 // ŭ = \u{u} 15330 "\u01d4": "\u0075\u030c", 15331 // ǔ = \v{u} 15332 "\u00fb": "\u0075\u0302", 15333 // û = \^{u} 15334 "\u016f": "\u0075\u030a", 15335 // ů = \r{u} 15336 "\u0171": "\u0075\u030b", 15337 // ű = \H{u} 15338 "\u1e7d": "\u0076\u0303", 15339 // ṽ = \~{v} 15340 "\u1e83": "\u0077\u0301", 15341 // ẃ = \'{w} 15342 "\u1e81": "\u0077\u0300", 15343 // ẁ = \`{w} 15344 "\u1e85": "\u0077\u0308", 15345 // ẅ = \"{w} 15346 "\u0175": "\u0077\u0302", 15347 // ŵ = \^{w} 15348 "\u1e87": "\u0077\u0307", 15349 // ẇ = \.{w} 15350 "\u1e98": "\u0077\u030a", 15351 // ẘ = \r{w} 15352 "\u1e8d": "\u0078\u0308", 15353 // ẍ = \"{x} 15354 "\u1e8b": "\u0078\u0307", 15355 // ẋ = \.{x} 15356 "\u00fd": "\u0079\u0301", 15357 // ý = \'{y} 15358 "\u1ef3": "\u0079\u0300", 15359 // ỳ = \`{y} 15360 "\u00ff": "\u0079\u0308", 15361 // ÿ = \"{y} 15362 "\u1ef9": "\u0079\u0303", 15363 // ỹ = \~{y} 15364 "\u0233": "\u0079\u0304", 15365 // ȳ = \={y} 15366 "\u0177": "\u0079\u0302", 15367 // ŷ = \^{y} 15368 "\u1e8f": "\u0079\u0307", 15369 // ẏ = \.{y} 15370 "\u1e99": "\u0079\u030a", 15371 // ẙ = \r{y} 15372 "\u017a": "\u007a\u0301", 15373 // ź = \'{z} 15374 "\u017e": "\u007a\u030c", 15375 // ž = \v{z} 15376 "\u1e91": "\u007a\u0302", 15377 // ẑ = \^{z} 15378 "\u017c": "\u007a\u0307", 15379 // ż = \.{z} 15380 "\u00c1": "\u0041\u0301", 15381 // Á = \'{A} 15382 "\u00c0": "\u0041\u0300", 15383 // À = \`{A} 15384 "\u00c4": "\u0041\u0308", 15385 // Ä = \"{A} 15386 "\u01de": "\u0041\u0308\u0304", 15387 // Ǟ = \"\={A} 15388 "\u00c3": "\u0041\u0303", 15389 // Ã = \~{A} 15390 "\u0100": "\u0041\u0304", 15391 // Ā = \={A} 15392 "\u0102": "\u0041\u0306", 15393 // Ă = \u{A} 15394 "\u1eae": "\u0041\u0306\u0301", 15395 // Ắ = \u\'{A} 15396 "\u1eb0": "\u0041\u0306\u0300", 15397 // Ằ = \u\`{A} 15398 "\u1eb4": "\u0041\u0306\u0303", 15399 // Ẵ = \u\~{A} 15400 "\u01cd": "\u0041\u030c", 15401 // Ǎ = \v{A} 15402 "\u00c2": "\u0041\u0302", 15403 // Â = \^{A} 15404 "\u1ea4": "\u0041\u0302\u0301", 15405 // Ấ = \^\'{A} 15406 "\u1ea6": "\u0041\u0302\u0300", 15407 // Ầ = \^\`{A} 15408 "\u1eaa": "\u0041\u0302\u0303", 15409 // Ẫ = \^\~{A} 15410 "\u0226": "\u0041\u0307", 15411 // Ȧ = \.{A} 15412 "\u01e0": "\u0041\u0307\u0304", 15413 // Ǡ = \.\={A} 15414 "\u00c5": "\u0041\u030a", 15415 // Å = \r{A} 15416 "\u01fa": "\u0041\u030a\u0301", 15417 // Ǻ = \r\'{A} 15418 "\u1e02": "\u0042\u0307", 15419 // Ḃ = \.{B} 15420 "\u0106": "\u0043\u0301", 15421 // Ć = \'{C} 15422 "\u010c": "\u0043\u030c", 15423 // Č = \v{C} 15424 "\u0108": "\u0043\u0302", 15425 // Ĉ = \^{C} 15426 "\u010a": "\u0043\u0307", 15427 // Ċ = \.{C} 15428 "\u010e": "\u0044\u030c", 15429 // Ď = \v{D} 15430 "\u1e0a": "\u0044\u0307", 15431 // Ḋ = \.{D} 15432 "\u00c9": "\u0045\u0301", 15433 // É = \'{E} 15434 "\u00c8": "\u0045\u0300", 15435 // È = \`{E} 15436 "\u00cb": "\u0045\u0308", 15437 // Ë = \"{E} 15438 "\u1ebc": "\u0045\u0303", 15439 // Ẽ = \~{E} 15440 "\u0112": "\u0045\u0304", 15441 // Ē = \={E} 15442 "\u1e16": "\u0045\u0304\u0301", 15443 // Ḗ = \=\'{E} 15444 "\u1e14": "\u0045\u0304\u0300", 15445 // Ḕ = \=\`{E} 15446 "\u0114": "\u0045\u0306", 15447 // Ĕ = \u{E} 15448 "\u011a": "\u0045\u030c", 15449 // Ě = \v{E} 15450 "\u00ca": "\u0045\u0302", 15451 // Ê = \^{E} 15452 "\u1ebe": "\u0045\u0302\u0301", 15453 // Ế = \^\'{E} 15454 "\u1ec0": "\u0045\u0302\u0300", 15455 // Ề = \^\`{E} 15456 "\u1ec4": "\u0045\u0302\u0303", 15457 // Ễ = \^\~{E} 15458 "\u0116": "\u0045\u0307", 15459 // Ė = \.{E} 15460 "\u1e1e": "\u0046\u0307", 15461 // Ḟ = \.{F} 15462 "\u01f4": "\u0047\u0301", 15463 // Ǵ = \'{G} 15464 "\u1e20": "\u0047\u0304", 15465 // Ḡ = \={G} 15466 "\u011e": "\u0047\u0306", 15467 // Ğ = \u{G} 15468 "\u01e6": "\u0047\u030c", 15469 // Ǧ = \v{G} 15470 "\u011c": "\u0047\u0302", 15471 // Ĝ = \^{G} 15472 "\u0120": "\u0047\u0307", 15473 // Ġ = \.{G} 15474 "\u1e26": "\u0048\u0308", 15475 // Ḧ = \"{H} 15476 "\u021e": "\u0048\u030c", 15477 // Ȟ = \v{H} 15478 "\u0124": "\u0048\u0302", 15479 // Ĥ = \^{H} 15480 "\u1e22": "\u0048\u0307", 15481 // Ḣ = \.{H} 15482 "\u00cd": "\u0049\u0301", 15483 // Í = \'{I} 15484 "\u00cc": "\u0049\u0300", 15485 // Ì = \`{I} 15486 "\u00cf": "\u0049\u0308", 15487 // Ï = \"{I} 15488 "\u1e2e": "\u0049\u0308\u0301", 15489 // Ḯ = \"\'{I} 15490 "\u0128": "\u0049\u0303", 15491 // Ĩ = \~{I} 15492 "\u012a": "\u0049\u0304", 15493 // Ī = \={I} 15494 "\u012c": "\u0049\u0306", 15495 // Ĭ = \u{I} 15496 "\u01cf": "\u0049\u030c", 15497 // Ǐ = \v{I} 15498 "\u00ce": "\u0049\u0302", 15499 // Î = \^{I} 15500 "\u0130": "\u0049\u0307", 15501 // İ = \.{I} 15502 "\u0134": "\u004a\u0302", 15503 // Ĵ = \^{J} 15504 "\u1e30": "\u004b\u0301", 15505 // Ḱ = \'{K} 15506 "\u01e8": "\u004b\u030c", 15507 // Ǩ = \v{K} 15508 "\u0139": "\u004c\u0301", 15509 // Ĺ = \'{L} 15510 "\u013d": "\u004c\u030c", 15511 // Ľ = \v{L} 15512 "\u1e3e": "\u004d\u0301", 15513 // Ḿ = \'{M} 15514 "\u1e40": "\u004d\u0307", 15515 // Ṁ = \.{M} 15516 "\u0143": "\u004e\u0301", 15517 // Ń = \'{N} 15518 "\u01f8": "\u004e\u0300", 15519 // Ǹ = \`{N} 15520 "\u00d1": "\u004e\u0303", 15521 // Ñ = \~{N} 15522 "\u0147": "\u004e\u030c", 15523 // Ň = \v{N} 15524 "\u1e44": "\u004e\u0307", 15525 // Ṅ = \.{N} 15526 "\u00d3": "\u004f\u0301", 15527 // Ó = \'{O} 15528 "\u00d2": "\u004f\u0300", 15529 // Ò = \`{O} 15530 "\u00d6": "\u004f\u0308", 15531 // Ö = \"{O} 15532 "\u022a": "\u004f\u0308\u0304", 15533 // Ȫ = \"\={O} 15534 "\u00d5": "\u004f\u0303", 15535 // Õ = \~{O} 15536 "\u1e4c": "\u004f\u0303\u0301", 15537 // Ṍ = \~\'{O} 15538 "\u1e4e": "\u004f\u0303\u0308", 15539 // Ṏ = \~\"{O} 15540 "\u022c": "\u004f\u0303\u0304", 15541 // Ȭ = \~\={O} 15542 "\u014c": "\u004f\u0304", 15543 // Ō = \={O} 15544 "\u1e52": "\u004f\u0304\u0301", 15545 // Ṓ = \=\'{O} 15546 "\u1e50": "\u004f\u0304\u0300", 15547 // Ṑ = \=\`{O} 15548 "\u014e": "\u004f\u0306", 15549 // Ŏ = \u{O} 15550 "\u01d1": "\u004f\u030c", 15551 // Ǒ = \v{O} 15552 "\u00d4": "\u004f\u0302", 15553 // Ô = \^{O} 15554 "\u1ed0": "\u004f\u0302\u0301", 15555 // Ố = \^\'{O} 15556 "\u1ed2": "\u004f\u0302\u0300", 15557 // Ồ = \^\`{O} 15558 "\u1ed6": "\u004f\u0302\u0303", 15559 // Ỗ = \^\~{O} 15560 "\u022e": "\u004f\u0307", 15561 // Ȯ = \.{O} 15562 "\u0230": "\u004f\u0307\u0304", 15563 // Ȱ = \.\={O} 15564 "\u0150": "\u004f\u030b", 15565 // Ő = \H{O} 15566 "\u1e54": "\u0050\u0301", 15567 // Ṕ = \'{P} 15568 "\u1e56": "\u0050\u0307", 15569 // Ṗ = \.{P} 15570 "\u0154": "\u0052\u0301", 15571 // Ŕ = \'{R} 15572 "\u0158": "\u0052\u030c", 15573 // Ř = \v{R} 15574 "\u1e58": "\u0052\u0307", 15575 // Ṙ = \.{R} 15576 "\u015a": "\u0053\u0301", 15577 // Ś = \'{S} 15578 "\u1e64": "\u0053\u0301\u0307", 15579 // Ṥ = \'\.{S} 15580 "\u0160": "\u0053\u030c", 15581 // Š = \v{S} 15582 "\u1e66": "\u0053\u030c\u0307", 15583 // Ṧ = \v\.{S} 15584 "\u015c": "\u0053\u0302", 15585 // Ŝ = \^{S} 15586 "\u1e60": "\u0053\u0307", 15587 // Ṡ = \.{S} 15588 "\u0164": "\u0054\u030c", 15589 // Ť = \v{T} 15590 "\u1e6a": "\u0054\u0307", 15591 // Ṫ = \.{T} 15592 "\u00da": "\u0055\u0301", 15593 // Ú = \'{U} 15594 "\u00d9": "\u0055\u0300", 15595 // Ù = \`{U} 15596 "\u00dc": "\u0055\u0308", 15597 // Ü = \"{U} 15598 "\u01d7": "\u0055\u0308\u0301", 15599 // Ǘ = \"\'{U} 15600 "\u01db": "\u0055\u0308\u0300", 15601 // Ǜ = \"\`{U} 15602 "\u01d5": "\u0055\u0308\u0304", 15603 // Ǖ = \"\={U} 15604 "\u01d9": "\u0055\u0308\u030c", 15605 // Ǚ = \"\v{U} 15606 "\u0168": "\u0055\u0303", 15607 // Ũ = \~{U} 15608 "\u1e78": "\u0055\u0303\u0301", 15609 // Ṹ = \~\'{U} 15610 "\u016a": "\u0055\u0304", 15611 // Ū = \={U} 15612 "\u1e7a": "\u0055\u0304\u0308", 15613 // Ṻ = \=\"{U} 15614 "\u016c": "\u0055\u0306", 15615 // Ŭ = \u{U} 15616 "\u01d3": "\u0055\u030c", 15617 // Ǔ = \v{U} 15618 "\u00db": "\u0055\u0302", 15619 // Û = \^{U} 15620 "\u016e": "\u0055\u030a", 15621 // Ů = \r{U} 15622 "\u0170": "\u0055\u030b", 15623 // Ű = \H{U} 15624 "\u1e7c": "\u0056\u0303", 15625 // Ṽ = \~{V} 15626 "\u1e82": "\u0057\u0301", 15627 // Ẃ = \'{W} 15628 "\u1e80": "\u0057\u0300", 15629 // Ẁ = \`{W} 15630 "\u1e84": "\u0057\u0308", 15631 // Ẅ = \"{W} 15632 "\u0174": "\u0057\u0302", 15633 // Ŵ = \^{W} 15634 "\u1e86": "\u0057\u0307", 15635 // Ẇ = \.{W} 15636 "\u1e8c": "\u0058\u0308", 15637 // Ẍ = \"{X} 15638 "\u1e8a": "\u0058\u0307", 15639 // Ẋ = \.{X} 15640 "\u00dd": "\u0059\u0301", 15641 // Ý = \'{Y} 15642 "\u1ef2": "\u0059\u0300", 15643 // Ỳ = \`{Y} 15644 "\u0178": "\u0059\u0308", 15645 // Ÿ = \"{Y} 15646 "\u1ef8": "\u0059\u0303", 15647 // Ỹ = \~{Y} 15648 "\u0232": "\u0059\u0304", 15649 // Ȳ = \={Y} 15650 "\u0176": "\u0059\u0302", 15651 // Ŷ = \^{Y} 15652 "\u1e8e": "\u0059\u0307", 15653 // Ẏ = \.{Y} 15654 "\u0179": "\u005a\u0301", 15655 // Ź = \'{Z} 15656 "\u017d": "\u005a\u030c", 15657 // Ž = \v{Z} 15658 "\u1e90": "\u005a\u0302", 15659 // Ẑ = \^{Z} 15660 "\u017b": "\u005a\u0307", 15661 // Ż = \.{Z} 15662 "\u03ac": "\u03b1\u0301", 15663 // ά = \'{α} 15664 "\u1f70": "\u03b1\u0300", 15665 // ὰ = \`{α} 15666 "\u1fb1": "\u03b1\u0304", 15667 // ᾱ = \={α} 15668 "\u1fb0": "\u03b1\u0306", 15669 // ᾰ = \u{α} 15670 "\u03ad": "\u03b5\u0301", 15671 // έ = \'{ε} 15672 "\u1f72": "\u03b5\u0300", 15673 // ὲ = \`{ε} 15674 "\u03ae": "\u03b7\u0301", 15675 // ή = \'{η} 15676 "\u1f74": "\u03b7\u0300", 15677 // ὴ = \`{η} 15678 "\u03af": "\u03b9\u0301", 15679 // ί = \'{ι} 15680 "\u1f76": "\u03b9\u0300", 15681 // ὶ = \`{ι} 15682 "\u03ca": "\u03b9\u0308", 15683 // ϊ = \"{ι} 15684 "\u0390": "\u03b9\u0308\u0301", 15685 // ΐ = \"\'{ι} 15686 "\u1fd2": "\u03b9\u0308\u0300", 15687 // ῒ = \"\`{ι} 15688 "\u1fd1": "\u03b9\u0304", 15689 // ῑ = \={ι} 15690 "\u1fd0": "\u03b9\u0306", 15691 // ῐ = \u{ι} 15692 "\u03cc": "\u03bf\u0301", 15693 // ό = \'{ο} 15694 "\u1f78": "\u03bf\u0300", 15695 // ὸ = \`{ο} 15696 "\u03cd": "\u03c5\u0301", 15697 // ύ = \'{υ} 15698 "\u1f7a": "\u03c5\u0300", 15699 // ὺ = \`{υ} 15700 "\u03cb": "\u03c5\u0308", 15701 // ϋ = \"{υ} 15702 "\u03b0": "\u03c5\u0308\u0301", 15703 // ΰ = \"\'{υ} 15704 "\u1fe2": "\u03c5\u0308\u0300", 15705 // ῢ = \"\`{υ} 15706 "\u1fe1": "\u03c5\u0304", 15707 // ῡ = \={υ} 15708 "\u1fe0": "\u03c5\u0306", 15709 // ῠ = \u{υ} 15710 "\u03ce": "\u03c9\u0301", 15711 // ώ = \'{ω} 15712 "\u1f7c": "\u03c9\u0300", 15713 // ὼ = \`{ω} 15714 "\u038e": "\u03a5\u0301", 15715 // Ύ = \'{Υ} 15716 "\u1fea": "\u03a5\u0300", 15717 // Ὺ = \`{Υ} 15718 "\u03ab": "\u03a5\u0308", 15719 // Ϋ = \"{Υ} 15720 "\u1fe9": "\u03a5\u0304", 15721 // Ῡ = \={Υ} 15722 "\u1fe8": "\u03a5\u0306", 15723 // Ῠ = \u{Υ} 15724 "\u038f": "\u03a9\u0301", 15725 // Ώ = \'{Ω} 15726 "\u1ffa": "\u03a9\u0300" // Ὼ = \`{Ω} 15727 15728}; 15729 15730/* eslint no-constant-condition:0 */ 15731 15732/** 15733 * This file contains the parser used to parse out a TeX expression from the 15734 * input. Since TeX isn't context-free, standard parsers don't work particularly 15735 * well. 15736 * 15737 * The strategy of this parser is as such: 15738 * 15739 * The main functions (the `.parse...` ones) take a position in the current 15740 * parse string to parse tokens from. The lexer (found in Lexer.js, stored at 15741 * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When 15742 * individual tokens are needed at a position, the lexer is called to pull out a 15743 * token, which is then used. 15744 * 15745 * The parser has a property called "mode" indicating the mode that 15746 * the parser is currently in. Currently it has to be one of "math" or 15747 * "text", which denotes whether the current environment is a math-y 15748 * one or a text-y one (e.g. inside \text). Currently, this serves to 15749 * limit the functions which can be used in text mode. 15750 * 15751 * The main functions then return an object which contains the useful data that 15752 * was parsed at its given point, and a new position at the end of the parsed 15753 * data. The main functions can call each other and continue the parsing by 15754 * using the returned position as a new starting point. 15755 * 15756 * There are also extra `.handle...` functions, which pull out some reused 15757 * functionality into self-contained functions. 15758 * 15759 * The functions return ParseNodes. 15760 */ 15761class Parser { 15762 constructor(input, settings) { 15763 this.mode = void 0; 15764 this.gullet = void 0; 15765 this.settings = void 0; 15766 this.leftrightDepth = void 0; 15767 this.nextToken = void 0; 15768 // Start in math mode 15769 this.mode = "math"; // Create a new macro expander (gullet) and (indirectly via that) also a 15770 // new lexer (mouth) for this parser (stomach, in the language of TeX) 15771 15772 this.gullet = new MacroExpander(input, settings, this.mode); // Store the settings for use in parsing 15773 15774 this.settings = settings; // Count leftright depth (for \middle errors) 15775 15776 this.leftrightDepth = 0; 15777 } 15778 /** 15779 * Checks a result to make sure it has the right type, and throws an 15780 * appropriate error otherwise. 15781 */ 15782 15783 15784 expect(text, consume) { 15785 if (consume === void 0) { 15786 consume = true; 15787 } 15788 15789 if (this.fetch().text !== text) { 15790 throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); 15791 } 15792 15793 if (consume) { 15794 this.consume(); 15795 } 15796 } 15797 /** 15798 * Discards the current lookahead token, considering it consumed. 15799 */ 15800 15801 15802 consume() { 15803 this.nextToken = null; 15804 } 15805 /** 15806 * Return the current lookahead token, or if there isn't one (at the 15807 * beginning, or if the previous lookahead token was consume()d), 15808 * fetch the next token as the new lookahead token and return it. 15809 */ 15810 15811 15812 fetch() { 15813 if (this.nextToken == null) { 15814 this.nextToken = this.gullet.expandNextToken(); 15815 } 15816 15817 return this.nextToken; 15818 } 15819 /** 15820 * Switches between "text" and "math" modes. 15821 */ 15822 15823 15824 switchMode(newMode) { 15825 this.mode = newMode; 15826 this.gullet.switchMode(newMode); 15827 } 15828 /** 15829 * Main parsing function, which parses an entire input. 15830 */ 15831 15832 15833 parse() { 15834 // Create a group namespace for the math expression. 15835 // (LaTeX creates a new group for every $...$, $$...$$, \[...\].) 15836 this.gullet.beginGroup(); // Use old \color behavior (same as LaTeX's \textcolor) if requested. 15837 // We do this within the group for the math expression, so it doesn't 15838 // pollute settings.macros. 15839 15840 if (this.settings.colorIsTextColor) { 15841 this.gullet.macros.set("\\color", "\\textcolor"); 15842 } // Try to parse the input 15843 15844 15845 const parse = this.parseExpression(false); // If we succeeded, make sure there's an EOF at the end 15846 15847 this.expect("EOF"); // End the group namespace for the expression 15848 15849 this.gullet.endGroup(); 15850 return parse; 15851 } 15852 15853 parseExpression(breakOnInfix, breakOnTokenText) { 15854 const body = []; // Keep adding atoms to the body until we can't parse any more atoms (either 15855 // we reached the end, a }, or a \right) 15856 15857 while (true) { 15858 // Ignore spaces in math mode 15859 if (this.mode === "math") { 15860 this.consumeSpaces(); 15861 } 15862 15863 const lex = this.fetch(); 15864 15865 if (Parser.endOfExpression.indexOf(lex.text) !== -1) { 15866 break; 15867 } 15868 15869 if (breakOnTokenText && lex.text === breakOnTokenText) { 15870 break; 15871 } 15872 15873 if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { 15874 break; 15875 } 15876 15877 const atom = this.parseAtom(breakOnTokenText); 15878 15879 if (!atom) { 15880 break; 15881 } 15882 15883 body.push(atom); 15884 } 15885 15886 if (this.mode === "text") { 15887 this.formLigatures(body); 15888 } 15889 15890 return this.handleInfixNodes(body); 15891 } 15892 /** 15893 * Rewrites infix operators such as \over with corresponding commands such 15894 * as \frac. 15895 * 15896 * There can only be one infix operator per group. If there's more than one 15897 * then the expression is ambiguous. This can be resolved by adding {}. 15898 */ 15899 15900 15901 handleInfixNodes(body) { 15902 let overIndex = -1; 15903 let funcName; 15904 15905 for (let i = 0; i < body.length; i++) { 15906 const node = checkNodeType(body[i], "infix"); 15907 15908 if (node) { 15909 if (overIndex !== -1) { 15910 throw new ParseError("only one infix operator per group", node.token); 15911 } 15912 15913 overIndex = i; 15914 funcName = node.replaceWith; 15915 } 15916 } 15917 15918 if (overIndex !== -1 && funcName) { 15919 let numerNode; 15920 let denomNode; 15921 const numerBody = body.slice(0, overIndex); 15922 const denomBody = body.slice(overIndex + 1); 15923 15924 if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { 15925 numerNode = numerBody[0]; 15926 } else { 15927 numerNode = { 15928 type: "ordgroup", 15929 mode: this.mode, 15930 body: numerBody 15931 }; 15932 } 15933 15934 if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { 15935 denomNode = denomBody[0]; 15936 } else { 15937 denomNode = { 15938 type: "ordgroup", 15939 mode: this.mode, 15940 body: denomBody 15941 }; 15942 } 15943 15944 let node; 15945 15946 if (funcName === "\\\\abovefrac") { 15947 node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); 15948 } else { 15949 node = this.callFunction(funcName, [numerNode, denomNode], []); 15950 } 15951 15952 return [node]; 15953 } else { 15954 return body; 15955 } 15956 } // The greediness of a superscript or subscript 15957 15958 15959 /** 15960 * Handle a subscript or superscript with nice errors. 15961 */ 15962 handleSupSubscript(name) { 15963 const symbolToken = this.fetch(); 15964 const symbol = symbolToken.text; 15965 this.consume(); 15966 const group = this.parseGroup(name, false, Parser.SUPSUB_GREEDINESS, undefined, undefined, true); // ignore spaces before sup/subscript argument 15967 15968 if (!group) { 15969 throw new ParseError("Expected group after '" + symbol + "'", symbolToken); 15970 } 15971 15972 return group; 15973 } 15974 /** 15975 * Converts the textual input of an unsupported command into a text node 15976 * contained within a color node whose color is determined by errorColor 15977 */ 15978 15979 15980 formatUnsupportedCmd(text) { 15981 const textordArray = []; 15982 15983 for (let i = 0; i < text.length; i++) { 15984 textordArray.push({ 15985 type: "textord", 15986 mode: "text", 15987 text: text[i] 15988 }); 15989 } 15990 15991 const textNode = { 15992 type: "text", 15993 mode: this.mode, 15994 body: textordArray 15995 }; 15996 const colorNode = { 15997 type: "color", 15998 mode: this.mode, 15999 color: this.settings.errorColor, 16000 body: [textNode] 16001 }; 16002 return colorNode; 16003 } 16004 /** 16005 * Parses a group with optional super/subscripts. 16006 */ 16007 16008 16009 parseAtom(breakOnTokenText) { 16010 // The body of an atom is an implicit group, so that things like 16011 // \left(x\right)^2 work correctly. 16012 const base = this.parseGroup("atom", false, null, breakOnTokenText); // In text mode, we don't have superscripts or subscripts 16013 16014 if (this.mode === "text") { 16015 return base; 16016 } // Note that base may be empty (i.e. null) at this point. 16017 16018 16019 let superscript; 16020 let subscript; 16021 16022 while (true) { 16023 // Guaranteed in math mode, so eat any spaces first. 16024 this.consumeSpaces(); // Lex the first token 16025 16026 const lex = this.fetch(); 16027 16028 if (lex.text === "\\limits" || lex.text === "\\nolimits") { 16029 // We got a limit control 16030 let opNode = checkNodeType(base, "op"); 16031 16032 if (opNode) { 16033 const limits = lex.text === "\\limits"; 16034 opNode.limits = limits; 16035 opNode.alwaysHandleSupSub = true; 16036 } else { 16037 opNode = checkNodeType(base, "operatorname"); 16038 16039 if (opNode && opNode.alwaysHandleSupSub) { 16040 const limits = lex.text === "\\limits"; 16041 opNode.limits = limits; 16042 } else { 16043 throw new ParseError("Limit controls must follow a math operator", lex); 16044 } 16045 } 16046 16047 this.consume(); 16048 } else if (lex.text === "^") { 16049 // We got a superscript start 16050 if (superscript) { 16051 throw new ParseError("Double superscript", lex); 16052 } 16053 16054 superscript = this.handleSupSubscript("superscript"); 16055 } else if (lex.text === "_") { 16056 // We got a subscript start 16057 if (subscript) { 16058 throw new ParseError("Double subscript", lex); 16059 } 16060 16061 subscript = this.handleSupSubscript("subscript"); 16062 } else if (lex.text === "'") { 16063 // We got a prime 16064 if (superscript) { 16065 throw new ParseError("Double superscript", lex); 16066 } 16067 16068 const prime = { 16069 type: "textord", 16070 mode: this.mode, 16071 text: "\\prime" 16072 }; // Many primes can be grouped together, so we handle this here 16073 16074 const primes = [prime]; 16075 this.consume(); // Keep lexing tokens until we get something that's not a prime 16076 16077 while (this.fetch().text === "'") { 16078 // For each one, add another prime to the list 16079 primes.push(prime); 16080 this.consume(); 16081 } // If there's a superscript following the primes, combine that 16082 // superscript in with the primes. 16083 16084 16085 if (this.fetch().text === "^") { 16086 primes.push(this.handleSupSubscript("superscript")); 16087 } // Put everything into an ordgroup as the superscript 16088 16089 16090 superscript = { 16091 type: "ordgroup", 16092 mode: this.mode, 16093 body: primes 16094 }; 16095 } else { 16096 // If it wasn't ^, _, or ', stop parsing super/subscripts 16097 break; 16098 } 16099 } // Base must be set if superscript or subscript are set per logic above, 16100 // but need to check here for type check to pass. 16101 16102 16103 if (superscript || subscript) { 16104 // If we got either a superscript or subscript, create a supsub 16105 return { 16106 type: "supsub", 16107 mode: this.mode, 16108 base: base, 16109 sup: superscript, 16110 sub: subscript 16111 }; 16112 } else { 16113 // Otherwise return the original body 16114 return base; 16115 } 16116 } 16117 /** 16118 * Parses an entire function, including its base and all of its arguments. 16119 */ 16120 16121 16122 parseFunction(breakOnTokenText, name, // For error reporting. 16123 greediness) { 16124 const token = this.fetch(); 16125 const func = token.text; 16126 const funcData = functions[func]; 16127 16128 if (!funcData) { 16129 return null; 16130 } 16131 16132 this.consume(); // consume command token 16133 16134 if (greediness != null && funcData.greediness <= greediness) { 16135 throw new ParseError("Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), token); 16136 } else if (this.mode === "text" && !funcData.allowedInText) { 16137 throw new ParseError("Can't use function '" + func + "' in text mode", token); 16138 } else if (this.mode === "math" && funcData.allowedInMath === false) { 16139 throw new ParseError("Can't use function '" + func + "' in math mode", token); 16140 } 16141 16142 const _this$parseArguments = this.parseArguments(func, funcData), 16143 args = _this$parseArguments.args, 16144 optArgs = _this$parseArguments.optArgs; 16145 16146 return this.callFunction(func, args, optArgs, token, breakOnTokenText); 16147 } 16148 /** 16149 * Call a function handler with a suitable context and arguments. 16150 */ 16151 16152 16153 callFunction(name, args, optArgs, token, breakOnTokenText) { 16154 const context = { 16155 funcName: name, 16156 parser: this, 16157 token, 16158 breakOnTokenText 16159 }; 16160 const func = functions[name]; 16161 16162 if (func && func.handler) { 16163 return func.handler(context, args, optArgs); 16164 } else { 16165 throw new ParseError(`No function handler for ${name}`); 16166 } 16167 } 16168 /** 16169 * Parses the arguments of a function or environment 16170 */ 16171 16172 16173 parseArguments(func, // Should look like "\name" or "\begin{name}". 16174 funcData) { 16175 const totalArgs = funcData.numArgs + funcData.numOptionalArgs; 16176 16177 if (totalArgs === 0) { 16178 return { 16179 args: [], 16180 optArgs: [] 16181 }; 16182 } 16183 16184 const baseGreediness = funcData.greediness; 16185 const args = []; 16186 const optArgs = []; 16187 16188 for (let i = 0; i < totalArgs; i++) { 16189 const argType = funcData.argTypes && funcData.argTypes[i]; 16190 const isOptional = i < funcData.numOptionalArgs; // Ignore spaces between arguments. As the TeXbook says: 16191 // "After you have said ‘\def\row#1#2{...}’, you are allowed to 16192 // put spaces between the arguments (e.g., ‘\row x n’), because 16193 // TeX doesn’t use single spaces as undelimited arguments." 16194 16195 const consumeSpaces = i > 0 && !isOptional || // Also consume leading spaces in math mode, as parseSymbol 16196 // won't know what to do with them. This can only happen with 16197 // macros, e.g. \frac\foo\foo where \foo expands to a space symbol. 16198 // In LaTeX, the \foo's get treated as (blank) arguments. 16199 // In KaTeX, for now, both spaces will get consumed. 16200 // TODO(edemaine) 16201 i === 0 && !isOptional && this.mode === "math"; 16202 const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional, baseGreediness, consumeSpaces); 16203 16204 if (!arg) { 16205 if (isOptional) { 16206 optArgs.push(null); 16207 continue; 16208 } 16209 16210 throw new ParseError(`Expected group after '${func}'`, this.fetch()); 16211 } 16212 16213 (isOptional ? optArgs : args).push(arg); 16214 } 16215 16216 return { 16217 args, 16218 optArgs 16219 }; 16220 } 16221 /** 16222 * Parses a group when the mode is changing. 16223 */ 16224 16225 16226 parseGroupOfType(name, type, optional, greediness, consumeSpaces) { 16227 switch (type) { 16228 case "color": 16229 if (consumeSpaces) { 16230 this.consumeSpaces(); 16231 } 16232 16233 return this.parseColorGroup(optional); 16234 16235 case "size": 16236 if (consumeSpaces) { 16237 this.consumeSpaces(); 16238 } 16239 16240 return this.parseSizeGroup(optional); 16241 16242 case "url": 16243 return this.parseUrlGroup(optional, consumeSpaces); 16244 16245 case "math": 16246 case "text": 16247 return this.parseGroup(name, optional, greediness, undefined, type, consumeSpaces); 16248 16249 case "hbox": 16250 { 16251 // hbox argument type wraps the argument in the equivalent of 16252 // \hbox, which is like \text but switching to \textstyle size. 16253 const group = this.parseGroup(name, optional, greediness, undefined, "text", consumeSpaces); 16254 16255 if (!group) { 16256 return group; 16257 } 16258 16259 const styledGroup = { 16260 type: "styling", 16261 mode: group.mode, 16262 body: [group], 16263 style: "text" // simulate \textstyle 16264 16265 }; 16266 return styledGroup; 16267 } 16268 16269 case "raw": 16270 { 16271 if (consumeSpaces) { 16272 this.consumeSpaces(); 16273 } 16274 16275 if (optional && this.fetch().text === "{") { 16276 return null; 16277 } 16278 16279 const token = this.parseStringGroup("raw", optional, true); 16280 16281 if (token) { 16282 return { 16283 type: "raw", 16284 mode: "text", 16285 string: token.text 16286 }; 16287 } else { 16288 throw new ParseError("Expected raw group", this.fetch()); 16289 } 16290 } 16291 16292 case "original": 16293 case null: 16294 case undefined: 16295 return this.parseGroup(name, optional, greediness, undefined, undefined, consumeSpaces); 16296 16297 default: 16298 throw new ParseError("Unknown group type as " + name, this.fetch()); 16299 } 16300 } 16301 /** 16302 * Discard any space tokens, fetching the next non-space token. 16303 */ 16304 16305 16306 consumeSpaces() { 16307 while (this.fetch().text === " ") { 16308 this.consume(); 16309 } 16310 } 16311 /** 16312 * Parses a group, essentially returning the string formed by the 16313 * brace-enclosed tokens plus some position information. 16314 */ 16315 16316 16317 parseStringGroup(modeName, // Used to describe the mode in error messages. 16318 optional, raw) { 16319 const groupBegin = optional ? "[" : "{"; 16320 const groupEnd = optional ? "]" : "}"; 16321 const beginToken = this.fetch(); 16322 16323 if (beginToken.text !== groupBegin) { 16324 if (optional) { 16325 return null; 16326 } else if (raw && beginToken.text !== "EOF" && /[^{}[\]]/.test(beginToken.text)) { 16327 this.consume(); 16328 return beginToken; 16329 } 16330 } 16331 16332 const outerMode = this.mode; 16333 this.mode = "text"; 16334 this.expect(groupBegin); 16335 let str = ""; 16336 const firstToken = this.fetch(); 16337 let nested = 0; // allow nested braces in raw string group 16338 16339 let lastToken = firstToken; 16340 let nextToken; 16341 16342 while ((nextToken = this.fetch()).text !== groupEnd || raw && nested > 0) { 16343 switch (nextToken.text) { 16344 case "EOF": 16345 throw new ParseError("Unexpected end of input in " + modeName, firstToken.range(lastToken, str)); 16346 16347 case groupBegin: 16348 nested++; 16349 break; 16350 16351 case groupEnd: 16352 nested--; 16353 break; 16354 } 16355 16356 lastToken = nextToken; 16357 str += lastToken.text; 16358 this.consume(); 16359 } 16360 16361 this.expect(groupEnd); 16362 this.mode = outerMode; 16363 return firstToken.range(lastToken, str); 16364 } 16365 /** 16366 * Parses a regex-delimited group: the largest sequence of tokens 16367 * whose concatenated strings match `regex`. Returns the string 16368 * formed by the tokens plus some position information. 16369 */ 16370 16371 16372 parseRegexGroup(regex, modeName) { 16373 const outerMode = this.mode; 16374 this.mode = "text"; 16375 const firstToken = this.fetch(); 16376 let lastToken = firstToken; 16377 let str = ""; 16378 let nextToken; 16379 16380 while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { 16381 lastToken = nextToken; 16382 str += lastToken.text; 16383 this.consume(); 16384 } 16385 16386 if (str === "") { 16387 throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); 16388 } 16389 16390 this.mode = outerMode; 16391 return firstToken.range(lastToken, str); 16392 } 16393 /** 16394 * Parses a color description. 16395 */ 16396 16397 16398 parseColorGroup(optional) { 16399 const res = this.parseStringGroup("color", optional); 16400 16401 if (!res) { 16402 return null; 16403 } 16404 16405 const match = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i.exec(res.text); 16406 16407 if (!match) { 16408 throw new ParseError("Invalid color: '" + res.text + "'", res); 16409 } 16410 16411 let color = match[0]; 16412 16413 if (/^[0-9a-f]{6}$/i.test(color)) { 16414 // We allow a 6-digit HTML color spec without a leading "#". 16415 // This follows the xcolor package's HTML color model. 16416 // Predefined color names are all missed by this RegEx pattern. 16417 color = "#" + color; 16418 } 16419 16420 return { 16421 type: "color-token", 16422 mode: this.mode, 16423 color 16424 }; 16425 } 16426 /** 16427 * Parses a size specification, consisting of magnitude and unit. 16428 */ 16429 16430 16431 parseSizeGroup(optional) { 16432 let res; 16433 let isBlank = false; 16434 16435 if (!optional && this.fetch().text !== "{") { 16436 res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); 16437 } else { 16438 res = this.parseStringGroup("size", optional); 16439 } 16440 16441 if (!res) { 16442 return null; 16443 } 16444 16445 if (!optional && res.text.length === 0) { 16446 // Because we've tested for what is !optional, this block won't 16447 // affect \kern, \hspace, etc. It will capture the mandatory arguments 16448 // to \genfrac and \above. 16449 res.text = "0pt"; // Enable \above{} 16450 16451 isBlank = true; // This is here specifically for \genfrac 16452 } 16453 16454 const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); 16455 16456 if (!match) { 16457 throw new ParseError("Invalid size: '" + res.text + "'", res); 16458 } 16459 16460 const data = { 16461 number: +(match[1] + match[2]), 16462 // sign + magnitude, cast to number 16463 unit: match[3] 16464 }; 16465 16466 if (!validUnit(data)) { 16467 throw new ParseError("Invalid unit: '" + data.unit + "'", res); 16468 } 16469 16470 return { 16471 type: "size", 16472 mode: this.mode, 16473 value: data, 16474 isBlank 16475 }; 16476 } 16477 /** 16478 * Parses an URL, checking escaped letters and allowed protocols, 16479 * and setting the catcode of % as an active character (as in \hyperref). 16480 */ 16481 16482 16483 parseUrlGroup(optional, consumeSpaces) { 16484 this.gullet.lexer.setCatcode("%", 13); // active character 16485 16486 const res = this.parseStringGroup("url", optional, true); // get raw string 16487 16488 this.gullet.lexer.setCatcode("%", 14); // comment character 16489 16490 if (!res) { 16491 return null; 16492 } // hyperref package allows backslashes alone in href, but doesn't 16493 // generate valid links in such cases; we interpret this as 16494 // "undefined" behaviour, and keep them as-is. Some browser will 16495 // replace backslashes with forward slashes. 16496 16497 16498 const url = res.text.replace(/\\([#$%&~_^{}])/g, '$1'); 16499 return { 16500 type: "url", 16501 mode: this.mode, 16502 url 16503 }; 16504 } 16505 /** 16506 * If `optional` is false or absent, this parses an ordinary group, 16507 * which is either a single nucleus (like "x") or an expression 16508 * in braces (like "{x+y}") or an implicit group, a group that starts 16509 * at the current position, and ends right before a higher explicit 16510 * group ends, or at EOF. 16511 * If `optional` is true, it parses either a bracket-delimited expression 16512 * (like "[x+y]") or returns null to indicate the absence of a 16513 * bracket-enclosed group. 16514 * If `mode` is present, switches to that mode while parsing the group, 16515 * and switches back after. 16516 */ 16517 16518 16519 parseGroup(name, // For error reporting. 16520 optional, greediness, breakOnTokenText, mode, consumeSpaces) { 16521 // Switch to specified mode 16522 const outerMode = this.mode; 16523 16524 if (mode) { 16525 this.switchMode(mode); 16526 } // Consume spaces if requested, crucially *after* we switch modes, 16527 // so that the next non-space token is parsed in the correct mode. 16528 16529 16530 if (consumeSpaces) { 16531 this.consumeSpaces(); 16532 } // Get first token 16533 16534 16535 const firstToken = this.fetch(); 16536 const text = firstToken.text; 16537 let result; // Try to parse an open brace or \begingroup 16538 16539 if (optional ? text === "[" : text === "{" || text === "\\begingroup") { 16540 this.consume(); 16541 const groupEnd = Parser.endOfGroup[text]; // Start a new group namespace 16542 16543 this.gullet.beginGroup(); // If we get a brace, parse an expression 16544 16545 const expression = this.parseExpression(false, groupEnd); 16546 const lastToken = this.fetch(); // Check that we got a matching closing brace 16547 16548 this.expect(groupEnd); // End group namespace 16549 16550 this.gullet.endGroup(); 16551 result = { 16552 type: "ordgroup", 16553 mode: this.mode, 16554 loc: SourceLocation.range(firstToken, lastToken), 16555 body: expression, 16556 // A group formed by \begingroup...\endgroup is a semi-simple group 16557 // which doesn't affect spacing in math mode, i.e., is transparent. 16558 // https://tex.stackexchange.com/questions/1930/when-should-one- 16559 // use-begingroup-instead-of-bgroup 16560 semisimple: text === "\\begingroup" || undefined 16561 }; 16562 } else if (optional) { 16563 // Return nothing for an optional group 16564 result = null; 16565 } else { 16566 // If there exists a function with this name, parse the function. 16567 // Otherwise, just return a nucleus 16568 result = this.parseFunction(breakOnTokenText, name, greediness) || this.parseSymbol(); 16569 16570 if (result == null && text[0] === "\\" && !implicitCommands.hasOwnProperty(text)) { 16571 if (this.settings.throwOnError) { 16572 throw new ParseError("Undefined control sequence: " + text, firstToken); 16573 } 16574 16575 result = this.formatUnsupportedCmd(text); 16576 this.consume(); 16577 } 16578 } // Switch mode back 16579 16580 16581 if (mode) { 16582 this.switchMode(outerMode); 16583 } 16584 16585 return result; 16586 } 16587 /** 16588 * Form ligature-like combinations of characters for text mode. 16589 * This includes inputs like "--", "---", "``" and "''". 16590 * The result will simply replace multiple textord nodes with a single 16591 * character in each value by a single textord node having multiple 16592 * characters in its value. The representation is still ASCII source. 16593 * The group will be modified in place. 16594 */ 16595 16596 16597 formLigatures(group) { 16598 let n = group.length - 1; 16599 16600 for (let i = 0; i < n; ++i) { 16601 const a = group[i]; // $FlowFixMe: Not every node type has a `text` property. 16602 16603 const v = a.text; 16604 16605 if (v === "-" && group[i + 1].text === "-") { 16606 if (i + 1 < n && group[i + 2].text === "-") { 16607 group.splice(i, 3, { 16608 type: "textord", 16609 mode: "text", 16610 loc: SourceLocation.range(a, group[i + 2]), 16611 text: "---" 16612 }); 16613 n -= 2; 16614 } else { 16615 group.splice(i, 2, { 16616 type: "textord", 16617 mode: "text", 16618 loc: SourceLocation.range(a, group[i + 1]), 16619 text: "--" 16620 }); 16621 n -= 1; 16622 } 16623 } 16624 16625 if ((v === "'" || v === "`") && group[i + 1].text === v) { 16626 group.splice(i, 2, { 16627 type: "textord", 16628 mode: "text", 16629 loc: SourceLocation.range(a, group[i + 1]), 16630 text: v + v 16631 }); 16632 n -= 1; 16633 } 16634 } 16635 } 16636 /** 16637 * Parse a single symbol out of the string. Here, we handle single character 16638 * symbols and special functions like \verb. 16639 */ 16640 16641 16642 parseSymbol() { 16643 const nucleus = this.fetch(); 16644 let text = nucleus.text; 16645 16646 if (/^\\verb[^a-zA-Z]/.test(text)) { 16647 this.consume(); 16648 let arg = text.slice(5); 16649 const star = arg.charAt(0) === "*"; 16650 16651 if (star) { 16652 arg = arg.slice(1); 16653 } // Lexer's tokenRegex is constructed to always have matching 16654 // first/last characters. 16655 16656 16657 if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { 16658 throw new ParseError(`\\verb assertion failed -- 16659 please report what input caused this bug`); 16660 } 16661 16662 arg = arg.slice(1, -1); // remove first and last char 16663 16664 return { 16665 type: "verb", 16666 mode: "text", 16667 body: arg, 16668 star 16669 }; 16670 } // At this point, we should have a symbol, possibly with accents. 16671 // First expand any accented base symbol according to unicodeSymbols. 16672 16673 16674 if (unicodeSymbols.hasOwnProperty(text[0]) && !symbols[this.mode][text[0]]) { 16675 // This behavior is not strict (XeTeX-compatible) in math mode. 16676 if (this.settings.strict && this.mode === "math") { 16677 this.settings.reportNonstrict("unicodeTextInMathMode", `Accented Unicode text character "${text[0]}" used in ` + `math mode`, nucleus); 16678 } 16679 16680 text = unicodeSymbols[text[0]] + text.substr(1); 16681 } // Strip off any combining characters 16682 16683 16684 const match = combiningDiacriticalMarksEndRegex.exec(text); 16685 16686 if (match) { 16687 text = text.substring(0, match.index); 16688 16689 if (text === 'i') { 16690 text = '\u0131'; // dotless i, in math and text mode 16691 } else if (text === 'j') { 16692 text = '\u0237'; // dotless j, in math and text mode 16693 } 16694 } // Recognize base symbol 16695 16696 16697 let symbol; 16698 16699 if (symbols[this.mode][text]) { 16700 if (this.settings.strict && this.mode === 'math' && extraLatin.indexOf(text) >= 0) { 16701 this.settings.reportNonstrict("unicodeTextInMathMode", `Latin-1/Unicode text character "${text[0]}" used in ` + `math mode`, nucleus); 16702 } 16703 16704 const group = symbols[this.mode][text].group; 16705 const loc = SourceLocation.range(nucleus); 16706 let s; 16707 16708 if (ATOMS.hasOwnProperty(group)) { 16709 // $FlowFixMe 16710 const family = group; 16711 s = { 16712 type: "atom", 16713 mode: this.mode, 16714 family, 16715 loc, 16716 text 16717 }; 16718 } else { 16719 // $FlowFixMe 16720 s = { 16721 type: group, 16722 mode: this.mode, 16723 loc, 16724 text 16725 }; 16726 } 16727 16728 symbol = s; 16729 } else if (text.charCodeAt(0) >= 0x80) { 16730 // no symbol for e.g. ^ 16731 if (this.settings.strict) { 16732 if (!supportedCodepoint(text.charCodeAt(0))) { 16733 this.settings.reportNonstrict("unknownSymbol", `Unrecognized Unicode character "${text[0]}"` + ` (${text.charCodeAt(0)})`, nucleus); 16734 } else if (this.mode === "math") { 16735 this.settings.reportNonstrict("unicodeTextInMathMode", `Unicode text character "${text[0]}" used in math mode`, nucleus); 16736 } 16737 } // All nonmathematical Unicode characters are rendered as if they 16738 // are in text mode (wrapped in \text) because that's what it 16739 // takes to render them in LaTeX. Setting `mode: this.mode` is 16740 // another natural choice (the user requested math mode), but 16741 // this makes it more difficult for getCharacterMetrics() to 16742 // distinguish Unicode characters without metrics and those for 16743 // which we want to simulate the letter M. 16744 16745 16746 symbol = { 16747 type: "textord", 16748 mode: "text", 16749 loc: SourceLocation.range(nucleus), 16750 text 16751 }; 16752 } else { 16753 return null; // EOF, ^, _, {, }, etc. 16754 } 16755 16756 this.consume(); // Transform combining characters into accents 16757 16758 if (match) { 16759 for (let i = 0; i < match[0].length; i++) { 16760 const accent = match[0][i]; 16761 16762 if (!unicodeAccents[accent]) { 16763 throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); 16764 } 16765 16766 const command = unicodeAccents[accent][this.mode]; 16767 16768 if (!command) { 16769 throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); 16770 } 16771 16772 symbol = { 16773 type: "accent", 16774 mode: this.mode, 16775 loc: SourceLocation.range(nucleus), 16776 label: command, 16777 isStretchy: false, 16778 isShifty: true, 16779 base: symbol 16780 }; 16781 } 16782 } 16783 16784 return symbol; 16785 } 16786 16787} 16788Parser.endOfExpression = ["}", "\\endgroup", "\\end", "\\right", "&"]; 16789Parser.endOfGroup = { 16790 "[": "]", 16791 "{": "}", 16792 "\\begingroup": "\\endgroup" 16793 /** 16794 * Parses an "expression", which is a list of atoms. 16795 * 16796 * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This 16797 * happens when functions have higher precendence han infix 16798 * nodes in implicit parses. 16799 * 16800 * `breakOnTokenText`: The text of the token that the expression should end 16801 * with, or `null` if something else should end the 16802 * expression. 16803 */ 16804 16805}; 16806Parser.SUPSUB_GREEDINESS = 1; 16807 16808/** 16809 * Provides a single function for parsing an expression using a Parser 16810 * TODO(emily): Remove this 16811 */ 16812 16813/** 16814 * Parses an expression using a Parser, then returns the parsed result. 16815 */ 16816const parseTree = function parseTree(toParse, settings) { 16817 if (!(typeof toParse === 'string' || toParse instanceof String)) { 16818 throw new TypeError('KaTeX can only parse string typed expression'); 16819 } 16820 16821 const parser = new Parser(toParse, settings); // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors 16822 16823 delete parser.gullet.macros.current["\\df@tag"]; 16824 let tree = parser.parse(); // If the input used \tag, it will set the \df@tag macro to the tag. 16825 // In this case, we separately parse the tag and wrap the tree. 16826 16827 if (parser.gullet.macros.get("\\df@tag")) { 16828 if (!settings.displayMode) { 16829 throw new ParseError("\\tag works only in display equations"); 16830 } 16831 16832 parser.gullet.feed("\\df@tag"); 16833 tree = [{ 16834 type: "tag", 16835 mode: "text", 16836 body: tree, 16837 tag: parser.parse() 16838 }]; 16839 } 16840 16841 return tree; 16842}; 16843 16844/* eslint no-console:0 */ 16845 16846/** 16847 * Parse and build an expression, and place that expression in the DOM node 16848 * given. 16849 */ 16850let render = function render(expression, baseNode, options) { 16851 baseNode.textContent = ""; 16852 const node = renderToDomTree(expression, options).toNode(); 16853 baseNode.appendChild(node); 16854}; // KaTeX's styles don't work properly in quirks mode. Print out an error, and 16855// disable rendering. 16856 16857 16858if (typeof document !== "undefined") { 16859 if (document.compatMode !== "CSS1Compat") { 16860 typeof console !== "undefined" && console.warn("Warning: KaTeX doesn't work in quirks mode. Make sure your " + "website has a suitable doctype."); 16861 16862 render = function render() { 16863 throw new ParseError("KaTeX doesn't work in quirks mode."); 16864 }; 16865 } 16866} 16867/** 16868 * Parse and build an expression, and return the markup for that. 16869 */ 16870 16871 16872const renderToString = function renderToString(expression, options) { 16873 const markup = renderToDomTree(expression, options).toMarkup(); 16874 return markup; 16875}; 16876/** 16877 * Parse an expression and return the parse tree. 16878 */ 16879 16880 16881const generateParseTree = function generateParseTree(expression, options) { 16882 const settings = new Settings(options); 16883 return parseTree(expression, settings); 16884}; 16885/** 16886 * If the given error is a KaTeX ParseError and options.throwOnError is false, 16887 * renders the invalid LaTeX as a span with hover title giving the KaTeX 16888 * error message. Otherwise, simply throws the error. 16889 */ 16890 16891 16892const renderError = function renderError(error, expression, options) { 16893 if (options.throwOnError || !(error instanceof ParseError)) { 16894 throw error; 16895 } 16896 16897 const node = buildCommon.makeSpan(["katex-error"], [new SymbolNode(expression)]); 16898 node.setAttribute("title", error.toString()); 16899 node.setAttribute("style", `color:${options.errorColor}`); 16900 return node; 16901}; 16902/** 16903 * Generates and returns the katex build tree. This is used for advanced 16904 * use cases (like rendering to custom output). 16905 */ 16906 16907 16908const renderToDomTree = function renderToDomTree(expression, options) { 16909 const settings = new Settings(options); 16910 16911 try { 16912 const tree = parseTree(expression, settings); 16913 return buildTree(tree, expression, settings); 16914 } catch (error) { 16915 return renderError(error, expression, settings); 16916 } 16917}; 16918/** 16919 * Generates and returns the katex build tree, with just HTML (no MathML). 16920 * This is used for advanced use cases (like rendering to custom output). 16921 */ 16922 16923 16924const renderToHTMLTree = function renderToHTMLTree(expression, options) { 16925 const settings = new Settings(options); 16926 16927 try { 16928 const tree = parseTree(expression, settings); 16929 return buildHTMLTree(tree, expression, settings); 16930 } catch (error) { 16931 return renderError(error, expression, settings); 16932 } 16933}; 16934 16935var katex = { 16936 /** 16937 * Current KaTeX version 16938 */ 16939 version: "0.11.1", 16940 16941 /** 16942 * Renders the given LaTeX into an HTML+MathML combination, and adds 16943 * it as a child to the specified DOM node. 16944 */ 16945 render, 16946 16947 /** 16948 * Renders the given LaTeX into an HTML+MathML combination string, 16949 * for sending to the client. 16950 */ 16951 renderToString, 16952 16953 /** 16954 * KaTeX error, usually during parsing. 16955 */ 16956 ParseError, 16957 16958 /** 16959 * Parses the given LaTeX into KaTeX's internal parse tree structure, 16960 * without rendering to HTML or MathML. 16961 * 16962 * NOTE: This method is not currently recommended for public use. 16963 * The internal tree representation is unstable and is very likely 16964 * to change. Use at your own risk. 16965 */ 16966 __parse: generateParseTree, 16967 16968 /** 16969 * Renders the given LaTeX into an HTML+MathML internal DOM tree 16970 * representation, without flattening that representation to a string. 16971 * 16972 * NOTE: This method is not currently recommended for public use. 16973 * The internal tree representation is unstable and is very likely 16974 * to change. Use at your own risk. 16975 */ 16976 __renderToDomTree: renderToDomTree, 16977 16978 /** 16979 * Renders the given LaTeX into an HTML internal DOM tree representation, 16980 * without MathML and without flattening that representation to a string. 16981 * 16982 * NOTE: This method is not currently recommended for public use. 16983 * The internal tree representation is unstable and is very likely 16984 * to change. Use at your own risk. 16985 */ 16986 __renderToHTMLTree: renderToHTMLTree, 16987 16988 /** 16989 * extends internal font metrics object with a new object 16990 * each key in the new object represents a font name 16991 */ 16992 __setFontMetrics: setFontMetrics, 16993 16994 /** 16995 * adds a new symbol to builtin symbols table 16996 */ 16997 __defineSymbol: defineSymbol, 16998 16999 /** 17000 * adds a new macro to builtin macro list 17001 */ 17002 __defineMacro: defineMacro, 17003 17004 /** 17005 * Expose the dom tree node types, which can be useful for type checking nodes. 17006 * 17007 * NOTE: This method is not currently recommended for public use. 17008 * The internal tree representation is unstable and is very likely 17009 * to change. Use at your own risk. 17010 */ 17011 __domTree: { 17012 Span, 17013 Anchor, 17014 SymbolNode, 17015 SvgNode, 17016 PathNode, 17017 LineNode 17018 } 17019}; 17020 17021export default katex; 17022