www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit f63af87f17fedfd0c4cab753a3d4f7a0a5290bc0
parent 79a5687057de6267ac71f507989d77a5e4a6812f
Author: Emily Eisenberg <emily@khanacademy.org>
Date:   Sun, 14 Sep 2014 19:23:39 -0700

Add looots of comments

Summary:
Add comments everywhere! Also fix some small bugs like using Style.id
instead of Style.size, and rename some variables to be more descriptive.

Fixes #22

Test Plan:
 - Make sure the huxley screenshots didn't change
 - Make sure the tests still pass

Reviewers: alpert

Reviewed By: alpert

Differential Revision: http://phabricator.khanacademy.org/D13158

Diffstat:
MLexer.js | 58+++++++++++++++++++++++++++++++++++++++++++++++-----------
MOptions.js | 37+++++++++++++++++++++++++++++++++++++
MParseError.js | 9+++++++++
MParser.js | 185+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
MStyle.js | 47+++++++++++++++++++++++++++++++++++++++++++++--
MbuildCommon.js | 43+++++++++++++++++++++++++++++++++++++++----
MbuildTree.js | 538+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mdelimiter.js | 167++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
MdomTree.js | 60+++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
MfontMetrics.js | 38++++++++++++++++++++++++++++++++++----
Mkatex.js | 15+++++++++++++++
MparseTree.js | 9++++++++-
Msymbols.js | 28++++++++++++++++++----------
Mutils.js | 20+++++++++++++++++++-
14 files changed, 956 insertions(+), 298 deletions(-)

diff --git a/Lexer.js b/Lexer.js @@ -1,3 +1,16 @@ +/** + * The Lexer class handles tokenizing the input in various ways. Since our + * parser expects us to be able to backtrack, the lexer allows lexing from any + * given starting point. + * + * Its main exposed function is the `lex` function, which takes a position to + * lex from and a type of token to lex. It defers to the appropriate `_innerLex` + * function. + * + * The various `_innerLex` functions perform the actual lexing of different + * kinds. + */ + var ParseError = require("./ParseError"); // The main lexer class @@ -5,14 +18,15 @@ function Lexer(input) { this._input = input; }; -// The result of a single lex +// The resulting token returned from `lex`. function LexResult(type, text, position) { this.type = type; this.text = text; this.position = position; } -// "normal" types of tokens +// "normal" types of tokens. These are tokens which can be matched by a simple +// regex, and have a type which is listed. var mathNormals = [ [/^[/|@."`0-9]/, "textord"], [/^[a-zA-Z]/, "mathord"], @@ -29,6 +43,8 @@ var mathNormals = [ [/^~/, "spacing"] ]; +// These are "normal" tokens like above, but should instead be parsed in text +// mode. var textNormals = [ [/^[a-zA-Z0-9`!@*()-=+\[\]'";:?\/.,]/, "textord"], [/^{/, "{"], @@ -36,22 +52,29 @@ var textNormals = [ [/^~/, "spacing"] ]; +// Regexes for matching whitespace var whitespaceRegex = /^\s*/; var whitespaceConcatRegex = /^( +|\\ +)/; -// Build a regex to easily parse the functions +// This regex matches any other TeX function, which is a backslash followed by a +// word or a single symbol var anyFunc = /^\\(?:[a-zA-Z]+|.)/; +/** + * This function lexes a single normal token. It takes a position, a list of + * "normal" tokens to try, and whether it should completely ignore whitespace or + * not. + */ Lexer.prototype._innerLex = function(pos, normals, ignoreWhitespace) { var input = this._input.slice(pos); - // Get rid of whitespace if (ignoreWhitespace) { + // Get rid of whitespace. var whitespace = input.match(whitespaceRegex)[0]; pos += whitespace.length; input = input.slice(whitespace.length); } else { - // Do the funky concatenation of whitespace + // Do the funky concatenation of whitespace that happens in text mode. var whitespace = input.match(whitespaceConcatRegex); if (whitespace !== null) { return new LexResult(" ", " ", pos + whitespace[0].length); @@ -65,7 +88,7 @@ Lexer.prototype._innerLex = function(pos, normals, ignoreWhitespace) { var match; if ((match = input.match(anyFunc))) { - // If we match one of the tokens, extract the type + // If we match a function token, return it return new LexResult(match[0], match[0], pos + match[0].length); } else { // Otherwise, we look through the normal token regexes and see if it's @@ -81,7 +104,6 @@ Lexer.prototype._innerLex = function(pos, normals, ignoreWhitespace) { } } - // We didn't match any of the tokens, so throw an error. throw new ParseError("Unexpected character: '" + input[0] + "'", this, pos); } @@ -89,6 +111,9 @@ Lexer.prototype._innerLex = function(pos, normals, ignoreWhitespace) { // A regex to match a CSS color (like #ffffff or BlueViolet) var cssColor = /^(#[a-z0-9]+|[a-z]+)/i; +/** + * This function lexes a CSS color. + */ Lexer.prototype._innerLexColor = function(pos) { var input = this._input.slice(pos); @@ -101,14 +126,18 @@ Lexer.prototype._innerLexColor = function(pos) { if ((match = input.match(cssColor))) { // If we look like a color, return a color return new LexResult("color", match[0], pos + match[0].length); + } else { + throw new ParseError("Invalid color", this, pos); } - - // We didn't match a color, so throw an error. - throw new ParseError("Invalid color", this, pos); }; +// A regex to match a dimension. Dimensions look like +// "1.2em" or ".4pt" or "1 ex" var sizeRegex = /^(\d+(?:\.\d*)?|\.\d+)\s*([a-z]{2})/; +/** + * This function lexes a dimension. + */ Lexer.prototype._innerLexSize = function(pos) { var input = this._input.slice(pos); @@ -120,6 +149,7 @@ Lexer.prototype._innerLexSize = function(pos) { var match; if ((match = input.match(sizeRegex))) { var unit = match[2]; + // We only currently handle "em" and "ex" units if (unit !== "em" && unit !== "ex") { throw new ParseError("Invalid unit: '" + unit + "'", this, pos); } @@ -132,6 +162,9 @@ Lexer.prototype._innerLexSize = function(pos) { throw new ParseError("Invalid size", this, pos); }; +/** + * This function lexes a string of whitespace. + */ Lexer.prototype._innerLexWhitespace = function(pos) { var input = this._input.slice(pos); @@ -141,7 +174,10 @@ Lexer.prototype._innerLexWhitespace = function(pos) { return new LexResult("whitespace", whitespace, pos); }; -// Lex a single token +/** + * This function lexes a single token starting at `pos` and of the given mode. + * Based on the mode, we defer to one of the `_innerLex` functions. + */ Lexer.prototype.lex = function(pos, mode) { if (mode === "math") { return this._innerLex(pos, mathNormals, true); diff --git a/Options.js b/Options.js @@ -1,3 +1,19 @@ +/** + * This file contains information about the options that the Parser carries + * around with it while parsing. Data is held in an `Options` object, and when + * recursing, a new `Options` object can be created with the `.with*` and + * `.reset` functions. + */ + +/** + * This is the main options class. It contains the style, size, and color of the + * current parse level. It also contains the style and size of the parent parse + * level, so size changes can be handled efficiently. + * + * Each of the `.with*` and `.reset` functions passes its current style and size + * as the parentStyle and parentSize of the new options class, so parent + * handling is taken care of automatically. + */ function Options(style, size, color, parentStyle, parentSize) { this.style = style; this.color = color; @@ -14,23 +30,40 @@ function Options(style, size, color, parentStyle, parentSize) { this.parentSize = parentSize; } +/** + * Create a new options object with the given style. + */ Options.prototype.withStyle = function(style) { return new Options(style, this.size, this.color, this.style, this.size); }; +/** + * Create a new options object with the given size. + */ Options.prototype.withSize = function(size) { return new Options(this.style, size, this.color, this.style, this.size); }; +/** + * Create a new options object with the given color. + */ Options.prototype.withColor = function(color) { return new Options(this.style, this.size, color, this.style, this.size); }; +/** + * Create a new options object with the same style, size, and color. This is + * used so that parent style and size changes are handled correctly. + */ Options.prototype.reset = function() { return new Options( this.style, this.size, this.color, this.style, this.size); }; +/** + * A map of color names to CSS colors. + * TODO(emily): Remove this when we have real macros + */ var colorMap = { "katex-blue": "#6495ed", "katex-orange": "#ffa500", @@ -41,6 +74,10 @@ var colorMap = { "katex-purple": "#9d38bd" }; +/** + * Gets the CSS color of the current options object, accounting for the + * `colorMap`. + */ Options.prototype.getColor = function() { return colorMap[this.color] || this.color; }; diff --git a/ParseError.js b/ParseError.js @@ -1,8 +1,14 @@ +/** + * This is the ParseError class, which is the main error thrown by KaTeX + * functions when something has gone wrong. This is used to distinguish internal + * errors from errors in the expression that the user provided. + */ function ParseError(message, lexer, position) { var error = "KaTeX parse error: " + message; if (lexer !== undefined && position !== undefined) { // If we have the input and a position, make the error a bit fancier + // Prepend some information error += " at position " + position + ": "; @@ -18,12 +24,15 @@ function ParseError(message, lexer, position) { error += input.slice(begin, end); } + // Some hackery to make ParseError a prototype of Error + // See http://stackoverflow.com/a/8460753 var self = new Error(error); self.name = "ParseError"; self.__proto__ = ParseError.prototype; return self; } +// More hackery ParseError.prototype.__proto__ = Error.prototype; module.exports = ParseError; diff --git a/Parser.js b/Parser.js @@ -5,60 +5,70 @@ var utils = require("./utils"); var ParseError = require("./ParseError"); -// This file contains the parser used to parse out a TeX expression from the -// input. Since TeX isn't context-free, standard parsers don't work particularly -// well. - -// The strategy of this parser is as such: -// -// The main functions (the `.parse...` ones) take a position in the current -// parse string to parse tokens from. The lexer (found in Lexer.js, stored at -// this.lexer) also supports pulling out tokens at arbitrary places. When -// individual tokens are needed at a position, the lexer is called to pull out a -// token, which is then used. -// -// The main functions also take a mode that the parser is currently in -// (currently "math" or "text"), which denotes whether the current environment -// is a math-y one or a text-y one (e.g. inside \text). Currently, this serves -// to limit the functions which can be used in text mode. -// -// The main functions then return an object which contains the useful data that -// was parsed at its given point, and a new position at the end of the parsed -// data. The main functions can call each other and continue the parsing by -// using the returned position as a new starting point. -// -// There are also extra `.handle...` functions, which pull out some reused -// functionality into self-contained functions. -// -// The earlier functions return `ParseResult`s, which contain a ParseNode and a -// new position. -// -// The later functions (which are called deeper in the parse) sometimes return -// ParseFuncOrArgument, which contain a ParseResult as well as some data about -// whether the parsed object is a function which is missing some arguments, or a -// standalone object which can be used as an argument to another function. - -// Main Parser class +/** + * This file contains the parser used to parse out a TeX expression from the + * input. Since TeX isn't context-free, standard parsers don't work particularly + * well. + * + * The strategy of this parser is as such: + * + * The main functions (the `.parse...` ones) take a position in the current + * parse string to parse tokens from. The lexer (found in Lexer.js, stored at + * this.lexer) also supports pulling out tokens at arbitrary places. When + * individual tokens are needed at a position, the lexer is called to pull out a + * token, which is then used. + * + * The main functions also take a mode that the parser is currently in + * (currently "math" or "text"), which denotes whether the current environment + * is a math-y one or a text-y one (e.g. inside \text). Currently, this serves + * to limit the functions which can be used in text mode. + * + * The main functions then return an object which contains the useful data that + * was parsed at its given point, and a new position at the end of the parsed + * data. The main functions can call each other and continue the parsing by + * using the returned position as a new starting point. + * + * There are also extra `.handle...` functions, which pull out some reused + * functionality into self-contained functions. + * + * The earlier functions return `ParseResult`s, which contain a ParseNode and a + * new position. + * + * The later functions (which are called deeper in the parse) sometimes return + * ParseFuncOrArgument, which contain a ParseResult as well as some data about + * whether the parsed object is a function which is missing some arguments, or a + * standalone object which can be used as an argument to another function. + */ + +/** + * Main Parser class + */ function Parser(input) { // Make a new lexer this.lexer = new Lexer(input); }; -// The resulting parse tree nodes of the parse tree. +/** + * The resulting parse tree nodes of the parse tree. + */ function ParseNode(type, value, mode) { this.type = type; this.value = value; this.mode = mode; } -// A result and final position returned by the `.parse...` functions. +/** + * A result and final position returned by the `.parse...` functions. + */ function ParseResult(result, newPosition) { this.result = result; this.position = newPosition; } -// An initial function (without its arguments), or an argument to a function. -// The `result` argument should be a ParseResult. +/** + * An initial function (without its arguments), or an argument to a function. + * The `result` argument should be a ParseResult. + */ function ParseFuncOrArgument(result, isFunction, allowedInText, numArgs, argTypes) { this.result = result; // Is this a function (i.e. is it something defined in functions.js)? @@ -71,8 +81,10 @@ function ParseFuncOrArgument(result, isFunction, allowedInText, numArgs, argType this.argTypes = argTypes; } -// Checks a result to make sure it has the right type, and throws an -// appropriate error otherwise. +/** + * Checks a result to make sure it has the right type, and throws an + * appropriate error otherwise. + */ Parser.prototype.expect = function(result, type) { if (result.type !== type) { throw new ParseError( @@ -82,15 +94,20 @@ Parser.prototype.expect = function(result, type) { } }; -// Main parsing function, which parses an entire input. Returns either a list -// of parseNodes or null if the parse fails. +/** + * Main parsing function, which parses an entire input. + * + * @return {?Array.<ParseNode>} + */ Parser.prototype.parse = function(input) { // Try to parse the input var parse = this.parseInput(0, "math"); return parse.result; }; -// Parses an entire input tree +/** + * Parses an entire input tree. + */ Parser.prototype.parseInput = function(pos, mode) { // Parse an expression var expression = this.parseExpression(pos, mode); @@ -100,7 +117,9 @@ Parser.prototype.parseInput = function(pos, mode) { return expression; }; -// Handles a body of an expression +/** + * Handles a body of an expression. + */ Parser.prototype.handleExpressionBody = function(pos, mode) { var body = []; var atom; @@ -116,9 +135,11 @@ Parser.prototype.handleExpressionBody = function(pos, mode) { }; }; -// Parses an "expression", which is a list of atoms -// -// Returns ParseResult +/** + * Parses an "expression", which is a list of atoms. + * + * @return {ParseResult} + */ Parser.prototype.parseExpression = function(pos, mode) { var body = this.handleExpressionBody(pos, mode); return new ParseResult(body.body, body.position); @@ -127,7 +148,9 @@ Parser.prototype.parseExpression = function(pos, mode) { // The greediness of a superscript or subscript var SUPSUB_GREEDINESS = 1; -// Handle a subscript or superscript with nice errors +/** + * Handle a subscript or superscript with nice errors. + */ Parser.prototype.handleSupSubscript = function(pos, mode, symbol, name) { var group = this.parseGroup(pos, mode); @@ -151,9 +174,11 @@ Parser.prototype.handleSupSubscript = function(pos, mode, symbol, name) { } }; -// Parses a group with optional super/subscripts -// -// Returns ParseResult or null +/** + * Parses a group with optional super/subscripts. + * + * @return {?ParseResult} + */ Parser.prototype.parseAtom = function(pos, mode) { // The body of an atom is an implicit group, so that things like // \left(x\right)^2 work correctly. @@ -247,15 +272,17 @@ var styleFuncs = [ "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle" ]; -// Parses an implicit group, which is a group that starts at the end of a -// specified, and ends right before a higher explicit group ends, or at EOL. It -// is used for functions that appear to affect the current style, like \Large or -// \textrm, where instead of keeping a style we just pretend that there is an -// implicit grouping after it until the end of the group. E.g. -// small text {\Large large text} small text again -// It is also used for \left and \right to get the correct grouping. -// -// Returns ParseResult or null +/** + * Parses an implicit group, which is a group that starts at the end of a + * specified, and ends right before a higher explicit group ends, or at EOL. It + * is used for functions that appear to affect the current style, like \Large or + * \textrm, where instead of keeping a style we just pretend that there is an + * implicit grouping after it until the end of the group. E.g. + * small text {\Large large text} small text again + * It is also used for \left and \right to get the correct grouping. + * + * @return {?ParseResult} + */ Parser.prototype.parseImplicitGroup = function(pos, mode) { var start = this.parseSymbol(pos, mode); @@ -320,9 +347,11 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) { } }; -// Parses an entire function, including its base and all of its arguments -// -// Returns ParseResult or null +/** + * Parses an entire function, including its base and all of its arguments + * + * @return {?ParseResult} + */ Parser.prototype.parseFunction = function(pos, mode) { var baseGroup = this.parseGroup(pos, mode); @@ -392,10 +421,12 @@ Parser.prototype.parseFunction = function(pos, mode) { } }; -// Parses a group when the mode is changing. Takes a position, a new mode, and -// an outer mode that is used to parse the outside. -// -// Returns a ParseFuncOrArgument or null +/** + * Parses a group when the mode is changing. Takes a position, a new mode, and + * an outer mode that is used to parse the outside. + * + * @return {?ParseFuncOrArgument} + */ Parser.prototype.parseSpecialGroup = function(pos, mode, outerMode) { if (mode === "color" || mode === "size") { // color and size modes are special because they should have braces and @@ -420,10 +451,12 @@ Parser.prototype.parseSpecialGroup = function(pos, mode, outerMode) { } }; -// Parses a group, which is either a single nucleus (like "x") or an expression -// in braces (like "{x+y}") -// -// Returns a ParseFuncOrArgument or null +/** + * Parses a group, which is either a single nucleus (like "x") or an expression + * in braces (like "{x+y}") + * + * @return {?ParseFuncOrArgument} + */ Parser.prototype.parseGroup = function(pos, mode) { var start = this.lexer.lex(pos, mode); // Try to parse an open brace @@ -444,10 +477,12 @@ Parser.prototype.parseGroup = function(pos, mode) { } }; -// Parse a single symbol out of the string. Here, we handle both the functions -// we have defined, as well as the single character symbols -// -// Returns a ParseFuncOrArgument or null +/** + * Parse a single symbol out of the string. Here, we handle both the functions + * we have defined, as well as the single character symbols + * + * @return {?ParseFuncOrArgument} + */ Parser.prototype.parseSymbol = function(pos, mode) { var nucleus = this.lexer.lex(pos, mode); diff --git a/Style.js b/Style.js @@ -1,3 +1,17 @@ +/** + * This file contains information and classes for the various kinds of styles + * used in TeX. It provides a generic `Style` class, which holds information + * about a specific style. It then provides instances of all the different kinds + * of styles possible, and provides functions to move between them and get + * information about them. + */ + +/** + * The main style class. Contains a unique id for the style, a size (which is + * the same for cramped and uncramped version of a style), a cramped flag, and a + * size multiplier, which gives the size difference between a style and + * textstyle. + */ function Style(id, size, multiplier, cramped) { this.id = id; this.size = size; @@ -5,36 +19,59 @@ function Style(id, size, multiplier, cramped) { this.sizeMultiplier = multiplier; } +/** + * Get the style of a superscript given a base in the current style. + */ Style.prototype.sup = function() { return styles[sup[this.id]]; }; +/** + * Get the style of a subscript given a base in the current style. + */ Style.prototype.sub = function() { return styles[sub[this.id]]; }; +/** + * Get the style of a fraction numerator given the fraction in the current + * style. + */ Style.prototype.fracNum = function() { return styles[fracNum[this.id]]; }; +/** + * Get the style of a fraction denominator given the fraction in the current + * style. + */ Style.prototype.fracDen = function() { return styles[fracDen[this.id]]; }; +/** + * Get the cramped version of a style (in particular, cramping a cramped style + * doesn't change the style). + */ Style.prototype.cramp = function() { return styles[cramp[this.id]]; }; -// HTML class name, like "displaystyle cramped" +/** + * HTML class name, like "displaystyle cramped" + */ Style.prototype.cls = function() { return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped"); }; -// HTML Reset class name, like "reset-textstyle" +/** + * HTML Reset class name, like "reset-textstyle" + */ Style.prototype.reset = function() { return resetNames[this.size]; }; +// IDs of the different styles var D = 0; var Dc = 1; var T = 2; @@ -44,6 +81,7 @@ var Sc = 5; var SS = 6; var SSc = 7; +// String names for the different sizes var sizeNames = [ "displaystyle textstyle", "textstyle", @@ -51,6 +89,7 @@ var sizeNames = [ "scriptscriptstyle" ]; +// Reset names for the different sizes var resetNames = [ "reset-textstyle", "reset-textstyle", @@ -58,6 +97,7 @@ var resetNames = [ "reset-scriptscriptstyle", ]; +// Instances of the different styles var styles = [ new Style(D, 0, 1.0, false), new Style(Dc, 0, 1.0, true), @@ -69,12 +109,15 @@ var styles = [ new Style(SSc, 3, 0.5, true) ]; +// Lookup tables for switching from one style to another var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc]; var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc]; var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc]; var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc]; var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc]; +// We only export some of the styles. Also, we don't export the `Style` class so +// no more styles can be generated. module.exports = { DISPLAY: styles[D], TEXT: styles[T], diff --git a/buildCommon.js b/buildCommon.js @@ -1,8 +1,19 @@ +/** + * This module contains general functions that can be used for building + * different kinds of domTree nodes in a consistent manner. + */ + var domTree = require("./domTree"); var fontMetrics = require("./fontMetrics"); var symbols = require("./symbols"); +/** + * Makes a symbolNode after translation via the list of symbols in symbols.js. + * Correctly pulls out metrics for the character, and optionally takes a list of + * classes to be attached to the node. + */ var makeSymbol = function(value, style, mode, color, classes) { + // Replace the value with its replaced value from symbol.js if (symbols[mode][value] && symbols[mode][value].replace) { value = symbols[mode][value].replace; } @@ -15,8 +26,10 @@ var makeSymbol = function(value, style, mode, color, classes) { value, metrics.height, metrics.depth, metrics.italic, metrics.skew, classes); } else { - console && console.warn("No character metrics for '" + value + - "' in style '" + style + "'"); + // TODO(emily): Figure out a good way to only print this in development + typeof console !== "undefined" && console.warn( + "No character metrics for '" + value + "' in style '" + + style + "'"); symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes); } @@ -27,12 +40,20 @@ var makeSymbol = function(value, style, mode, color, classes) { return symbolNode; }; +/** + * Makes a symbol in the italic math font. + */ var mathit = function(value, mode, color, classes) { return makeSymbol( value, "Math-Italic", mode, color, classes.concat(["mathit"])); }; +/** + * Makes a symbol in the upright roman font. + */ var mathrm = function(value, mode, color, classes) { + // Decide what font to render the symbol in by its entry in the symbols + // table. if (symbols[mode][value].font === "main") { return makeSymbol(value, "Main-Regular", mode, color, classes); } else { @@ -41,6 +62,10 @@ var mathrm = function(value, mode, color, classes) { } }; +/** + * Calculate the height, depth, and maxFontSize of an element based on its + * children. + */ var sizeElementFromChildren = function(elem) { var height = 0; var depth = 0; @@ -65,6 +90,9 @@ var sizeElementFromChildren = function(elem) { elem.maxFontSize = maxFontSize; }; +/** + * Makes a span with the given list of classes, list of children, and color. + */ var makeSpan = function(classes, children, color) { var span = new domTree.span(classes, children); @@ -77,6 +105,9 @@ var makeSpan = function(classes, children, color) { return span; }; +/** + * Makes a document fragment with the given list of children. + */ var makeFragment = function(children) { var fragment = new domTree.documentFragment(children); @@ -85,6 +116,11 @@ var makeFragment = function(children) { return fragment; }; +/** + * Makes an element placed in each of the vlist elements to ensure that each + * element has the same max font size. To do this, we create a zero-width space + * with the correct font size. + */ var makeFontSizer = function(options, fontSize) { var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]); fontSizeInner.style.fontSize = (fontSize / options.style.sizeMultiplier) + "em"; @@ -96,7 +132,7 @@ var makeFontSizer = function(options, fontSize) { return fontSizer; }; -/* +/** * Makes a vertical list by stacking elements and kerns on top of each other. * Allows for many different ways of specifying the positioning method. * @@ -229,6 +265,5 @@ module.exports = { mathrm: mathrm, makeSpan: makeSpan, makeFragment: makeFragment, - makeFontSizer: makeFontSizer, makeVList: makeVList }; diff --git a/buildTree.js b/buildTree.js @@ -1,3 +1,10 @@ +/** + * This file does the main work of building a domTree sturcture from a parse + * tree. The entry point is the `buildTree` function, which takes a parse tree. + * Then, the buildExpression, buildGroup, and various groupTypes functions are + * called, to produce a final tree. + */ + var Options = require("./Options"); var ParseError = require("./ParseError"); var Style = require("./Style"); @@ -12,6 +19,11 @@ var utils = require("./utils"); var makeSpan = buildCommon.makeSpan; +/** + * Take a list of nodes, build them in order, and return a list of the built + * nodes. This function handles the `prev` node correctly, and passes the + * previous element from the list as the prev of the next element. + */ var buildExpression = function(expression, options, prev) { var groups = []; for (var i = 0; i < expression.length; i++) { @@ -22,6 +34,7 @@ var buildExpression = function(expression, options, prev) { return groups; }; +// List of types used by getTypeOfGroup var groupToType = { mathord: "mord", textord: "mord", @@ -44,6 +57,20 @@ var groupToType = { accent: "mord" }; +/** + * Gets the final math type of an expression, given its group type. This type is + * used to determine spacing between elements, and affects bin elements by + * causing them to change depending on what types are around them. This type + * must be attached to the outermost node of an element as a CSS class so that + * spacing with its surrounding elements works correctly. + * + * Some elements can be mapped one-to-one from group type to math type, and + * those are listed in the `groupToType` table. + * + * Others (usually elements that wrap around other elements) often have + * recursive definitions, and thus call `getTypeOfGroup` on their inner + * elements. + */ var getTypeOfGroup = function(group) { if (group == null) { // Like when typesetting $^3$ @@ -65,11 +92,19 @@ var getTypeOfGroup = function(group) { } }; +/** + * Sometimes, groups perform special rules when they have superscripts or + * subscripts attached to them. This function lets the `supsub` group know that + * its inner element should handle the superscripts and subscripts instead of + * handling them itself. + */ var shouldHandleSupSub = function(group, options) { if (group == null) { return false; } else if (group.type === "op") { - return group.value.limits && options.style.id === Style.DISPLAY.id; + // Operators handle supsubs differently when they have limits + // (e.g. `\displaystyle\sum_2^3`) + return group.value.limits && options.style.size === Style.DISPLAY.size; } else if (group.type === "accent") { return isCharacterBox(group.value.base); } else { @@ -77,6 +112,11 @@ var shouldHandleSupSub = function(group, options) { } }; +/** + * Sometimes we want to pull out the innermost element of a group. In most + * cases, this will just be the group itself, but when ordgroups and colors have + * a single element, we want to pull that out. + */ var getBaseElem = function(group) { if (group == null) { return false; @@ -97,18 +137,29 @@ var getBaseElem = function(group) { } }; +/** + * TeXbook algorithms often reference "character boxes", which are simply groups + * with a single character in them. To decide if something is a character box, + * we find its innermost group, and see if it is a single character. + */ var isCharacterBox = function(group) { var baseElem = getBaseElem(group); + // These are all they types of groups which hold single characters return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "bin" || baseElem.type === "rel" || + baseElem.type === "inner" || baseElem.type === "open" || baseElem.type === "close" || baseElem.type === "punct"; }; +/** + * This is a map of group types to the function used to handle that type. + * Simpler types come at the beginning, while complicated types come afterwards. + */ var groupTypes = { mathord: function(group, options, prev) { return buildCommon.mathit( @@ -122,11 +173,17 @@ var groupTypes = { bin: function(group, options, prev) { var className = "mbin"; + // Pull out the most recent element. Do some special handling to find + // things at the end of a \color group. Note that we don't use the same + // logic for ordgroups (which count as ords). var prevAtom = prev; while (prevAtom && prevAtom.type == "color") { var atoms = prevAtom.value.value; prevAtom = atoms[atoms.length - 1]; } + // See TeXbook pg. 442-446, Rules 5 and 6, and the text before Rule 19. + // Here, we determine whether the bin should turn into an ord. We + // currently only apply Rule 5. if (!prev || utils.contains(["mbin", "mopen", "mrel", "mop", "mpunct"], getTypeOfGroup(prevAtom))) { group.type = "textord"; @@ -142,14 +199,59 @@ var groupTypes = { group.value, group.mode, options.getColor(), ["mrel"]); }, + open: function(group, options, prev) { + return buildCommon.mathrm( + group.value, group.mode, options.getColor(), ["mopen"]); + }, + + close: function(group, options, prev) { + return buildCommon.mathrm( + group.value, group.mode, options.getColor(), ["mclose"]); + }, + + inner: function(group, options, prev) { + return buildCommon.mathrm( + group.value, group.mode, options.getColor(), ["minner"]); + }, + + punct: function(group, options, prev) { + return buildCommon.mathrm( + group.value, group.mode, options.getColor(), ["mpunct"]); + }, + + ordgroup: function(group, options, prev) { + return makeSpan( + ["mord", options.style.cls()], + buildExpression(group.value, options.reset()) + ); + }, + text: function(group, options, prev) { return makeSpan(["text", "mord", options.style.cls()], buildExpression(group.value.body, options.reset())); }, + color: function(group, options, prev) { + var elements = buildExpression( + group.value.value, + options.withColor(group.value.color), + prev + ); + + // \color isn't supposed to affect the type of the elements it contains. + // To accomplish this, we wrap the results in a fragment, so the inner + // elements will be able to directly interact with their neighbors. For + // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3` + return new buildCommon.makeFragment(elements); + }, + supsub: function(group, options, prev) { + // Superscript and subscripts are handled in the TeXbook on page + // 445-446, rules 18(a-f). var baseGroup = group.value.base; + // Here is where we defer to the inner group if it should handle + // superscripts and subscripts itself. if (shouldHandleSupSub(group.value.base, options)) { return groupTypes[group.value.base.type](group, options, prev); } @@ -170,77 +272,90 @@ var groupTypes = { [options.style.reset(), options.style.sub().cls()], [sub]); } - var u, v; + // Rule 18a + var supShift, subShift; if (isCharacterBox(group.value.base)) { - u = 0; - v = 0; + supShift = 0; + subShift = 0; } else { - u = base.height - fontMetrics.metrics.supDrop; - v = base.depth + fontMetrics.metrics.subDrop; + supShift = base.height - fontMetrics.metrics.supDrop; + subShift = base.depth + fontMetrics.metrics.subDrop; } - var p; + // Rule 18c + var minSupShift; if (options.style === Style.DISPLAY) { - p = fontMetrics.metrics.sup1; + minSupShift = fontMetrics.metrics.sup1; } else if (options.style.cramped) { - p = fontMetrics.metrics.sup3; + minSupShift = fontMetrics.metrics.sup3; } else { - p = fontMetrics.metrics.sup2; + minSupShift = fontMetrics.metrics.sup2; } + // scriptspace is a font-size-independent size, so scale it + // appropriately var multiplier = Style.TEXT.sizeMultiplier * options.style.sizeMultiplier; var scriptspace = (0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em"; var supsub; - if (!group.value.sup) { - v = Math.max(v, fontMetrics.metrics.sub1, + // Rule 18b + subShift = Math.max( + subShift, fontMetrics.metrics.sub1, sub.height - 0.8 * fontMetrics.metrics.xHeight); supsub = buildCommon.makeVList([ {type: "elem", elem: submid} - ], "shift", v, options); + ], "shift", subShift, options); supsub.children[0].style.marginRight = scriptspace; + // Subscripts shouldn't be shifted by the base's italic correction. + // Account for that by shifting the subscript back the appropriate + // amount. Note we only do this when the base is a single symbol. if (base instanceof domTree.symbolNode) { supsub.children[0].style.marginLeft = -base.italic + "em"; } } else if (!group.value.sub) { - u = Math.max(u, p, + // Rule 18c, d + supShift = Math.max(supShift, minSupShift, sup.depth + 0.25 * fontMetrics.metrics.xHeight); supsub = buildCommon.makeVList([ {type: "elem", elem: supmid} - ], "shift", -u, options); + ], "shift", -supShift, options); supsub.children[0].style.marginRight = scriptspace; } else { - u = Math.max(u, p, + supShift = Math.max( + supShift, minSupShift, sup.depth + 0.25 * fontMetrics.metrics.xHeight); - v = Math.max(v, fontMetrics.metrics.sub2); + subShift = Math.max(subShift, fontMetrics.metrics.sub2); - var theta = fontMetrics.metrics.defaultRuleThickness; + var ruleWidth = fontMetrics.metrics.defaultRuleThickness; - if ((u - sup.depth) - (sub.height - v) < 4 * theta) { - v = 4 * theta - (u - sup.depth) + sub.height; - var psi = 0.8 * fontMetrics.metrics.xHeight - (u - sup.depth); + // Rule 18e + if ((supShift - sup.depth) - (sub.height - subShift) < + 4 * ruleWidth) { + subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height; + var psi = 0.8 * fontMetrics.metrics.xHeight - + (supShift - sup.depth); if (psi > 0) { - u += psi; - v -= psi; + supShift += psi; + subShift -= psi; } } supsub = buildCommon.makeVList([ - {type: "elem", elem: submid, shift: v}, - {type: "elem", elem: supmid, shift: -u} + {type: "elem", elem: submid, shift: subShift}, + {type: "elem", elem: supmid, shift: -supShift} ], "individualShift", null, options); + // See comment above about subscripts not being shifted if (base instanceof domTree.symbolNode) { - supsub.children[1].style.marginLeft = base.italic + "em"; - base.italic = 0; + supsub.children[0].style.marginLeft = -base.italic + "em"; } supsub.children[0].style.marginRight = scriptspace; @@ -251,22 +366,10 @@ var groupTypes = { [base, supsub]); }, - open: function(group, options, prev) { - return buildCommon.mathrm( - group.value, group.mode, options.getColor(), ["mopen"]); - }, - - close: function(group, options, prev) { - return buildCommon.mathrm( - group.value, group.mode, options.getColor(), ["mclose"]); - }, - - inner: function(group, options, prev) { - return buildCommon.mathrm( - group.value, group.mode, options.getColor(), ["minner"]); - }, - frac: function(group, options, prev) { + // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e). + // Figure out what style this fraction should be in based on the + // function used var fstyle = options.style; if (group.value.size === "dfrac") { fstyle = Style.DISPLAY; @@ -283,40 +386,54 @@ var groupTypes = { var denom = buildGroup(group.value.denom, options.withStyle(dstyle)); var denomreset = makeSpan([fstyle.reset(), dstyle.cls()], [denom]) - var theta = fontMetrics.metrics.defaultRuleThickness / options.style.sizeMultiplier; + var ruleWidth = fontMetrics.metrics.defaultRuleThickness / + options.style.sizeMultiplier; - var mid = makeSpan([options.style.reset(), Style.TEXT.cls(), "frac-line"]); - mid.height = theta; + var mid = makeSpan( + [options.style.reset(), Style.TEXT.cls(), "frac-line"]); + // Manually set the height of the line because its height is created in + // CSS + mid.height = ruleWidth; - var u, v, phi; + // Rule 15b, 15d + var numShift, denomShift, clearance; if (fstyle.size === Style.DISPLAY.size) { - u = fontMetrics.metrics.num1; - v = fontMetrics.metrics.denom1; - phi = 3 * theta; + numShift = fontMetrics.metrics.num1; + denomShift = fontMetrics.metrics.denom1; + clearance = 3 * ruleWidth; } else { - u = fontMetrics.metrics.num2; - v = fontMetrics.metrics.denom2; - phi = theta; + numShift = fontMetrics.metrics.num2; + denomShift = fontMetrics.metrics.denom2; + clearance = ruleWidth; } - var a = fontMetrics.metrics.axisHeight; + var axisHeight = fontMetrics.metrics.axisHeight; - if ((u - numer.depth) - (a + 0.5 * theta) < phi) { - u += phi - ((u - numer.depth) - (a + 0.5 * theta)); + // Rule 15d + if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) + < clearance) { + numShift += + clearance - ((numShift - numer.depth) - + (axisHeight + 0.5 * ruleWidth)); } - if ((a - 0.5 * theta) - (denom.height - v) < phi) { - v += phi - ((a - 0.5 * theta) - (denom.height - v)); + if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) + < clearance) { + denomShift += + clearance - ((axisHeight - 0.5 * ruleWidth) - + (denom.height - denomShift)); } - var midShift = -(a - 0.5 * theta); + var midShift = -(axisHeight - 0.5 * ruleWidth); var frac = buildCommon.makeVList([ - {type: "elem", elem: denomreset, shift: v}, + {type: "elem", elem: denomreset, shift: denomShift}, {type: "elem", elem: mid, shift: midShift}, - {type: "elem", elem: numerreset, shift: -u} + {type: "elem", elem: numerreset, shift: -numShift} ], "individualShift", null, options); + // Since we manually change the style sometimes (with \dfrac or \tfrac), + // account for the possible size change here. frac.height *= fstyle.sizeMultiplier / options.style.sizeMultiplier; frac.depth *= fstyle.sizeMultiplier / options.style.sizeMultiplier; @@ -325,24 +442,19 @@ var groupTypes = { [frac], options.getColor()); }, - color: function(group, options, prev) { - var elements = buildExpression( - group.value.value, - options.withColor(group.value.color), - prev - ); - - return new buildCommon.makeFragment(elements); - }, - spacing: function(group, options, prev) { if (group.value === "\\ " || group.value === "\\space" || group.value === " " || group.value === "~") { + // Spaces are generated by adding an actual space. Each of these + // things has an entry in the symbols table, so these will be turned + // into appropriate outputs. return makeSpan( ["mord", "mspace"], [buildCommon.mathrm(group.value, group.mode)] ); } else { + // Other kinds of spaces are of arbitrary width. We use CSS to + // generate these. var spacingClassMap = { "\\qquad": "qquad", "\\quad": "quad", @@ -374,23 +486,15 @@ var groupTypes = { ["rlap", options.style.cls()], [inner, fix]); }, - punct: function(group, options, prev) { - return buildCommon.mathrm( - group.value, group.mode, options.getColor(), ["mpunct"]); - }, - - ordgroup: function(group, options, prev) { - return makeSpan( - ["mord", options.style.cls()], - buildExpression(group.value, options.reset()) - ); - }, - op: function(group, options, prev) { + // Operators are handled in the TeXbook pg. 443-444, rule 13(a). var supGroup; var subGroup; var hasLimits = false; if (group.type === "supsub" ) { + // If we have limits, supsub will pass us its group to handle. Pull + // out the superscript and subscript and set the group to the op in + // its base. supGroup = group.value.sup; subGroup = group.value.sub; group = group.value.base; @@ -403,29 +507,40 @@ var groupTypes = { ]; var large = false; - - if (options.style.id === Style.DISPLAY.id && + if (options.style.size === Style.DISPLAY.size && group.value.symbol && !utils.contains(noSuccessor, group.value.body)) { - // Make symbols larger in displaystyle, except for smallint + // Most symbol operators get larger in displaystyle (rule 13) large = true; } var base; var baseShift = 0; - var delta = 0; + var slant = 0; if (group.value.symbol) { + // If this is a symbol, create the symbol. var style = large ? "Size2-Regular" : "Size1-Regular"; base = buildCommon.makeSymbol( group.value.body, style, "math", options.getColor(), ["op-symbol", large ? "large-op" : "small-op", "mop"]); + // Shift the symbol so its center lies on the axis (rule 13). It + // appears that our fonts have the centers of the symbols already + // almost on the axis, so these numbers are very small. Note we + // don't actually apply this here, but instead it is used either in + // the vlist creation or separately when there are no limits. baseShift = (base.height - base.depth) / 2 - fontMetrics.metrics.axisHeight * options.style.sizeMultiplier; - delta = base.italic; + + // The slant of the symbol is just its italic correction. + slant = base.italic; } else { + // Otherwise, this is a text operator. Build the text from the + // operator's name. + // TODO(emily): Add a space in the middle of some of these + // operators, like \limsup var output = []; for (var i = 1; i < group.value.body.length; i++) { output.push(buildCommon.mathrm(group.value.body[i], group.mode)); @@ -438,28 +553,34 @@ var groupTypes = { // in a new span so it is an inline, and works. var base = makeSpan([], [base]); + var supmid, supKern, submid, subKern; + // We manually have to handle the superscripts and subscripts. This, + // aside from the kern calculations, is copied from supsub. if (supGroup) { - var sup = buildGroup(supGroup, - options.withStyle(options.style.sup())); - var supmid = makeSpan( + var sup = buildGroup( + supGroup, options.withStyle(options.style.sup())); + supmid = makeSpan( [options.style.reset(), options.style.sup().cls()], [sup]); - var supKern = Math.max( + supKern = Math.max( fontMetrics.metrics.bigOpSpacing1, fontMetrics.metrics.bigOpSpacing3 - sup.depth); } if (subGroup) { - var sub = buildGroup(subGroup, - options.withStyle(options.style.sub())); - var submid = makeSpan( - [options.style.reset(), options.style.sub().cls()], [sub]); + var sub = buildGroup( + subGroup, options.withStyle(options.style.sub())); + submid = makeSpan( + [options.style.reset(), options.style.sub().cls()], + [sub]); - var subKern = Math.max( + subKern = Math.max( fontMetrics.metrics.bigOpSpacing2, fontMetrics.metrics.bigOpSpacing4 - sub.height); } + // Build the final group as a vlist of the possible subscript, base, + // and possible superscript. var finalGroup; if (!supGroup) { var top = base.height - baseShift; @@ -471,7 +592,11 @@ var groupTypes = { {type: "elem", elem: base} ], "top", top, options); - finalGroup.children[0].style.marginLeft = -delta + "em"; + // Here, we shift the limits by the slant of the symbol. Note + // that we are supposed to shift the limits by 1/2 of the slant, + // but since we are centering the limits adding a full slant of + // margin will shift by 1/2 that. + finalGroup.children[0].style.marginLeft = -slant + "em"; } else if (!subGroup) { var bottom = base.depth + baseShift; @@ -482,8 +607,12 @@ var groupTypes = { {type: "kern", size: fontMetrics.metrics.bigOpSpacing5} ], "bottom", bottom, options); - finalGroup.children[1].style.marginLeft = delta + "em"; + // See comment above about slants + finalGroup.children[1].style.marginLeft = slant + "em"; } else if (!supGroup && !subGroup) { + // This case probably shouldn't occur (this would mean the + // supsub was sending us a group with no superscript or + // subscript) but be safe. return base; } else { var bottom = fontMetrics.metrics.bigOpSpacing5 + @@ -501,8 +630,9 @@ var groupTypes = { {type: "kern", size: fontMetrics.metrics.bigOpSpacing5} ], "bottom", bottom, options); - finalGroup.children[0].style.marginLeft = -delta + "em"; - finalGroup.children[2].style.marginLeft = delta + "em"; + // See comment above about slants + finalGroup.children[0].style.marginLeft = -slant + "em"; + finalGroup.children[2].style.marginLeft = slant + "em"; } return makeSpan(["mop", "op-limits"], [finalGroup]); @@ -516,6 +646,9 @@ var groupTypes = { }, katex: function(group, options, prev) { + // The KaTeX logo. The offsets for the K and a were chosen to look + // good, but the offsets for the T, E, and X were taken from the + // definition of \TeX in TeX (see TeXbook pg. 356) var k = makeSpan( ["k"], [buildCommon.mathrm("K", group.mode)]); var a = makeSpan( @@ -539,42 +672,78 @@ var groupTypes = { ["katex-logo"], [k, a, t, e, x], options.getColor()); }, + overline: function(group, options, prev) { + // Overlines are handled in the TeXbook pg 443, Rule 9. + + // Build the inner group in the cramped style. + var innerGroup = buildGroup(group.value.body, + options.withStyle(options.style.cramp())); + + var ruleWidth = fontMetrics.metrics.defaultRuleThickness / + options.style.sizeMultiplier; + + // Create the line above the body + var line = makeSpan( + [options.style.reset(), Style.TEXT.cls(), "overline-line"]); + line.height = ruleWidth; + line.maxFontSize = 1.0; + + // Generate the vlist, with the appropriate kerns + var vlist = buildCommon.makeVList([ + {type: "elem", elem: innerGroup}, + {type: "kern", size: 3 * ruleWidth}, + {type: "elem", elem: line}, + {type: "kern", size: ruleWidth} + ], "firstBaseline", null, options); + + return makeSpan(["overline", "mord"], [vlist], options.getColor()); + }, + sqrt: function(group, options, prev) { + // Square roots are handled in the TeXbook pg. 443, Rule 11. + + // First, we do the same steps as in overline to build the inner group + // and line var inner = buildGroup(group.value.body, options.withStyle(options.style.cramp())); - var theta = fontMetrics.metrics.defaultRuleThickness / + var ruleWidth = fontMetrics.metrics.defaultRuleThickness / options.style.sizeMultiplier; var line = makeSpan( [options.style.reset(), Style.TEXT.cls(), "sqrt-line"], [], options.getColor()); - line.height = theta; + line.height = ruleWidth; line.maxFontSize = 1.0; - var phi = theta; + var phi = ruleWidth; if (options.style.id < Style.TEXT.id) { phi = fontMetrics.metrics.xHeight; } - var psi = theta + phi / 4; + // Calculate the clearance between the body and line + var lineClearance = ruleWidth + phi / 4; var innerHeight = (inner.height + inner.depth) * options.style.sizeMultiplier; - var minDelimiterHeight = innerHeight + psi + theta; + var minDelimiterHeight = innerHeight + lineClearance + ruleWidth; + // Create a \surd delimiter of the required minimum size var delim = makeSpan(["sqrt-sign"], [ delimiter.customSizedDelim("\\surd", minDelimiterHeight, false, options, group.mode)], options.getColor()); - var delimDepth = (delim.height + delim.depth) - theta; + var delimDepth = (delim.height + delim.depth) - ruleWidth; - if (delimDepth > inner.height + inner.depth + psi) { - psi = (psi + delimDepth - inner.height - inner.depth) / 2; + // Adjust the clearance based on the delimiter size + if (delimDepth > inner.height + inner.depth + lineClearance) { + lineClearance = + (lineClearance + delimDepth - inner.height - inner.depth) / 2; } - delimShift = -(inner.height + psi + theta) + delim.height; + // Shift the delimiter so that its top lines up with the top of the line + delimShift = -(inner.height + lineClearance + ruleWidth) + delim.height; delim.style.top = delimShift + "em"; delim.height -= delimShift; delim.depth += delimShift; @@ -590,38 +759,19 @@ var groupTypes = { } else { body = buildCommon.makeVList([ {type: "elem", elem: inner}, - {type: "kern", size: psi}, + {type: "kern", size: lineClearance}, {type: "elem", elem: line}, - {type: "kern", size: theta} + {type: "kern", size: ruleWidth} ], "firstBaseline", null, options); } return makeSpan(["sqrt", "mord"], [delim, body]); }, - overline: function(group, options, prev) { - var innerGroup = buildGroup(group.value.body, - options.withStyle(options.style.cramp())); - - var theta = fontMetrics.metrics.defaultRuleThickness / - options.style.sizeMultiplier; - - var line = makeSpan( - [options.style.reset(), Style.TEXT.cls(), "overline-line"]); - line.height = theta; - line.maxFontSize = 1.0; - - var vlist = buildCommon.makeVList([ - {type: "elem", elem: innerGroup}, - {type: "kern", size: 3 * theta}, - {type: "elem", elem: line}, - {type: "kern", size: theta} - ], "firstBaseline", null, options); - - return makeSpan(["overline", "mord"], [vlist], options.getColor()); - }, - sizing: function(group, options, prev) { + // Handle sizing operators like \Huge. Real TeX doesn't actually allow + // these functions inside of math expressions, so we do some special + // handling. var inner = buildExpression(group.value.value, options.withSize(group.value.size), prev); @@ -630,26 +780,17 @@ var groupTypes = { options.style.cls()], inner)]); - var sizeToFontSize = { - "size1": 0.5, - "size2": 0.7, - "size3": 0.8, - "size4": 0.9, - "size5": 1.0, - "size6": 1.2, - "size7": 1.44, - "size8": 1.73, - "size9": 2.07, - "size10": 2.49 - }; - - var fontSize = sizeToFontSize[group.value.size]; + // Calculate the correct maxFontSize manually + var fontSize = sizingMultiplier[group.value.size]; span.maxFontSize = fontSize * options.style.sizeMultiplier; return span; }, styling: function(group, options, prev) { + // Style changes are handled in the TeXbook on pg. 442, Rule 3. + + // Figure out what style we're changing to. var style = { "display": Style.DISPLAY, "text": Style.TEXT, @@ -659,6 +800,7 @@ var groupTypes = { var newStyle = style[group.value.style]; + // Build the inner expression in the new style. var inner = buildExpression( group.value.value, options.withStyle(newStyle), prev); @@ -669,9 +811,12 @@ var groupTypes = { var delim = group.value.value; if (delim === ".") { + // Empty delimiters still count as elements, even though they don't + // show anything. return makeSpan([groupToType[group.value.delimType]]); } + // Use delimiter.sizedDelim to generate the delimiter. return makeSpan( [groupToType[group.value.delimType]], [delimiter.sizedDelim( @@ -679,30 +824,40 @@ var groupTypes = { }, leftright: function(group, options, prev) { + // Build the inner expression var inner = buildExpression(group.value.body, options.reset()); var innerHeight = 0; var innerDepth = 0; + // Calculate its height and depth for (var i = 0; i < inner.length; i++) { innerHeight = Math.max(inner[i].height, innerHeight); innerDepth = Math.max(inner[i].depth, innerDepth); } + // The size of delimiters is the same, regardless of what style we are + // in. Thus, to correctly calculate the size of delimiter we need around + // a group, we scale down the inner size based on the size. innerHeight *= options.style.sizeMultiplier; innerDepth *= options.style.sizeMultiplier; var leftDelim; if (group.value.left === ".") { + // Empty delimiters in \left and \right make null delimiter spaces. leftDelim = makeSpan(["nulldelimiter"]); } else { + // Otherwise, use leftRightDelim to generate the correct sized + // delimiter. leftDelim = delimiter.leftRightDelim( group.value.left, innerHeight, innerDepth, options, group.mode); } + // Add it to the beginning of the expression inner.unshift(leftDelim); var rightDelim; + // Same for the right delimiter if (group.value.right === ".") { rightDelim = makeSpan(["nulldelimiter"]); } else { @@ -710,6 +865,7 @@ var groupTypes = { group.value.right, innerHeight, innerDepth, options, group.mode); } + // Add it to the end of the expression. inner.push(rightDelim); return makeSpan( @@ -720,6 +876,7 @@ var groupTypes = { // Make an empty span for the rule var rule = makeSpan(["mord", "rule"], [], options.getColor()); + // Calculate the width and height of the rule, and account for units var width = group.value.width.number; if (group.value.width.unit === "ex") { width *= fontMetrics.metrics.xHeight; @@ -730,6 +887,8 @@ var groupTypes = { height *= fontMetrics.metrics.xHeight; } + // The sizes of rules are absolute, so make it larger if we are in a + // smaller style. width /= options.style.sizeMultiplier; height /= options.style.sizeMultiplier; @@ -745,36 +904,69 @@ var groupTypes = { }, accent: function(group, options, prev) { + // Accents are handled in the TeXbook pg. 443, rule 12. var base = group.value.base; var supsubGroup; if (group.type === "supsub") { + // If our base is a character box, and we have superscripts and + // subscripts, the supsub will defer to us. In particular, we want + // to attach the superscripts and subscripts to the inner body (so + // that the position of the superscripts and subscripts won't be + // affected by the height of the accent). We accomplish this by + // sticking the base of the accent into the base of the supsub, and + // rendering that, while keeping track of where the accent is. + + // The supsub group is the group that was passed in var supsub = group; - group = group.value.base; + // The real accent group is the base of the supsub group + group = supsub.value.base; + // The character box is the base of the accent group base = group.value.base; + // Stick the character box into the base of the supsub group supsub.value.base = base; + // Rerender the supsub group with its new base, and store that + // result. supsubGroup = buildGroup( - supsub, options.reset()); + supsub, options.reset(), prev); } + // Build the base group var body = buildGroup( base, options.withStyle(options.style.cramp())); - var s; - if (isCharacterBox(group.value.base)) { - var baseChar = getBaseElem(group.value.base); + // Calculate the skew of the accent. This is based on the line "If the + // nucleus is not a single character, let s = 0; otherwise set s to the + // kern amount for the nucleus followed by the \skewchar of its font." + // Note that our skew metrics are just the kern between each character + // and the skewchar. + var skew; + if (isCharacterBox(base)) { + // If the base is a character box, then we want the skew of the + // innermost character. To do that, we find the innermost character: + var baseChar = getBaseElem(base); + // Then, we render its group to get the symbol inside it var baseGroup = buildGroup( baseChar, options.withStyle(options.style.cramp())); - s = baseGroup.skew; + // Finally, we pull the skew off of the symbol. + skew = baseGroup.skew; + // Note that we now throw away baseGroup, because the layers we + // removed with getBaseElem might contain things like \color which + // we can't get rid of. + // TODO(emily): Find a better way to get the skew } else { - s = 0; + skew = 0; } - var delta = Math.min(body.height, fontMetrics.metrics.xHeight); + // calculate the amount of space between the body and the accent + var clearance = Math.min(body.height, fontMetrics.metrics.xHeight); + // Build the accent var accent = buildCommon.makeSymbol( group.value.accent, "Main-Regular", "math", options.getColor()); + // Remove the italic correction of the accent, because it only serves to + // shift the accent over to a place we don't want. accent.italic = 0; // The \vec character that the fonts use is a combining character, and @@ -788,11 +980,14 @@ var groupTypes = { var accentBody = buildCommon.makeVList([ {type: "elem", elem: body}, - {type: "kern", size: -delta}, + {type: "kern", size: -clearance}, {type: "elem", elem: accentBody} ], "firstBaseline", null, options); - accentBody.children[1].style.marginLeft = 2 * s + "em"; + // Shift the accent over by the skew. Note we shift by twice the skew + // because we are centering the accent, so by adding 2*skew to the left, + // we shift it to the right by 1*skew. + accentBody.children[1].style.marginLeft = 2 * skew + "em"; var accentWrap = makeSpan(["mord", "accent"], [accentBody]); @@ -828,14 +1023,22 @@ var sizingMultiplier = { size10: 2.49 }; +/** + * buildGroup is the function that takes a group and calls the correct groupType + * function for it. It also handles the interaction of size and style changes + * between parents and children. + */ var buildGroup = function(group, options, prev) { if (!group) { return makeSpan(); } if (groupTypes[group.type]) { + // Call the groupTypes function var groupNode = groupTypes[group.type](group, options, prev); + // If the style changed between the parent and the current group, + // account for the size difference if (options.style !== options.parentStyle) { var multiplier = options.style.sizeMultiplier / options.parentStyle.sizeMultiplier; @@ -844,6 +1047,8 @@ var buildGroup = function(group, options, prev) { groupNode.depth *= multiplier; } + // If the size changed between the parent and the current group, account + // for that size difference. if (options.size !== options.parentSize) { var multiplier = sizingMultiplier[options.size] / sizingMultiplier[options.parentSize]; @@ -859,24 +1064,33 @@ var buildGroup = function(group, options, prev) { } }; +/** + * Take an entire parse tree, and build it into an appropriate set of nodes. + */ var buildTree = function(tree) { // Setup the default options var options = new Options(Style.TEXT, "size5", ""); + // Build the expression contained in the tree var expression = buildExpression(tree, options); - var span = makeSpan(["base", options.style.cls()], expression); + var body = makeSpan(["base", options.style.cls()], expression); + + // Add struts, which ensure that the top of the HTML element falls at the + // height of the expression, and the bottom of the HTML element falls at the + // depth of the expression. var topStrut = makeSpan(["strut"]); var bottomStrut = makeSpan(["strut", "bottom"]); - topStrut.style.height = span.height + "em"; - bottomStrut.style.height = (span.height + span.depth) + "em"; + topStrut.style.height = body.height + "em"; + bottomStrut.style.height = (body.height + body.depth) + "em"; // We'd like to use `vertical-align: top` but in IE 9 this lowers the // baseline of the box to the bottom of this strut (instead staying in the // normal place) so we use an absolute value for vertical-align instead - bottomStrut.style.verticalAlign = -span.depth + "em"; + bottomStrut.style.verticalAlign = -body.depth + "em"; + // Wrap the struts and body together var katexNode = makeSpan(["katex"], [ - makeSpan(["katex-inner"], [topStrut, bottomStrut, span]) + makeSpan(["katex-inner"], [topStrut, bottomStrut, body]) ]); return katexNode; diff --git a/delimiter.js b/delimiter.js @@ -1,17 +1,42 @@ +/** + * This file deals with creating delimiters of various sizes. The TeXbook + * discusses these routines on page 441-442, in the "Another subroutine sets box + * x to a specified variable delimiter" paragraph. + * + * There are three main routines here. `makeSmallDelim` makes a delimiter in the + * normal font, but in either text, script, or scriptscript style. + * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1, + * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of + * smaller pieces that are stacked on top of one another. + * + * The functions take a parameter `center`, which determines if the delimiter + * should be centered around the axis. + * + * Then, there are three exposed functions. `sizedDelim` makes a delimiter in + * one of the given sizes. This is used for things like `\bigl`. + * `customSizedDelim` makes a delimiter with a given total height+depth. It is + * called in places like `\sqrt`. `leftRightDelim` makes an appropriate + * delimiter which surrounds an expression of a given height an depth. It is + * used in `\left` and `\right`. + */ + var Options = require("./Options"); var ParseError = require("./ParseError"); var Style = require("./Style"); +var buildCommon = require("./buildCommon"); var domTree = require("./domTree"); var fontMetrics = require("./fontMetrics"); var parseTree = require("./parseTree"); -var utils = require("./utils"); var symbols = require("./symbols"); -var buildCommon = require("./buildCommon"); -var makeSpan = require("./buildCommon").makeSpan; +var utils = require("./utils"); -// Get the metrics for a given symbol and font, after transformation (i.e. -// after following replacement from symbols.js) +var makeSpan = buildCommon.makeSpan; + +/** + * Get the metrics for a given symbol and font, after transformation (i.e. + * after following replacement from symbols.js) + */ var getMetrics = function(symbol, font) { if (symbols["math"][symbol] && symbols["math"][symbol].replace) { return fontMetrics.getCharacterMetrics( @@ -22,12 +47,20 @@ var getMetrics = function(symbol, font) { } }; +/** + * Builds a symbol in the given font size (note size is an integer) + */ var mathrmSize = function(value, size, mode) { return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode); }; +/** + * Puts a delimiter span in a given style, and adds appropriate height, depth, + * and maxFontSizes. + */ var styleWrap = function(delim, toStyle, options) { - var span = makeSpan(["style-wrap", options.style.reset(), toStyle.cls()], [delim]); + var span = makeSpan( + ["style-wrap", options.style.reset(), toStyle.cls()], [delim]); var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier; @@ -38,6 +71,11 @@ var styleWrap = function(delim, toStyle, options) { return span; }; +/** + * Makes a small delimiter. This is a delimiter that comes in the Main-Regular + * font, but is restyled to either be in textstyle, scriptstyle, or + * scriptscriptstyle. + */ var makeSmallDelim = function(delim, style, center, options, mode) { var text = buildCommon.makeSymbol(delim, "Main-Regular", mode); @@ -56,6 +94,10 @@ var makeSmallDelim = function(delim, style, center, options, mode) { return span; }; +/** + * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2, + * Size3, or Size4 fonts. It is always rendered in textstyle. + */ var makeLargeDelim = function(delim, size, center, options, mode) { var inner = mathrmSize(delim, size, mode); @@ -76,9 +118,13 @@ var makeLargeDelim = function(delim, size, center, options, mode) { return span; }; -// Make an inner span with the given offset and in the given font +/** + * Make an inner span with the given offset and in the given font. This is used + * in `makeStackedDelim` to make the stacking pieces for the delimiter. + */ var makeInner = function(symbol, font, mode) { var sizeClass; + // Apply the correct CSS class to choose the right font. if (font === "Size1-Regular") { sizeClass = "delim-size1"; } else if (font === "Size4-Regular") { @@ -89,14 +135,22 @@ var makeInner = function(symbol, font, mode) { ["delimsizinginner", sizeClass], [makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]); + // Since this will be passed into `makeVList` in the end, wrap the element + // in the appropriate tag that VList uses. return {type: "elem", elem: inner}; }; +/** + * Make a stacked delimiter out of a given delimiter, with the total height at + * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook. + */ var makeStackedDelim = function(delim, heightTotal, center, options, mode) { - // There are four parts, the top, a middle, a repeated part, and a bottom. + // There are four parts, the top, an optional middle, a repeated part, and a + // bottom. var top, middle, repeat, bottom; top = repeat = bottom = delim; middle = null; + // Also keep track of what font the delimiters are in var font = "Size1-Regular"; // We set the parts and font based on the symbol. Note that we use @@ -175,7 +229,7 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) { font = "Size4-Regular"; } - // Get the metrics of the three sections + // Get the metrics of the four sections var topMetrics = getMetrics(top, font); var topHeightTotal = topMetrics.height + topMetrics.depth; var repeatMetrics = getMetrics(repeat, font); @@ -188,36 +242,49 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) { middleHeightTotal = middleMetrics.height + middleMetrics.depth; } + // Calcuate the real height that the delimiter will have. It is at least the + // size of the top, bottom, and optional middle combined. var realHeightTotal = topHeightTotal + bottomHeightTotal; if (middle !== null) { realHeightTotal += middleHeightTotal; } + // Then add repeated pieces until we reach the specified height. while (realHeightTotal < heightTotal) { realHeightTotal += repeatHeightTotal; if (middle !== null) { + // If there is a middle section, we need an equal number of pieces + // on the top and bottom. realHeightTotal += repeatHeightTotal; } } + // The center of the delimiter is placed at the center of the axis. Note + // that in this context, "center" means that the delimiter should be + // centered around the axis in the current style, while normally it is + // centered around the axis in textstyle. var axisHeight = fontMetrics.metrics.axisHeight; if (center) { axisHeight *= options.style.sizeMultiplier; } + // Calculate the height and depth var height = realHeightTotal / 2 + axisHeight; var depth = realHeightTotal / 2 - axisHeight; - // Keep a list of the inner spans + // Now, we start building the pieces that will go into the vlist + + // Keep a list of the inner pieces var inners = []; // Add the bottom symbol inners.push(makeInner(bottom, font, mode)); if (middle === null) { + // Calculate the number of repeated symbols we need var repeatHeight = realHeightTotal - topHeightTotal - bottomHeightTotal; var symbolCount = Math.ceil(repeatHeight / repeatHeightTotal); - // Add repeat symbols until there's only space for the bottom symbol + // Add that many symbols for (var i = 0; i < symbolCount; i++) { inners.push(makeInner(repeat, font, mode)); } @@ -250,8 +317,10 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) { } } + // Add the top symbol inners.push(makeInner(top, font, mode)); + // Finally, build the vlist var inner = buildCommon.makeVList(inners, "bottom", depth, options); return styleWrap( @@ -259,29 +328,37 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) { Style.TEXT, options); }; -var normalDelimiters = [ +// There are three kinds of delimiters, delimiters that stack when they become +// too large +var stackLargeDelimiters = [ "(", ")", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\\lceil", "\\rceil", - "<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\surd" ]; -var stackDelimiters = [ +// delimiters that always stack +var stackAlwaysDelimiters = [ "\\uparrow", "\\downarrow", "\\updownarrow", "\\Uparrow", "\\Downarrow", "\\Updownarrow", "|", "\\|", "\\vert", "\\Vert" ]; -var onlyNormalDelimiters = [ +// and delimiters that never stack +var stackNeverDelimiters = [ "<", ">", "\\langle", "\\rangle", "/", "\\backslash" ]; // Metrics of the different sizes. Found by looking at TeX's output of -// $\bigl| \Bigl| \biggl| \Biggl| \showlists$ +// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ +// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; +/** + * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4. + */ var makeSizedDelim = function(delim, size, options, mode) { + // < and > turn into \langle and \rangle in delimiters if (delim === "<") { delim = "\\langle"; } else if (delim === ">") { @@ -290,9 +367,11 @@ var makeSizedDelim = function(delim, size, options, mode) { var retDelim; - if (utils.contains(normalDelimiters, delim)) { + // Sized delimiters are never centered. + if (utils.contains(stackLargeDelimiters, delim) || + utils.contains(stackNeverDelimiters, delim)) { return makeLargeDelim(delim, size, false, options, mode); - } else if (utils.contains(stackDelimiters, delim)) { + } else if (utils.contains(stackAlwaysDelimiters, delim)) { return makeStackedDelim( delim, sizeToMaxHeight[size], false, options, mode); } else { @@ -300,7 +379,20 @@ var makeSizedDelim = function(delim, size, options, mode) { } }; -var normalDelimiterSequence = [ +/** + * There are three different sequences of delimiter sizes that the delimiters + * follow depending on the kind of delimiter. This is used when creating custom + * sized delimiters to decide whether to create a small, large, or stacked + * delimiter. + * + * In real TeX, these sequences aren't explicitly defined, but are instead + * defined inside the font metrics. Since there are only three sequences that + * are possible for the delimiters that TeX defines, it is easier to just encode + * them explicitly here. + */ + +// Delimiters that never stack try small delimiters and large delimiters only +var stackNeverDelimiterSequence = [ {type: "small", style: Style.SCRIPTSCRIPT}, {type: "small", style: Style.SCRIPT}, {type: "small", style: Style.TEXT}, @@ -310,6 +402,7 @@ var normalDelimiterSequence = [ {type: "large", size: 4} ]; +// Delimiters that always stack try the small delimiters first, then stack var stackAlwaysDelimiterSequence = [ {type: "small", style: Style.SCRIPTSCRIPT}, {type: "small", style: Style.SCRIPT}, @@ -317,6 +410,8 @@ var stackAlwaysDelimiterSequence = [ {type: "stack"} ]; +// Delimiters that stack when large try the small and then large delimiters, and +// stack afterwards var stackLargeDelimiterSequence = [ {type: "small", style: Style.SCRIPTSCRIPT}, {type: "small", style: Style.SCRIPT}, @@ -328,6 +423,9 @@ var stackLargeDelimiterSequence = [ {type: "stack"} ]; +/** + * Get the font used in a delimiter based on what kind of delimiter it is. + */ var delimTypeToFont = function(type) { if (type.type === "small") { return "Main-Regular"; @@ -338,6 +436,10 @@ var delimTypeToFont = function(type) { } }; +/** + * Traverse a sequence of types of delimiters to decide what kind of delimiter + * should be used to create a delimiter of the given height+depth. + */ var traverseSequence = function(delim, height, sequence, options) { // Here, we choose the index we should start at in the sequences. In smaller // sizes (which correspond to larger numbers in style.size) we start earlier @@ -351,21 +453,29 @@ var traverseSequence = function(delim, height, sequence, options) { } var metrics = getMetrics(delim, delimTypeToFont(sequence[i])); - var heightDepth = metrics.height + metrics.depth; + // Small delimiters are scaled down versions of the same font, so we + // account for the style change size. + if (sequence[i].type === "small") { heightDepth *= sequence[i].style.sizeMultiplier; } + // Check if the delimiter at this size works for the given height. if (heightDepth > height) { return sequence[i]; } } + // If we reached the end of the sequence, return the last sequence element. return sequence[sequence.length - 1]; }; +/** + * Make a delimiter of a given height+depth, with optional centering. Here, we + * traverse the sequences, and create a delimiter that the sequence tells us to. + */ var makeCustomSizedDelim = function(delim, height, center, options, mode) { if (delim === "<") { delim = "\\langle"; @@ -373,17 +483,21 @@ var makeCustomSizedDelim = function(delim, height, center, options, mode) { delim = "\\rangle"; } + // Decide what sequence to use var sequence; - if (utils.contains(onlyNormalDelimiters, delim)) { - sequence = normalDelimiterSequence; - } else if (utils.contains(normalDelimiters, delim)) { + if (utils.contains(stackNeverDelimiters, delim)) { + sequence = stackNeverDelimiterSequence; + } else if (utils.contains(stackLargeDelimiters, delim)) { sequence = stackLargeDelimiterSequence; } else { sequence = stackAlwaysDelimiterSequence; } + // Look through the sequence var delimType = traverseSequence(delim, height, sequence, options); + // Depending on the sequence element we decided on, call the appropriate + // function. if (delimType.type === "small") { return makeSmallDelim(delim, delimType.style, center, options, mode); } else if (delimType.type === "large") { @@ -393,7 +507,12 @@ var makeCustomSizedDelim = function(delim, height, center, options, mode) { } }; +/** + * Make a delimiter for use with `\left` and `\right`, given a height and depth + * of an expression that the delimiters surround. + */ var makeLeftRightDelim = function(delim, height, depth, options, mode) { + // We always center \left/\right delimiters, so the axis is always shifted var axisHeight = fontMetrics.metrics.axisHeight * options.style.sizeMultiplier; @@ -417,6 +536,8 @@ var makeLeftRightDelim = function(delim, height, depth, options, mode) { maxDistFromAxis / 500 * delimiterFactor, 2 * maxDistFromAxis - delimiterExtend); + // Finally, we defer to `makeCustomSizedDelim` with our calculated total + // height return makeCustomSizedDelim(delim, totalHeight, true, options, mode); }; diff --git a/domTree.js b/domTree.js @@ -1,11 +1,17 @@ -// These objects store the data about the DOM nodes we create, as well as some -// extra data. They can then be transformed into real DOM nodes with the toNode -// function or HTML markup using toMarkup. They are useful for both storing -// extra properties on the nodes, as well as providing a way to easily work -// with the DOM. +/** + * These objects store the data about the DOM nodes we create, as well as some + * extra data. They can then be transformed into real DOM nodes with the toNode + * function or HTML markup using toMarkup. They are useful for both storing + * extra properties on the nodes, as well as providing a way to easily work + * with the DOM. + */ var utils = require("./utils"); +/** + * Create an HTML className based on a list of classes. In addition to joining + * with spaces, we also remove null or empty classes. + */ var createClass = function(classes) { classes = classes.slice(); for (var i = classes.length - 1; i >= 0; i--) { @@ -17,6 +23,11 @@ var createClass = function(classes) { return classes.join(" "); }; +/** + * This node represents a span node, with a className, a list of children, and + * an inline style. It also contains information about its height, depth, and + * maxFontSize. + */ function span(classes, children, height, depth, maxFontSize, style) { this.classes = classes || []; this.children = children || []; @@ -26,17 +37,23 @@ function span(classes, children, height, depth, maxFontSize, style) { this.style = style || {}; } +/** + * Convert the span into an HTML node + */ span.prototype.toNode = function() { var span = document.createElement("span"); + // Apply the class span.className = createClass(this.classes); + // Apply inline styles for (var style in this.style) { if (this.style.hasOwnProperty(style)) { span.style[style] = this.style[style]; } } + // Append the children, also as HTML nodes for (var i = 0; i < this.children.length; i++) { span.appendChild(this.children[i].toNode()); } @@ -44,9 +61,13 @@ span.prototype.toNode = function() { return span; }; +/** + * Convert the span into an HTML markup string + */ span.prototype.toMarkup = function() { var markup = "<span"; + // Add the class if (this.classes.length) { markup += " class=\""; markup += utils.escape(createClass(this.classes)); @@ -55,6 +76,7 @@ span.prototype.toMarkup = function() { var styles = ""; + // Add the styles, after hyphenation for (var style in this.style) { if (this.style.hasOwnProperty(style)) { styles += utils.hyphenate(style) + ":" + this.style[style] + ";"; @@ -67,6 +89,7 @@ span.prototype.toMarkup = function() { markup += ">"; + // Add the markup of the children, also as markup for (var i = 0; i < this.children.length; i++) { markup += this.children[i].toMarkup(); } @@ -76,6 +99,12 @@ span.prototype.toMarkup = function() { return markup; }; +/** + * This node represents a document fragment, which contains elements, but when + * placed into the DOM doesn't have any representation itself. Thus, it only + * contains children and doesn't have any HTML properties. It also keeps track + * of a height, depth, and maxFontSize. + */ function documentFragment(children, height, depth, maxFontSize) { this.children = children || []; this.height = height || 0; @@ -83,9 +112,14 @@ function documentFragment(children, height, depth, maxFontSize) { this.maxFontSize = maxFontSize || 0; } +/** + * Convert the fragment into a node + */ documentFragment.prototype.toNode = function() { + // Create a fragment var frag = document.createDocumentFragment(); + // Append the children for (var i = 0; i < this.children.length; i++) { frag.appendChild(this.children[i].toNode()); } @@ -93,9 +127,13 @@ documentFragment.prototype.toNode = function() { return frag; }; +/** + * Convert the fragment into HTML markup + */ documentFragment.prototype.toMarkup = function() { var markup = ""; + // Simply concatenate the markup for the children together for (var i = 0; i < this.children.length; i++) { markup += this.children[i].toMarkup(); } @@ -103,6 +141,11 @@ documentFragment.prototype.toMarkup = function() { return markup; }; +/** + * A symbol node contains information about a single symbol. It either renders + * to a single text node, or a span with a single text node in it, depending on + * whether it has CSS classes, styles, or needs italic correction. + */ function symbolNode(value, height, depth, italic, skew, classes, style) { this.value = value || ""; this.height = height || 0; @@ -114,6 +157,10 @@ function symbolNode(value, height, depth, italic, skew, classes, style) { this.maxFontSize = 0; } +/** + * Creates a text node or span from a symbol node. Note that a span is only + * created if it is needed. + */ symbolNode.prototype.toNode = function() { var node = document.createTextNode(this.value); var span = null; @@ -143,6 +190,9 @@ symbolNode.prototype.toNode = function() { } }; +/** + * Creates markup for a symbol node. + */ symbolNode.prototype.toMarkup = function() { // TODO(alpert): More duplication than I'd like from // span.prototype.toMarkup and symbolNode.prototype.toNode... diff --git a/fontMetrics.js b/fontMetrics.js @@ -1,4 +1,18 @@ -// These font metrics are extracted from TeX +/** + * This file contains metrics regarding fonts and individual symbols. The sigma + * and xi variables, as well as the metricMap map contain data extracted from + * TeX, TeX font metrics, and the TTF files. These data are then exposed via the + * `metrics` variable and the getCharacterMetrics function. + */ + +// These font metrics are extracted from TeX by using +// \font\a=cmmi10 +// \showthe\fontdimenX\a +// where X is the corresponding variable number. These correspond to the font +// parameters of the symbol fonts. In TeX, there are actually three sets of +// dimensions, one for each of textstyle, scriptstyle, and scriptscriptstyle, +// but we only use the textstyle ones, and scale certain dimensions accordingly. +// See the TeXbook, page 441. var sigma1 = 0.025; var sigma2 = 0; var sigma3 = 0; @@ -22,6 +36,11 @@ var sigma20 = 2.390; var sigma21 = 0.101; var sigma22 = 0.250; +// These font metrics are extracted from TeX by using +// \font\a=cmex10 +// \showthe\fontdimenX\a +// where X is the corresponding variable number. These correspond to the font +// parameters of the extension fonts (family 3). See the TeXbook, page 441. var xi1 = 0; var xi2 = 0; var xi3 = 0; @@ -36,11 +55,15 @@ var xi11 = .2; var xi12 = .6; var xi13 = .1; -// This value is also used in katex.less, if you change it make sure the values +// This value determines how large a pt is, for metrics which are defined in +// terms of pts. +// This value is also used in katex.less; if you change it make sure the values // match. var ptPerEm = 10.0; -// This is just a mapping from common names to real metrics +/** + * This is just a mapping from common names to real metrics + */ var metrics = { xHeight: sigma5, quad: sigma6, @@ -68,9 +91,16 @@ var metrics = { ptPerEm: ptPerEm }; -// This map is generated by metric_parse.rb +// This map contains a mapping from font name and character code to character +// metrics, including height, depth, italic correction, and skew (kern from the +// character to the corresponding \skewchar) +// This map is generated via `make metrics`. It should not be changed manually. var metricMap = {"AMS-Regular":{"10003":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"10016":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"1008":{"depth":0.0,"height":0.43056,"italic":0.04028,"skew":0},"107":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"10731":{"depth":0.11111,"height":0.69224,"italic":0.0,"skew":0},"10846":{"depth":0.19444,"height":0.75583,"italic":0.0,"skew":0},"10877":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"10878":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"10885":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"10886":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"10887":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"10888":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"10889":{"depth":0.26167,"height":0.75726,"italic":0.0,"skew":0},"10890":{"depth":0.26167,"height":0.75726,"italic":0.0,"skew":0},"10891":{"depth":0.48256,"height":0.98256,"italic":0.0,"skew":0},"10892":{"depth":0.48256,"height":0.98256,"italic":0.0,"skew":0},"10901":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"10902":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"10933":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"10934":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"10935":{"depth":0.26167,"height":0.75726,"italic":0.0,"skew":0},"10936":{"depth":0.26167,"height":0.75726,"italic":0.0,"skew":0},"10937":{"depth":0.26167,"height":0.75726,"italic":0.0,"skew":0},"10938":{"depth":0.26167,"height":0.75726,"italic":0.0,"skew":0},"10949":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"10950":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"10955":{"depth":0.28481,"height":0.79383,"italic":0.0,"skew":0},"10956":{"depth":0.28481,"height":0.79383,"italic":0.0,"skew":0},"165":{"depth":0.0,"height":0.675,"italic":0.025,"skew":0},"174":{"depth":0.15559,"height":0.69224,"italic":0.0,"skew":0},"240":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"295":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"57350":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"57351":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"57352":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"57353":{"depth":0.0,"height":0.43056,"italic":0.04028,"skew":0},"57356":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"57357":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"57358":{"depth":0.41951,"height":0.91951,"italic":0.0,"skew":0},"57359":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"57360":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"57361":{"depth":0.41951,"height":0.91951,"italic":0.0,"skew":0},"57366":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"57367":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"57368":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"57369":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"57370":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"57371":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"65":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"66":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"67":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"68":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"69":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"70":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"71":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"72":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"73":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.9,"italic":0.0,"skew":0},"74":{"depth":0.16667,"height":0.68889,"italic":0.0,"skew":0},"75":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"76":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"77":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.9,"italic":0.0,"skew":0},"78":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"79":{"depth":0.16667,"height":0.68889,"italic":0.0,"skew":0},"80":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"81":{"depth":0.16667,"height":0.68889,"italic":0.0,"skew":0},"82":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8245":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"83":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"84":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8463":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8487":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8498":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"85":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8502":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8503":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8504":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8513":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8592":{"depth":-0.03598,"height":0.46402,"italic":0.0,"skew":0},"8594":{"depth":-0.03598,"height":0.46402,"italic":0.0,"skew":0},"86":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8602":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8603":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8606":{"depth":0.01354,"height":0.52239,"italic":0.0,"skew":0},"8608":{"depth":0.01354,"height":0.52239,"italic":0.0,"skew":0},"8610":{"depth":0.01354,"height":0.52239,"italic":0.0,"skew":0},"8611":{"depth":0.01354,"height":0.52239,"italic":0.0,"skew":0},"8619":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8620":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8621":{"depth":-0.13313,"height":0.37788,"italic":0.0,"skew":0},"8622":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8624":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8625":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8630":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"8631":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"8634":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8635":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8638":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8639":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8642":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8643":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8644":{"depth":0.1808,"height":0.675,"italic":0.0,"skew":0},"8646":{"depth":0.1808,"height":0.675,"italic":0.0,"skew":0},"8647":{"depth":0.1808,"height":0.675,"italic":0.0,"skew":0},"8648":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8649":{"depth":0.1808,"height":0.675,"italic":0.0,"skew":0},"8650":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8651":{"depth":0.01354,"height":0.52239,"italic":0.0,"skew":0},"8652":{"depth":0.01354,"height":0.52239,"italic":0.0,"skew":0},"8653":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8654":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8655":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8666":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8667":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8669":{"depth":-0.13313,"height":0.37788,"italic":0.0,"skew":0},"87":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8705":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"8708":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8709":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8717":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"8722":{"depth":-0.03598,"height":0.46402,"italic":0.0,"skew":0},"8724":{"depth":0.08198,"height":0.69224,"italic":0.0,"skew":0},"8726":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8733":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8736":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8737":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8738":{"depth":0.03517,"height":0.52239,"italic":0.0,"skew":0},"8739":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8740":{"depth":0.25142,"height":0.74111,"italic":0.0,"skew":0},"8741":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8742":{"depth":0.25142,"height":0.74111,"italic":0.0,"skew":0},"8756":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8757":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8764":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8765":{"depth":-0.13313,"height":0.37788,"italic":0.0,"skew":0},"8769":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8770":{"depth":-0.03625,"height":0.46375,"italic":0.0,"skew":0},"8774":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8776":{"depth":-0.01688,"height":0.48312,"italic":0.0,"skew":0},"8778":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8782":{"depth":0.06062,"height":0.54986,"italic":0.0,"skew":0},"8783":{"depth":0.06062,"height":0.54986,"italic":0.0,"skew":0},"8785":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8786":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8787":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8790":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8791":{"depth":0.22958,"height":0.72958,"italic":0.0,"skew":0},"8796":{"depth":0.08198,"height":0.91667,"italic":0.0,"skew":0},"88":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8806":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"8807":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"8808":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"8809":{"depth":0.25142,"height":0.75726,"italic":0.0,"skew":0},"8812":{"depth":0.25583,"height":0.75583,"italic":0.0,"skew":0},"8814":{"depth":0.20576,"height":0.70576,"italic":0.0,"skew":0},"8815":{"depth":0.20576,"height":0.70576,"italic":0.0,"skew":0},"8816":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8817":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8818":{"depth":0.22958,"height":0.72958,"italic":0.0,"skew":0},"8819":{"depth":0.22958,"height":0.72958,"italic":0.0,"skew":0},"8822":{"depth":0.1808,"height":0.675,"italic":0.0,"skew":0},"8823":{"depth":0.1808,"height":0.675,"italic":0.0,"skew":0},"8828":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8829":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8830":{"depth":0.22958,"height":0.72958,"italic":0.0,"skew":0},"8831":{"depth":0.22958,"height":0.72958,"italic":0.0,"skew":0},"8832":{"depth":0.20576,"height":0.70576,"italic":0.0,"skew":0},"8833":{"depth":0.20576,"height":0.70576,"italic":0.0,"skew":0},"8840":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8841":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8842":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8843":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8847":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8848":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8858":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8859":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8861":{"depth":0.08198,"height":0.58198,"italic":0.0,"skew":0},"8862":{"depth":0.0,"height":0.675,"italic":0.0,"skew":0},"8863":{"depth":0.0,"height":0.675,"italic":0.0,"skew":0},"8864":{"depth":0.0,"height":0.675,"italic":0.0,"skew":0},"8865":{"depth":0.0,"height":0.675,"italic":0.0,"skew":0},"8872":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8873":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8874":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8876":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8877":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8878":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8879":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8882":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8883":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8884":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8885":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8888":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8890":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0},"8891":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8892":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"89":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8901":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8903":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8905":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8906":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0},"8907":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8908":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8909":{"depth":-0.03598,"height":0.46402,"italic":0.0,"skew":0},"8910":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8911":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8912":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8913":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8914":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8915":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"8916":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8918":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8919":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8920":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8921":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"8922":{"depth":0.38569,"height":0.88569,"italic":0.0,"skew":0},"8923":{"depth":0.38569,"height":0.88569,"italic":0.0,"skew":0},"8926":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8927":{"depth":0.13667,"height":0.63667,"italic":0.0,"skew":0},"8928":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8929":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8934":{"depth":0.23222,"height":0.74111,"italic":0.0,"skew":0},"8935":{"depth":0.23222,"height":0.74111,"italic":0.0,"skew":0},"8936":{"depth":0.23222,"height":0.74111,"italic":0.0,"skew":0},"8937":{"depth":0.23222,"height":0.74111,"italic":0.0,"skew":0},"8938":{"depth":0.20576,"height":0.70576,"italic":0.0,"skew":0},"8939":{"depth":0.20576,"height":0.70576,"italic":0.0,"skew":0},"8940":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8941":{"depth":0.30274,"height":0.79383,"italic":0.0,"skew":0},"8994":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"8995":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"90":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"9416":{"depth":0.15559,"height":0.69224,"italic":0.0,"skew":0},"9484":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"9488":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"9492":{"depth":0.0,"height":0.37788,"italic":0.0,"skew":0},"9496":{"depth":0.0,"height":0.37788,"italic":0.0,"skew":0},"9585":{"depth":0.19444,"height":0.68889,"italic":0.0,"skew":0},"9586":{"depth":0.19444,"height":0.74111,"italic":0.0,"skew":0},"9632":{"depth":0.0,"height":0.675,"italic":0.0,"skew":0},"9633":{"depth":0.0,"height":0.675,"italic":0.0,"skew":0},"9650":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"9651":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"9654":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"9660":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"9661":{"depth":0.0,"height":0.54986,"italic":0.0,"skew":0},"9664":{"depth":0.03517,"height":0.54986,"italic":0.0,"skew":0},"9674":{"depth":0.11111,"height":0.69224,"italic":0.0,"skew":0},"9733":{"depth":0.19444,"height":0.69224,"italic":0.0,"skew":0},"989":{"depth":0.08167,"height":0.58167,"italic":0.0,"skew":0}},"Main-Bold":{"100":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"101":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"102":{"depth":0.0,"height":0.69444,"italic":0.10903,"skew":0},"10216":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"10217":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"103":{"depth":0.19444,"height":0.44444,"italic":0.01597,"skew":0},"104":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"105":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"106":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"107":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"108":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"10815":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"109":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"10927":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"10928":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"110":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"111":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"112":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"113":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"114":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"115":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"116":{"depth":0.0,"height":0.63492,"italic":0.0,"skew":0},"117":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"118":{"depth":0.0,"height":0.44444,"italic":0.01597,"skew":0},"119":{"depth":0.0,"height":0.44444,"italic":0.01597,"skew":0},"120":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"121":{"depth":0.19444,"height":0.44444,"italic":0.01597,"skew":0},"122":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"123":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"124":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"125":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"126":{"depth":0.35,"height":0.34444,"italic":0.0,"skew":0},"168":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"172":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"175":{"depth":0.0,"height":0.59611,"italic":0.0,"skew":0},"176":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"177":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"180":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"215":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"247":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"305":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"33":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"34":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"35":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"36":{"depth":0.05556,"height":0.75,"italic":0.0,"skew":0},"37":{"depth":0.05556,"height":0.75,"italic":0.0,"skew":0},"38":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"39":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"40":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"41":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"42":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"43":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"44":{"depth":0.19444,"height":0.15556,"italic":0.0,"skew":0},"45":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"46":{"depth":0.0,"height":0.15556,"italic":0.0,"skew":0},"47":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"48":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"49":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"50":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"51":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"52":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"53":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"54":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"55":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"56":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"567":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"57":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"58":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"59":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"60":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"61":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"62":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"63":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"64":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"65":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"66":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"67":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"68":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"69":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"70":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"71":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"711":{"depth":0.0,"height":0.63194,"italic":0.0,"skew":0},"713":{"depth":0.0,"height":0.59611,"italic":0.0,"skew":0},"714":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"715":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"72":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"728":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"729":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"73":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"730":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"74":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"75":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"76":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"768":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"769":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"77":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"772":{"depth":0.0,"height":0.59611,"italic":0.0,"skew":0},"774":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"775":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"776":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"778":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"779":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"78":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"780":{"depth":0.0,"height":0.63194,"italic":0.0,"skew":0},"79":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"80":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"81":{"depth":0.19444,"height":0.68611,"italic":0.0,"skew":0},"82":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"8211":{"depth":0.0,"height":0.44444,"italic":0.03194,"skew":0},"8212":{"depth":0.0,"height":0.44444,"italic":0.03194,"skew":0},"8216":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8217":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8220":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8221":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8224":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8225":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"824":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8242":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"83":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"84":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"8407":{"depth":0.0,"height":0.72444,"italic":0.15486,"skew":0},"8463":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8465":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8467":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8472":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"8476":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"85":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"8501":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8592":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8593":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8594":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8595":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8596":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8597":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8598":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8599":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"86":{"depth":0.0,"height":0.68611,"italic":0.01597,"skew":0},"8600":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8601":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8636":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8637":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8640":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8641":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8656":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8657":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8658":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8659":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8660":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8661":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"87":{"depth":0.0,"height":0.68611,"italic":0.01597,"skew":0},"8704":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8706":{"depth":0.0,"height":0.69444,"italic":0.06389,"skew":0},"8707":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8709":{"depth":0.05556,"height":0.75,"italic":0.0,"skew":0},"8711":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"8712":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8715":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8722":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8723":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8725":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8726":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8727":{"depth":-0.02778,"height":0.47222,"italic":0.0,"skew":0},"8728":{"depth":-0.02639,"height":0.47361,"italic":0.0,"skew":0},"8729":{"depth":-0.02639,"height":0.47361,"italic":0.0,"skew":0},"8730":{"depth":0.18,"height":0.82,"italic":0.0,"skew":0},"8733":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"8734":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"8736":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8739":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8741":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8743":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8744":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8745":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8746":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8747":{"depth":0.19444,"height":0.69444,"italic":0.12778,"skew":0},"8764":{"depth":-0.10889,"height":0.39111,"italic":0.0,"skew":0},"8768":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8771":{"depth":0.00222,"height":0.50222,"italic":0.0,"skew":0},"8776":{"depth":0.02444,"height":0.52444,"italic":0.0,"skew":0},"8781":{"depth":0.00222,"height":0.50222,"italic":0.0,"skew":0},"88":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"8801":{"depth":0.00222,"height":0.50222,"italic":0.0,"skew":0},"8804":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"8805":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"8810":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8811":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8826":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8827":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8834":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8835":{"depth":0.08556,"height":0.58556,"italic":0.0,"skew":0},"8838":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"8839":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"8846":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8849":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"8850":{"depth":0.19667,"height":0.69667,"italic":0.0,"skew":0},"8851":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8852":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8853":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8854":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8855":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8856":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8857":{"depth":0.13333,"height":0.63333,"italic":0.0,"skew":0},"8866":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8867":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8868":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8869":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"89":{"depth":0.0,"height":0.68611,"italic":0.02875,"skew":0},"8900":{"depth":-0.02639,"height":0.47361,"italic":0.0,"skew":0},"8901":{"depth":-0.02639,"height":0.47361,"italic":0.0,"skew":0},"8902":{"depth":-0.02778,"height":0.47222,"italic":0.0,"skew":0},"8968":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8969":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8970":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8971":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8994":{"depth":-0.13889,"height":0.36111,"italic":0.0,"skew":0},"8995":{"depth":-0.13889,"height":0.36111,"italic":0.0,"skew":0},"90":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"91":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"915":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"916":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"92":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"920":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"923":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"926":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"928":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"93":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"931":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"933":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"934":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"936":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"937":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"94":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"95":{"depth":0.31,"height":0.13444,"italic":0.03194,"skew":0},"96":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"9651":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"9657":{"depth":-0.02778,"height":0.47222,"italic":0.0,"skew":0},"9661":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"9667":{"depth":-0.02778,"height":0.47222,"italic":0.0,"skew":0},"97":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"9711":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"98":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"9824":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9825":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9826":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9827":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9837":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"9838":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"9839":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"99":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0}},"Main-Italic":{"100":{"depth":0.0,"height":0.69444,"italic":0.10333,"skew":0},"101":{"depth":0.0,"height":0.43056,"italic":0.07514,"skew":0},"102":{"depth":0.19444,"height":0.69444,"italic":0.21194,"skew":0},"103":{"depth":0.19444,"height":0.43056,"italic":0.08847,"skew":0},"104":{"depth":0.0,"height":0.69444,"italic":0.07671,"skew":0},"105":{"depth":0.0,"height":0.65536,"italic":0.1019,"skew":0},"106":{"depth":0.19444,"height":0.65536,"italic":0.14467,"skew":0},"107":{"depth":0.0,"height":0.69444,"italic":0.10764,"skew":0},"108":{"depth":0.0,"height":0.69444,"italic":0.10333,"skew":0},"109":{"depth":0.0,"height":0.43056,"italic":0.07671,"skew":0},"110":{"depth":0.0,"height":0.43056,"italic":0.07671,"skew":0},"111":{"depth":0.0,"height":0.43056,"italic":0.06312,"skew":0},"112":{"depth":0.19444,"height":0.43056,"italic":0.06312,"skew":0},"113":{"depth":0.19444,"height":0.43056,"italic":0.08847,"skew":0},"114":{"depth":0.0,"height":0.43056,"italic":0.10764,"skew":0},"115":{"depth":0.0,"height":0.43056,"italic":0.08208,"skew":0},"116":{"depth":0.0,"height":0.61508,"italic":0.09486,"skew":0},"117":{"depth":0.0,"height":0.43056,"italic":0.07671,"skew":0},"118":{"depth":0.0,"height":0.43056,"italic":0.10764,"skew":0},"119":{"depth":0.0,"height":0.43056,"italic":0.10764,"skew":0},"120":{"depth":0.0,"height":0.43056,"italic":0.12042,"skew":0},"121":{"depth":0.19444,"height":0.43056,"italic":0.08847,"skew":0},"122":{"depth":0.0,"height":0.43056,"italic":0.12292,"skew":0},"126":{"depth":0.35,"height":0.31786,"italic":0.11585,"skew":0},"163":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"305":{"depth":0.0,"height":0.43056,"italic":0.07671,"skew":0},"33":{"depth":0.0,"height":0.69444,"italic":0.12417,"skew":0},"34":{"depth":0.0,"height":0.69444,"italic":0.06961,"skew":0},"35":{"depth":0.19444,"height":0.69444,"italic":0.06616,"skew":0},"37":{"depth":0.05556,"height":0.75,"italic":0.13639,"skew":0},"38":{"depth":0.0,"height":0.69444,"italic":0.09694,"skew":0},"39":{"depth":0.0,"height":0.69444,"italic":0.12417,"skew":0},"40":{"depth":0.25,"height":0.75,"italic":0.16194,"skew":0},"41":{"depth":0.25,"height":0.75,"italic":0.03694,"skew":0},"42":{"depth":0.0,"height":0.75,"italic":0.14917,"skew":0},"43":{"depth":0.05667,"height":0.56167,"italic":0.03694,"skew":0},"44":{"depth":0.19444,"height":0.10556,"italic":0.0,"skew":0},"45":{"depth":0.0,"height":0.43056,"italic":0.02826,"skew":0},"46":{"depth":0.0,"height":0.10556,"italic":0.0,"skew":0},"47":{"depth":0.25,"height":0.75,"italic":0.16194,"skew":0},"48":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"49":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"50":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"51":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"52":{"depth":0.19444,"height":0.64444,"italic":0.13556,"skew":0},"53":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"54":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"55":{"depth":0.19444,"height":0.64444,"italic":0.13556,"skew":0},"56":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"567":{"depth":0.19444,"height":0.43056,"italic":0.03736,"skew":0},"57":{"depth":0.0,"height":0.64444,"italic":0.13556,"skew":0},"58":{"depth":0.0,"height":0.43056,"italic":0.0582,"skew":0},"59":{"depth":0.19444,"height":0.43056,"italic":0.0582,"skew":0},"61":{"depth":-0.13313,"height":0.36687,"italic":0.06616,"skew":0},"63":{"depth":0.0,"height":0.69444,"italic":0.1225,"skew":0},"64":{"depth":0.0,"height":0.69444,"italic":0.09597,"skew":0},"65":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"66":{"depth":0.0,"height":0.68333,"italic":0.10257,"skew":0},"67":{"depth":0.0,"height":0.68333,"italic":0.14528,"skew":0},"68":{"depth":0.0,"height":0.68333,"italic":0.09403,"skew":0},"69":{"depth":0.0,"height":0.68333,"italic":0.12028,"skew":0},"70":{"depth":0.0,"height":0.68333,"italic":0.13305,"skew":0},"71":{"depth":0.0,"height":0.68333,"italic":0.08722,"skew":0},"72":{"depth":0.0,"height":0.68333,"italic":0.16389,"skew":0},"73":{"depth":0.0,"height":0.68333,"italic":0.15806,"skew":0},"74":{"depth":0.0,"height":0.68333,"italic":0.14028,"skew":0},"75":{"depth":0.0,"height":0.68333,"italic":0.14528,"skew":0},"76":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"768":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"769":{"depth":0.0,"height":0.69444,"italic":0.09694,"skew":0},"77":{"depth":0.0,"height":0.68333,"italic":0.16389,"skew":0},"770":{"depth":0.0,"height":0.69444,"italic":0.06646,"skew":0},"771":{"depth":0.0,"height":0.66786,"italic":0.11585,"skew":0},"772":{"depth":0.0,"height":0.56167,"italic":0.10333,"skew":0},"774":{"depth":0.0,"height":0.69444,"italic":0.10806,"skew":0},"775":{"depth":0.0,"height":0.66786,"italic":0.11752,"skew":0},"776":{"depth":0.0,"height":0.66786,"italic":0.10474,"skew":0},"778":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"779":{"depth":0.0,"height":0.69444,"italic":0.1225,"skew":0},"78":{"depth":0.0,"height":0.68333,"italic":0.16389,"skew":0},"780":{"depth":0.0,"height":0.62847,"italic":0.08295,"skew":0},"79":{"depth":0.0,"height":0.68333,"italic":0.09403,"skew":0},"80":{"depth":0.0,"height":0.68333,"italic":0.10257,"skew":0},"81":{"depth":0.19444,"height":0.68333,"italic":0.09403,"skew":0},"82":{"depth":0.0,"height":0.68333,"italic":0.03868,"skew":0},"8211":{"depth":0.0,"height":0.43056,"italic":0.09208,"skew":0},"8212":{"depth":0.0,"height":0.43056,"italic":0.09208,"skew":0},"8216":{"depth":0.0,"height":0.69444,"italic":0.12417,"skew":0},"8217":{"depth":0.0,"height":0.69444,"italic":0.12417,"skew":0},"8220":{"depth":0.0,"height":0.69444,"italic":0.1685,"skew":0},"8221":{"depth":0.0,"height":0.69444,"italic":0.06961,"skew":0},"83":{"depth":0.0,"height":0.68333,"italic":0.11972,"skew":0},"84":{"depth":0.0,"height":0.68333,"italic":0.13305,"skew":0},"8463":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"85":{"depth":0.0,"height":0.68333,"italic":0.16389,"skew":0},"86":{"depth":0.0,"height":0.68333,"italic":0.18361,"skew":0},"87":{"depth":0.0,"height":0.68333,"italic":0.18361,"skew":0},"88":{"depth":0.0,"height":0.68333,"italic":0.15806,"skew":0},"89":{"depth":0.0,"height":0.68333,"italic":0.19383,"skew":0},"90":{"depth":0.0,"height":0.68333,"italic":0.14528,"skew":0},"91":{"depth":0.25,"height":0.75,"italic":0.1875,"skew":0},"915":{"depth":0.0,"height":0.68333,"italic":0.13305,"skew":0},"916":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"920":{"depth":0.0,"height":0.68333,"italic":0.09403,"skew":0},"923":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"926":{"depth":0.0,"height":0.68333,"italic":0.15294,"skew":0},"928":{"depth":0.0,"height":0.68333,"italic":0.16389,"skew":0},"93":{"depth":0.25,"height":0.75,"italic":0.10528,"skew":0},"931":{"depth":0.0,"height":0.68333,"italic":0.12028,"skew":0},"933":{"depth":0.0,"height":0.68333,"italic":0.11111,"skew":0},"934":{"depth":0.0,"height":0.68333,"italic":0.05986,"skew":0},"936":{"depth":0.0,"height":0.68333,"italic":0.11111,"skew":0},"937":{"depth":0.0,"height":0.68333,"italic":0.10257,"skew":0},"94":{"depth":0.0,"height":0.69444,"italic":0.06646,"skew":0},"95":{"depth":0.31,"height":0.12056,"italic":0.09208,"skew":0},"97":{"depth":0.0,"height":0.43056,"italic":0.07671,"skew":0},"98":{"depth":0.0,"height":0.69444,"italic":0.06312,"skew":0},"99":{"depth":0.0,"height":0.43056,"italic":0.05653,"skew":0}},"Main-Regular":{"32":{"0.0":0},"160":{"0.0":0},"8230":{"-0.0":0,"120.0":0.12},"8773":{"-22.0":-0.022,"0":0,"589.0":0.589},"8800":{"0":0,"215.0":0.215,"716.0":0.716},"8942":{"0":0,"30.0":0.03,"900.0":0.9},"8943":{"-190.0":-0.19,"0":0,"310.0":0.31},"8945":{"-100.0":-0.1,"0":0,"820.0":0.82},"100":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"101":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"102":{"depth":0.0,"height":0.69444,"italic":0.07778,"skew":0},"10216":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"10217":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"103":{"depth":0.19444,"height":0.43056,"italic":0.01389,"skew":0},"104":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"105":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"106":{"depth":0.19444,"height":0.66786,"italic":0.0,"skew":0},"107":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"108":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"10815":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"109":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"10927":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"10928":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"110":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"111":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"112":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0},"113":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0},"114":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"115":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"116":{"depth":0.0,"height":0.61508,"italic":0.0,"skew":0},"117":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"118":{"depth":0.0,"height":0.43056,"italic":0.01389,"skew":0},"119":{"depth":0.0,"height":0.43056,"italic":0.01389,"skew":0},"120":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"121":{"depth":0.19444,"height":0.43056,"italic":0.01389,"skew":0},"122":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"123":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"124":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"125":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"126":{"depth":0.35,"height":0.31786,"italic":0.0,"skew":0},"168":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"172":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"175":{"depth":0.0,"height":0.56778,"italic":0.0,"skew":0},"176":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"177":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"180":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"215":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"247":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"305":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"33":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"34":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"35":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"36":{"depth":0.05556,"height":0.75,"italic":0.0,"skew":0},"37":{"depth":0.05556,"height":0.75,"italic":0.0,"skew":0},"38":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"39":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"40":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"41":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"42":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"43":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"44":{"depth":0.19444,"height":0.10556,"italic":0.0,"skew":0},"45":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"46":{"depth":0.0,"height":0.10556,"italic":0.0,"skew":0},"47":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"48":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"49":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"50":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"51":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"52":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"53":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"54":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"55":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"56":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"567":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0},"57":{"depth":0.0,"height":0.64444,"italic":0.0,"skew":0},"58":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"59":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0},"60":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"61":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"62":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"63":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"64":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"65":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"66":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"67":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"68":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"69":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"70":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"71":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"711":{"depth":0.0,"height":0.62847,"italic":0.0,"skew":0},"713":{"depth":0.0,"height":0.56778,"italic":0.0,"skew":0},"714":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"715":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"72":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"728":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"729":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"73":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"730":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"74":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"75":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"76":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"768":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"769":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"77":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"772":{"depth":0.0,"height":0.56778,"italic":0.0,"skew":0},"774":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"775":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"776":{"depth":0.0,"height":0.66786,"italic":0.0,"skew":0},"778":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"779":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"78":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"780":{"depth":0.0,"height":0.62847,"italic":0.0,"skew":0},"79":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"80":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"81":{"depth":0.19444,"height":0.68333,"italic":0.0,"skew":0},"82":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"8211":{"depth":0.0,"height":0.43056,"italic":0.02778,"skew":0},"8212":{"depth":0.0,"height":0.43056,"italic":0.02778,"skew":0},"8216":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8217":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8220":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8221":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8224":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8225":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"824":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8242":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"83":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"84":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"8407":{"depth":0.0,"height":0.71444,"italic":0.15382,"skew":0},"8463":{"depth":0.0,"height":0.68889,"italic":0.0,"skew":0},"8465":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8467":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0.11111},"8472":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.11111},"8476":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"85":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"8501":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8592":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8593":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8594":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8595":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8596":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8597":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8598":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8599":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"86":{"depth":0.0,"height":0.68333,"italic":0.01389,"skew":0},"8600":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8601":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8636":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8637":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8640":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8641":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8656":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8657":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8658":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8659":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8660":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8661":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"87":{"depth":0.0,"height":0.68333,"italic":0.01389,"skew":0},"8704":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8706":{"depth":0.0,"height":0.69444,"italic":0.05556,"skew":0.08334},"8707":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8709":{"depth":0.05556,"height":0.75,"italic":0.0,"skew":0},"8711":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"8712":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8715":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8722":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8723":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8725":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8726":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8727":{"depth":-0.03472,"height":0.46528,"italic":0.0,"skew":0},"8728":{"depth":-0.05555,"height":0.44445,"italic":0.0,"skew":0},"8729":{"depth":-0.05555,"height":0.44445,"italic":0.0,"skew":0},"8730":{"depth":0.2,"height":0.8,"italic":0.0,"skew":0},"8733":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"8734":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"8736":{"depth":0.0,"height":0.69224,"italic":0.0,"skew":0},"8739":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8741":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8743":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8744":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8745":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8746":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8747":{"depth":0.19444,"height":0.69444,"italic":0.11111,"skew":0},"8764":{"depth":-0.13313,"height":0.36687,"italic":0.0,"skew":0},"8768":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"8771":{"depth":-0.03625,"height":0.46375,"italic":0.0,"skew":0},"8776":{"depth":-0.01688,"height":0.48312,"italic":0.0,"skew":0},"8781":{"depth":-0.03625,"height":0.46375,"italic":0.0,"skew":0},"88":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"8801":{"depth":-0.03625,"height":0.46375,"italic":0.0,"skew":0},"8804":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8805":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8810":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8811":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8826":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8827":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8834":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8835":{"depth":0.0391,"height":0.5391,"italic":0.0,"skew":0},"8838":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8839":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8846":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8849":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8850":{"depth":0.13597,"height":0.63597,"italic":0.0,"skew":0},"8851":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8852":{"depth":0.0,"height":0.55556,"italic":0.0,"skew":0},"8853":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8854":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8855":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8856":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8857":{"depth":0.08333,"height":0.58333,"italic":0.0,"skew":0},"8866":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8867":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8868":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"8869":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"89":{"depth":0.0,"height":0.68333,"italic":0.025,"skew":0},"8900":{"depth":-0.05555,"height":0.44445,"italic":0.0,"skew":0},"8901":{"depth":-0.05555,"height":0.44445,"italic":0.0,"skew":0},"8902":{"depth":-0.03472,"height":0.46528,"italic":0.0,"skew":0},"8968":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8969":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8970":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8971":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"8994":{"depth":-0.14236,"height":0.35764,"italic":0.0,"skew":0},"8995":{"depth":-0.14236,"height":0.35764,"italic":0.0,"skew":0},"90":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"91":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"915":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"916":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"92":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"920":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"923":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"926":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"928":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"93":{"depth":0.25,"height":0.75,"italic":0.0,"skew":0},"931":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"933":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"934":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"936":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"937":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0},"94":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"95":{"depth":0.31,"height":0.12056,"italic":0.02778,"skew":0},"96":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"9651":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"9657":{"depth":-0.03472,"height":0.46528,"italic":0.0,"skew":0},"9661":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"9667":{"depth":-0.03472,"height":0.46528,"italic":0.0,"skew":0},"97":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"9711":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"98":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"9824":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9825":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9826":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9827":{"depth":0.12963,"height":0.69444,"italic":0.0,"skew":0},"9837":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"9838":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"9839":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"99":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0}},"Math-BoldItalic":{"100":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"1009":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"101":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"1013":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"102":{"depth":0.19444,"height":0.69444,"italic":0.11042,"skew":0},"103":{"depth":0.19444,"height":0.44444,"italic":0.03704,"skew":0},"104":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"105":{"depth":0.0,"height":0.69326,"italic":0.0,"skew":0},"106":{"depth":0.19444,"height":0.69326,"italic":0.0622,"skew":0},"107":{"depth":0.0,"height":0.69444,"italic":0.01852,"skew":0},"108":{"depth":0.0,"height":0.69444,"italic":0.0088,"skew":0},"109":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"110":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"111":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"112":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"113":{"depth":0.19444,"height":0.44444,"italic":0.03704,"skew":0},"114":{"depth":0.0,"height":0.44444,"italic":0.03194,"skew":0},"115":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"116":{"depth":0.0,"height":0.63492,"italic":0.0,"skew":0},"117":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"118":{"depth":0.0,"height":0.44444,"italic":0.03704,"skew":0},"119":{"depth":0.0,"height":0.44444,"italic":0.02778,"skew":0},"120":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"121":{"depth":0.19444,"height":0.44444,"italic":0.03704,"skew":0},"122":{"depth":0.0,"height":0.44444,"italic":0.04213,"skew":0},"47":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"65":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"66":{"depth":0.0,"height":0.68611,"italic":0.04835,"skew":0},"67":{"depth":0.0,"height":0.68611,"italic":0.06979,"skew":0},"68":{"depth":0.0,"height":0.68611,"italic":0.03194,"skew":0},"69":{"depth":0.0,"height":0.68611,"italic":0.05451,"skew":0},"70":{"depth":0.0,"height":0.68611,"italic":0.15972,"skew":0},"71":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"72":{"depth":0.0,"height":0.68611,"italic":0.08229,"skew":0},"73":{"depth":0.0,"height":0.68611,"italic":0.07778,"skew":0},"74":{"depth":0.0,"height":0.68611,"italic":0.10069,"skew":0},"75":{"depth":0.0,"height":0.68611,"italic":0.06979,"skew":0},"76":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"77":{"depth":0.0,"height":0.68611,"italic":0.11424,"skew":0},"78":{"depth":0.0,"height":0.68611,"italic":0.11424,"skew":0},"79":{"depth":0.0,"height":0.68611,"italic":0.03194,"skew":0},"80":{"depth":0.0,"height":0.68611,"italic":0.15972,"skew":0},"81":{"depth":0.19444,"height":0.68611,"italic":0.0,"skew":0},"82":{"depth":0.0,"height":0.68611,"italic":0.00421,"skew":0},"83":{"depth":0.0,"height":0.68611,"italic":0.05382,"skew":0},"84":{"depth":0.0,"height":0.68611,"italic":0.15972,"skew":0},"85":{"depth":0.0,"height":0.68611,"italic":0.11424,"skew":0},"86":{"depth":0.0,"height":0.68611,"italic":0.25555,"skew":0},"87":{"depth":0.0,"height":0.68611,"italic":0.15972,"skew":0},"88":{"depth":0.0,"height":0.68611,"italic":0.07778,"skew":0},"89":{"depth":0.0,"height":0.68611,"italic":0.25555,"skew":0},"90":{"depth":0.0,"height":0.68611,"italic":0.06979,"skew":0},"915":{"depth":0.0,"height":0.68611,"italic":0.15972,"skew":0},"916":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"920":{"depth":0.0,"height":0.68611,"italic":0.03194,"skew":0},"923":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"926":{"depth":0.0,"height":0.68611,"italic":0.07458,"skew":0},"928":{"depth":0.0,"height":0.68611,"italic":0.08229,"skew":0},"931":{"depth":0.0,"height":0.68611,"italic":0.05451,"skew":0},"933":{"depth":0.0,"height":0.68611,"italic":0.15972,"skew":0},"934":{"depth":0.0,"height":0.68611,"italic":0.0,"skew":0},"936":{"depth":0.0,"height":0.68611,"italic":0.11653,"skew":0},"937":{"depth":0.0,"height":0.68611,"italic":0.04835,"skew":0},"945":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"946":{"depth":0.19444,"height":0.69444,"italic":0.03403,"skew":0},"947":{"depth":0.19444,"height":0.44444,"italic":0.06389,"skew":0},"948":{"depth":0.0,"height":0.69444,"italic":0.03819,"skew":0},"949":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"950":{"depth":0.19444,"height":0.69444,"italic":0.06215,"skew":0},"951":{"depth":0.19444,"height":0.44444,"italic":0.03704,"skew":0},"952":{"depth":0.0,"height":0.69444,"italic":0.03194,"skew":0},"953":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"954":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"955":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"956":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"957":{"depth":0.0,"height":0.44444,"italic":0.06898,"skew":0},"958":{"depth":0.19444,"height":0.69444,"italic":0.03021,"skew":0},"959":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"960":{"depth":0.0,"height":0.44444,"italic":0.03704,"skew":0},"961":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"962":{"depth":0.09722,"height":0.44444,"italic":0.07917,"skew":0},"963":{"depth":0.0,"height":0.44444,"italic":0.03704,"skew":0},"964":{"depth":0.0,"height":0.44444,"italic":0.13472,"skew":0},"965":{"depth":0.0,"height":0.44444,"italic":0.03704,"skew":0},"966":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"967":{"depth":0.19444,"height":0.44444,"italic":0.0,"skew":0},"968":{"depth":0.19444,"height":0.69444,"italic":0.03704,"skew":0},"969":{"depth":0.0,"height":0.44444,"italic":0.03704,"skew":0},"97":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0},"977":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"98":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"981":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"982":{"depth":0.0,"height":0.44444,"italic":0.03194,"skew":0},"99":{"depth":0.0,"height":0.44444,"italic":0.0,"skew":0}},"Math-Italic":{"100":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0.16667},"1009":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"101":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"1013":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"102":{"depth":0.19444,"height":0.69444,"italic":0.10764,"skew":0.16667},"103":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.02778},"104":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"105":{"depth":0.0,"height":0.65952,"italic":0.0,"skew":0},"106":{"depth":0.19444,"height":0.65952,"italic":0.05724,"skew":0},"107":{"depth":0.0,"height":0.69444,"italic":0.03148,"skew":0},"108":{"depth":0.0,"height":0.69444,"italic":0.01968,"skew":0.08334},"109":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"110":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"111":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"112":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"113":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.08334},"114":{"depth":0.0,"height":0.43056,"italic":0.02778,"skew":0.05556},"115":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"116":{"depth":0.0,"height":0.61508,"italic":0.0,"skew":0.08334},"117":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.02778},"118":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0.02778},"119":{"depth":0.0,"height":0.43056,"italic":0.02691,"skew":0.08334},"120":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.02778},"121":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.05556},"122":{"depth":0.0,"height":0.43056,"italic":0.04398,"skew":0.05556},"47":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0},"65":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.13889},"66":{"depth":0.0,"height":0.68333,"italic":0.05017,"skew":0.08334},"67":{"depth":0.0,"height":0.68333,"italic":0.07153,"skew":0.08334},"68":{"depth":0.0,"height":0.68333,"italic":0.02778,"skew":0.05556},"69":{"depth":0.0,"height":0.68333,"italic":0.05764,"skew":0.08334},"70":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"71":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.08334},"72":{"depth":0.0,"height":0.68333,"italic":0.08125,"skew":0.05556},"73":{"depth":0.0,"height":0.68333,"italic":0.07847,"skew":0.11111},"74":{"depth":0.0,"height":0.68333,"italic":0.09618,"skew":0.16667},"75":{"depth":0.0,"height":0.68333,"italic":0.07153,"skew":0.05556},"76":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.02778},"77":{"depth":0.0,"height":0.68333,"italic":0.10903,"skew":0.08334},"78":{"depth":0.0,"height":0.68333,"italic":0.10903,"skew":0.08334},"79":{"depth":0.0,"height":0.68333,"italic":0.02778,"skew":0.08334},"80":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"81":{"depth":0.19444,"height":0.68333,"italic":0.0,"skew":0.08334},"82":{"depth":0.0,"height":0.68333,"italic":0.00773,"skew":0.08334},"83":{"depth":0.0,"height":0.68333,"italic":0.05764,"skew":0.08334},"84":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"85":{"depth":0.0,"height":0.68333,"italic":0.10903,"skew":0.02778},"86":{"depth":0.0,"height":0.68333,"italic":0.22222,"skew":0},"87":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0},"88":{"depth":0.0,"height":0.68333,"italic":0.07847,"skew":0.08334},"89":{"depth":0.0,"height":0.68333,"italic":0.22222,"skew":0},"90":{"depth":0.0,"height":0.68333,"italic":0.07153,"skew":0.08334},"915":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"916":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.16667},"920":{"depth":0.0,"height":0.68333,"italic":0.02778,"skew":0.08334},"923":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.16667},"926":{"depth":0.0,"height":0.68333,"italic":0.07569,"skew":0.08334},"928":{"depth":0.0,"height":0.68333,"italic":0.08125,"skew":0.05556},"931":{"depth":0.0,"height":0.68333,"italic":0.05764,"skew":0.08334},"933":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.05556},"934":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.08334},"936":{"depth":0.0,"height":0.68333,"italic":0.11,"skew":0.05556},"937":{"depth":0.0,"height":0.68333,"italic":0.05017,"skew":0.08334},"945":{"depth":0.0,"height":0.43056,"italic":0.0037,"skew":0.02778},"946":{"depth":0.19444,"height":0.69444,"italic":0.05278,"skew":0.08334},"947":{"depth":0.19444,"height":0.43056,"italic":0.05556,"skew":0},"948":{"depth":0.0,"height":0.69444,"italic":0.03785,"skew":0.05556},"949":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.08334},"950":{"depth":0.19444,"height":0.69444,"italic":0.07378,"skew":0.08334},"951":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.05556},"952":{"depth":0.0,"height":0.69444,"italic":0.02778,"skew":0.08334},"953":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"954":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"955":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"956":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.02778},"957":{"depth":0.0,"height":0.43056,"italic":0.06366,"skew":0.02778},"958":{"depth":0.19444,"height":0.69444,"italic":0.04601,"skew":0.11111},"959":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"960":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0},"961":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"962":{"depth":0.09722,"height":0.43056,"italic":0.07986,"skew":0.08334},"963":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0},"964":{"depth":0.0,"height":0.43056,"italic":0.1132,"skew":0.02778},"965":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0.02778},"966":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"967":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.05556},"968":{"depth":0.19444,"height":0.69444,"italic":0.03588,"skew":0.11111},"969":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0},"97":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"977":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0.08334},"98":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"981":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0.08334},"982":{"depth":0.0,"height":0.43056,"italic":0.02778,"skew":0},"99":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556}},"Math-Regular":{"100":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0.16667},"1009":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"101":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"1013":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"102":{"depth":0.19444,"height":0.69444,"italic":0.10764,"skew":0.16667},"103":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.02778},"104":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"105":{"depth":0.0,"height":0.65952,"italic":0.0,"skew":0},"106":{"depth":0.19444,"height":0.65952,"italic":0.05724,"skew":0},"107":{"depth":0.0,"height":0.69444,"italic":0.03148,"skew":0},"108":{"depth":0.0,"height":0.69444,"italic":0.01968,"skew":0.08334},"109":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"110":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"111":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"112":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"113":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.08334},"114":{"depth":0.0,"height":0.43056,"italic":0.02778,"skew":0.05556},"115":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"116":{"depth":0.0,"height":0.61508,"italic":0.0,"skew":0.08334},"117":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.02778},"118":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0.02778},"119":{"depth":0.0,"height":0.43056,"italic":0.02691,"skew":0.08334},"120":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.02778},"121":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.05556},"122":{"depth":0.0,"height":0.43056,"italic":0.04398,"skew":0.05556},"65":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.13889},"66":{"depth":0.0,"height":0.68333,"italic":0.05017,"skew":0.08334},"67":{"depth":0.0,"height":0.68333,"italic":0.07153,"skew":0.08334},"68":{"depth":0.0,"height":0.68333,"italic":0.02778,"skew":0.05556},"69":{"depth":0.0,"height":0.68333,"italic":0.05764,"skew":0.08334},"70":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"71":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.08334},"72":{"depth":0.0,"height":0.68333,"italic":0.08125,"skew":0.05556},"73":{"depth":0.0,"height":0.68333,"italic":0.07847,"skew":0.11111},"74":{"depth":0.0,"height":0.68333,"italic":0.09618,"skew":0.16667},"75":{"depth":0.0,"height":0.68333,"italic":0.07153,"skew":0.05556},"76":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.02778},"77":{"depth":0.0,"height":0.68333,"italic":0.10903,"skew":0.08334},"78":{"depth":0.0,"height":0.68333,"italic":0.10903,"skew":0.08334},"79":{"depth":0.0,"height":0.68333,"italic":0.02778,"skew":0.08334},"80":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"81":{"depth":0.19444,"height":0.68333,"italic":0.0,"skew":0.08334},"82":{"depth":0.0,"height":0.68333,"italic":0.00773,"skew":0.08334},"83":{"depth":0.0,"height":0.68333,"italic":0.05764,"skew":0.08334},"84":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"85":{"depth":0.0,"height":0.68333,"italic":0.10903,"skew":0.02778},"86":{"depth":0.0,"height":0.68333,"italic":0.22222,"skew":0},"87":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0},"88":{"depth":0.0,"height":0.68333,"italic":0.07847,"skew":0.08334},"89":{"depth":0.0,"height":0.68333,"italic":0.22222,"skew":0},"90":{"depth":0.0,"height":0.68333,"italic":0.07153,"skew":0.08334},"915":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.08334},"916":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.16667},"920":{"depth":0.0,"height":0.68333,"italic":0.02778,"skew":0.08334},"923":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.16667},"926":{"depth":0.0,"height":0.68333,"italic":0.07569,"skew":0.08334},"928":{"depth":0.0,"height":0.68333,"italic":0.08125,"skew":0.05556},"931":{"depth":0.0,"height":0.68333,"italic":0.05764,"skew":0.08334},"933":{"depth":0.0,"height":0.68333,"italic":0.13889,"skew":0.05556},"934":{"depth":0.0,"height":0.68333,"italic":0.0,"skew":0.08334},"936":{"depth":0.0,"height":0.68333,"italic":0.11,"skew":0.05556},"937":{"depth":0.0,"height":0.68333,"italic":0.05017,"skew":0.08334},"945":{"depth":0.0,"height":0.43056,"italic":0.0037,"skew":0.02778},"946":{"depth":0.19444,"height":0.69444,"italic":0.05278,"skew":0.08334},"947":{"depth":0.19444,"height":0.43056,"italic":0.05556,"skew":0},"948":{"depth":0.0,"height":0.69444,"italic":0.03785,"skew":0.05556},"949":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.08334},"950":{"depth":0.19444,"height":0.69444,"italic":0.07378,"skew":0.08334},"951":{"depth":0.19444,"height":0.43056,"italic":0.03588,"skew":0.05556},"952":{"depth":0.0,"height":0.69444,"italic":0.02778,"skew":0.08334},"953":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"954":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"955":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"956":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.02778},"957":{"depth":0.0,"height":0.43056,"italic":0.06366,"skew":0.02778},"958":{"depth":0.19444,"height":0.69444,"italic":0.04601,"skew":0.11111},"959":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556},"960":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0},"961":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"962":{"depth":0.09722,"height":0.43056,"italic":0.07986,"skew":0.08334},"963":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0},"964":{"depth":0.0,"height":0.43056,"italic":0.1132,"skew":0.02778},"965":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0.02778},"966":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.08334},"967":{"depth":0.19444,"height":0.43056,"italic":0.0,"skew":0.05556},"968":{"depth":0.19444,"height":0.69444,"italic":0.03588,"skew":0.11111},"969":{"depth":0.0,"height":0.43056,"italic":0.03588,"skew":0},"97":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0},"977":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0.08334},"98":{"depth":0.0,"height":0.69444,"italic":0.0,"skew":0},"981":{"depth":0.19444,"height":0.69444,"italic":0.0,"skew":0.08334},"982":{"depth":0.0,"height":0.43056,"italic":0.02778,"skew":0},"99":{"depth":0.0,"height":0.43056,"italic":0.0,"skew":0.05556}},"Size1-Regular":{"10216":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"10217":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"10752":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"10753":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"10754":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"10756":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"10758":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"123":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"125":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"40":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"41":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"47":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.72222,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.72222,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.72222,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.72222,"italic":0.0,"skew":0},"8214":{"depth":-0.00099,"height":0.601,"italic":0.0,"skew":0},"8593":{"depth":1e-05,"height":0.6,"italic":0.0,"skew":0},"8595":{"depth":1e-05,"height":0.6,"italic":0.0,"skew":0},"8657":{"depth":1e-05,"height":0.6,"italic":0.0,"skew":0},"8659":{"depth":1e-05,"height":0.6,"italic":0.0,"skew":0},"8719":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8720":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8721":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8730":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"8739":{"depth":-0.00599,"height":0.606,"italic":0.0,"skew":0},"8741":{"depth":-0.00599,"height":0.606,"italic":0.0,"skew":0},"8747":{"depth":0.30612,"height":0.805,"italic":0.19445,"skew":0},"8750":{"depth":0.30612,"height":0.805,"italic":0.19445,"skew":0},"8896":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8897":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8898":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8899":{"depth":0.25001,"height":0.75,"italic":0.0,"skew":0},"8968":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"8969":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"8970":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"8971":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"91":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"9168":{"depth":-0.00099,"height":0.601,"italic":0.0,"skew":0},"92":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0},"93":{"depth":0.35001,"height":0.85,"italic":0.0,"skew":0}},"Size2-Regular":{"10216":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"10217":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"10752":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"10753":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"10754":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"10756":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"10758":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"123":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"125":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"40":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"41":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"47":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"8719":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8720":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8721":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8730":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"8747":{"depth":0.86225,"height":1.36,"italic":0.44445,"skew":0},"8750":{"depth":0.86225,"height":1.36,"italic":0.44445,"skew":0},"8896":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8897":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8898":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8899":{"depth":0.55001,"height":1.05,"italic":0.0,"skew":0},"8968":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"8969":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"8970":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"8971":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"91":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"92":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"93":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0}},"Size3-Regular":{"10216":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"10217":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"123":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"125":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"40":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"41":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"47":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.75,"italic":0.0,"skew":0},"8730":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"8968":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"8969":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"8970":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"8971":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"91":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"92":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0},"93":{"depth":0.95003,"height":1.45,"italic":0.0,"skew":0}},"Size4-Regular":{"10216":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"10217":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"123":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"125":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"40":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"41":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"47":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"57344":{"depth":-0.00499,"height":0.605,"italic":0.0,"skew":0},"57345":{"depth":-0.00499,"height":0.605,"italic":0.0,"skew":0},"57680":{"depth":0.0,"height":0.12,"italic":0.0,"skew":0},"57681":{"depth":0.0,"height":0.12,"italic":0.0,"skew":0},"57682":{"depth":0.0,"height":0.12,"italic":0.0,"skew":0},"57683":{"depth":0.0,"height":0.12,"italic":0.0,"skew":0},"710":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"732":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"770":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"771":{"depth":0.0,"height":0.825,"italic":0.0,"skew":0},"8730":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"8968":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"8969":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"8970":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"8971":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"91":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"9115":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9116":{"depth":1e-05,"height":0.6,"italic":0.0,"skew":0},"9117":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9118":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9119":{"depth":1e-05,"height":0.6,"italic":0.0,"skew":0},"9120":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9121":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9122":{"depth":-0.00099,"height":0.601,"italic":0.0,"skew":0},"9123":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9124":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9125":{"depth":-0.00099,"height":0.601,"italic":0.0,"skew":0},"9126":{"depth":0.64502,"height":1.155,"italic":0.0,"skew":0},"9127":{"depth":1e-05,"height":0.9,"italic":0.0,"skew":0},"9128":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"9129":{"depth":0.90001,"height":0.0,"italic":0.0,"skew":0},"9130":{"depth":0.0,"height":0.3,"italic":0.0,"skew":0},"9131":{"depth":1e-05,"height":0.9,"italic":0.0,"skew":0},"9132":{"depth":0.65002,"height":1.15,"italic":0.0,"skew":0},"9133":{"depth":0.90001,"height":0.0,"italic":0.0,"skew":0},"9143":{"depth":0.88502,"height":0.915,"italic":0.0,"skew":0},"92":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0},"93":{"depth":1.25003,"height":1.75,"italic":0.0,"skew":0}}}; +/** + * This function is a convience function for looking up information in the + * metricMap table. It takes a character as a string, and a style + */ var getCharacterMetrics = function(character, style) { return metricMap[style][character.charCodeAt(0)]; }; diff --git a/katex.js b/katex.js @@ -1,9 +1,21 @@ +/** + * This is the main entry point for KaTeX. Here, we expose functions for + * rendering expressions either to DOM nodes or to markup strings. + * + * We also expose the ParseError class to check if errors thrown from KaTeX are + * errors in the expression, or errors in javascript handling. + */ + var ParseError = require("./ParseError"); var buildTree = require("./buildTree"); var parseTree = require("./parseTree"); var utils = require("./utils"); +/** + * Parse and build an expression, and place that expression in the DOM node + * given. + */ var process = function(toParse, baseNode) { utils.clearNode(baseNode); @@ -13,6 +25,9 @@ var process = function(toParse, baseNode) { baseNode.appendChild(node); }; +/** + * Parse and build an expression, and return the markup for that. + */ var renderToString = function(toParse) { var tree = parseTree(toParse); return buildTree(tree).toMarkup(); diff --git a/parseTree.js b/parseTree.js @@ -1,6 +1,13 @@ +/** + * Provides a single function for parsing an expression using a Parser + * TODO(emily): Remove this + */ + var Parser = require("./Parser"); -// Parses the expression using the parser +/** + * Parses an expression using a Parser, then returns the parsed result. + */ var parseTree = function(toParse) { var parser = new Parser(toParse); diff --git a/symbols.js b/symbols.js @@ -1,15 +1,18 @@ -/* This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). For each of the symbols, there are three - * properties they can have: - * - font (required): the font to be used for this * symbol. Either "main" (the - normal font), or "ams" (the ams fonts) +/** + * This file holds a list of all no-argument functions and single-character + * symbols (like 'a' or ';'). + * + * For each of the symbols, there are three properties they can have: + * - font (required): the font to be used for this symbol. Either "main" (the + normal font), or "ams" (the ams fonts). * - group (required): the ParseNode group type the symbol should have (i.e. - "textord" or "mathord" or - * - replace (optiona): the character that this symbol or function should be + "textord", "mathord", etc). + * - replace (optional): the character that this symbol or function should be * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font) - * There outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text") + * character in the main font). + * + * The outermost map in the table indicates what mode the symbols should be + * accepted in (e.g. "math" or "text"). */ var symbols = { @@ -854,6 +857,9 @@ var symbols = { } }; +// There are lots of symbols which are the same, so we add them in afterwards. + +// All of these are textords in math mode var mathTextSymbols = "0123456789/@.\""; for (var i = 0; i < mathTextSymbols.length; i++) { var ch = mathTextSymbols.charAt(i); @@ -863,6 +869,7 @@ for (var i = 0; i < mathTextSymbols.length; i++) { }; } +// All of these are textords in text mode var textSymbols = "0123456789`!@*()-=+[]'\";:?/.,"; for (var i = 0; i < textSymbols.length; i++) { var ch = textSymbols.charAt(i); @@ -872,6 +879,7 @@ for (var i = 0; i < textSymbols.length; i++) { }; } +// All of these are textords in text mode, and mathords in math mode var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (var i = 0; i < letters.length; i++) { var ch = letters.charAt(i); diff --git a/utils.js b/utils.js @@ -1,3 +1,12 @@ +/** + * This file contains a list of utility functions which are useful in other + * files. + */ + +/** + * Provide an `indexOf` function which works in IE8, but defers to native if + * possible. + */ var nativeIndexOf = Array.prototype.indexOf; var indexOf = function(list, elem) { if (list == null) { @@ -15,6 +24,9 @@ var indexOf = function(list, elem) { return -1; }; +/** + * Return whether an element is contained in a list + */ var contains = function(list, elem) { return indexOf(list, elem) !== -1; }; @@ -50,8 +62,11 @@ function escape(text) { return ('' + text).replace(ESCAPE_REGEX, escaper); } +/** + * A function to set the text content of a DOM element in all supported + * browsers. Note that we don't define this if there is no document. + */ var setTextContent; - if (typeof document !== "undefined") { var testNode = document.createElement("span"); if ("textContent" in testNode) { @@ -65,6 +80,9 @@ if (typeof document !== "undefined") { } } +/** + * A function to clear a node. + */ function clearNode(node) { setTextContent(node, ""); }