// @flow import buildCommon from "../buildCommon"; import defineFunction from "../defineFunction"; import mathMLTree from "../mathMLTree"; import {makeEm} from "../units"; import * as html from "../buildHTML"; import * as mml from "../buildMathML"; import type Options from "../Options"; import type {AnyParseNode} from "../parseNode"; import type {HtmlBuilder} from "../defineFunction"; import type {documentFragment as HtmlDocumentFragment} from "../domTree"; export function sizingGroup( value: AnyParseNode[], options: Options, baseOptions: Options, ): HtmlDocumentFragment { const inner = html.buildExpression(value, options, false); const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; // Add size-resetting classes to the inner list and set maxFontSize // manually. Handle nested size changes. for (let i = 0; i < inner.length; i++) { const pos = inner[i].classes.indexOf("sizing"); if (pos < 0) { Array.prototype.push.apply(inner[i].classes, options.sizingClasses(baseOptions)); } else if (inner[i].classes[pos + 1] === "reset-size" + options.size) { // This is a nested size change: e.g., inner[i] is the "b" in // `\Huge a \small b`. Override the old size (the `reset-` class) // but not the new size. inner[i].classes[pos + 1] = "reset-size" + baseOptions.size; } inner[i].height *= multiplier; inner[i].depth *= multiplier; } return buildCommon.makeFragment(inner); } const sizeFuncs = [ "\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge", ]; export const htmlBuilder: HtmlBuilder<"sizing"> = (group, options) => { // Handle sizing operators like \Huge. Real TeX doesn't actually allow // these functions inside of math expressions, so we do some special // handling. const newOptions = options.havingSize(group.size); return sizingGroup(group.body, newOptions, options); }; defineFunction({ type: "sizing", names: sizeFuncs, props: { numArgs: 0, allowedInText: true, }, handler: ({breakOnTokenText, funcName, parser}, args) => { const body = parser.parseExpression(false, breakOnTokenText); return { type: "sizing", mode: parser.mode, // Figure out what size to use based on the list of functions above size: sizeFuncs.indexOf(funcName) + 1, body, }; }, htmlBuilder, mathmlBuilder: (group, options) => { const newOptions = options.havingSize(group.size); const inner = mml.buildExpression(group.body, newOptions); const node = new mathMLTree.MathNode("mstyle", inner); // TODO(emily): This doesn't produce the correct size for nested size // changes, because we don't keep state of what style we're currently // in, so we can't reset the size to normal before changing it. Now // that we're passing an options parameter we should be able to fix // this. node.setAttribute("mathsize", makeEm(newOptions.sizeMultiplier)); return node; }, });