diff --git a/Options.js b/Options.js index 8d2a8d032..ca33a30bd 100644 --- a/Options.js +++ b/Options.js @@ -1,14 +1,8 @@ -function Options(style, size, color, deep, parentStyle, parentSize) { +function Options(style, size, color, parentStyle, parentSize) { this.style = style; this.color = color; this.size = size; - // TODO(emily): Get rid of deep when we can actually use sizing everywhere - if (deep === undefined) { - deep = false; - } - this.deep = deep; - if (parentStyle === undefined) { parentStyle = style; } @@ -21,28 +15,20 @@ function Options(style, size, color, deep, parentStyle, parentSize) { } Options.prototype.withStyle = function(style) { - return new Options(style, this.size, this.color, this.deep, - this.style, this.size); + return new Options(style, this.size, this.color, this.style, this.size); }; Options.prototype.withSize = function(size) { - return new Options(this.style, size, this.color, this.deep, - this.style, this.size); + return new Options(this.style, size, this.color, this.style, this.size); }; Options.prototype.withColor = function(color) { - return new Options(this.style, this.size, color, this.deep, - this.style, this.size); -}; - -Options.prototype.deepen = function() { - return new Options(this.style, this.size, this.color, true, - this.parentStyle, this.parentSize); + return new Options(this.style, this.size, color, this.style, this.size); }; Options.prototype.reset = function() { - return new Options(this.style, this.size, this.color, this.deep, - this.style, this.size); + return new Options( + this.style, this.size, this.color, this.style, this.size); }; var colorMap = { diff --git a/buildTree.js b/buildTree.js index 6e8b654fa..d9eeb10e7 100644 --- a/buildTree.js +++ b/buildTree.js @@ -21,6 +21,7 @@ var buildExpression = function(expression, options, prev) { var makeSpan = function(classes, children, color) { var height = 0; var depth = 0; + var maxFontSize = 0; if (children) { for (var i = 0; i < children.length; i++) { @@ -30,10 +31,14 @@ var makeSpan = function(classes, children, color) { if (children[i].depth > depth) { depth = children[i].depth; } + if (children[i].maxFontSize > maxFontSize) { + maxFontSize = children[i].maxFontSize; + } } } - var span = new domTree.span(classes, children, height, depth); + var span = new domTree.span( + classes, children, height, depth, maxFontSize); if (color) { span.style.color = color; @@ -42,6 +47,17 @@ var makeSpan = function(classes, children, color) { return span; }; +var makeFontSizer = function(options, fontSize) { + var fontSizeInner = makeSpan([], [new domTree.textNode("\u200b")]); + fontSizeInner.style.fontSize = (fontSize / options.style.sizeMultiplier) + "em"; + + var fontSizer = makeSpan( + ["fontsize-ensurer", "reset-" + options.size, "size5"], + [fontSizeInner]); + + return fontSizer; +}; + var groupToType = { mathord: "mord", textord: "mord", @@ -142,7 +158,7 @@ var groupTypes = { text: function(group, options, prev) { return makeSpan(["text mord", options.style.cls()], - [buildGroup(group.value, options.deepen())] + [buildGroup(group.value, options.reset())] ); }, @@ -151,18 +167,16 @@ var groupTypes = { if (group.value.sup) { var sup = buildGroup(group.value.sup, - options.withStyle(options.style.sup()).deepen()); + options.withStyle(options.style.sup())); var supmid = makeSpan( [options.style.reset(), options.style.sup().cls()], [sup]); - var supwrap = makeSpan(["msup", options.style.reset()], [supmid]); } if (group.value.sub) { var sub = buildGroup(group.value.sub, - options.withStyle(options.style.sub()).deepen()); + options.withStyle(options.style.sub())); var submid = makeSpan( [options.style.reset(), options.style.sub().cls()], [sub]); - var subwrap = makeSpan(["msub"], [submid]); } if (isCharacterBox(group.value.base)) { @@ -183,9 +197,11 @@ var groupTypes = { } var supsub; - var fixIE = makeSpan(["fix-ie"], [new domTree.textNode("\u00a0")]); if (!group.value.sup) { + var fontSizer = makeFontSizer(options, submid.maxFontSize); + var subwrap = makeSpan(["msub"], [fontSizer, submid]); + v = Math.max(v, fontMetrics.metrics.sub1, sub.height - 0.8 * fontMetrics.metrics.xHeight); @@ -194,8 +210,13 @@ var groupTypes = { subwrap.depth = subwrap.depth + v; subwrap.height = 0; + var fixIE = makeSpan(["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]); + supsub = makeSpan(["msupsub"], [subwrap, fixIE]); } else if (!group.value.sub) { + var fontSizer = makeFontSizer(options, supmid.maxFontSize); + var supwrap = makeSpan(["msup"], [fontSizer, supmid]); + u = Math.max(u, p, sup.depth + 0.25 * fontMetrics.metrics.xHeight); @@ -204,8 +225,15 @@ var groupTypes = { supwrap.height = supwrap.height + u; supwrap.depth = 0; + var fixIE = makeSpan(["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]); + supsub = makeSpan(["msupsub"], [supwrap, fixIE]); } else { + var fontSizer = makeFontSizer(options, + Math.max(submid.maxFontSize, supmid.maxFontSize)); + var subwrap = makeSpan(["msub"], [fontSizer, submid]); + var supwrap = makeSpan(["msup"], [fontSizer, supmid]); + u = Math.max(u, p, sup.depth + 0.25 * fontMetrics.metrics.xHeight); v = Math.max(v, fontMetrics.metrics.sub2); @@ -230,6 +258,8 @@ var groupTypes = { subwrap.height = 0; subwrap.depth = subwrap.depth + v; + var fixIE = makeSpan(["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]); + supsub = makeSpan(["msupsub"], [supwrap, subwrap, fixIE]); } @@ -263,15 +293,18 @@ var groupTypes = { var nstyle = fstyle.fracNum(); var dstyle = fstyle.fracDen(); - var numer = buildGroup(group.value.numer, options.withStyle(nstyle).deepen()); + var numer = buildGroup(group.value.numer, options.withStyle(nstyle)); var numernumer = makeSpan([fstyle.reset(), nstyle.cls()], [numer]); - var numerrow = makeSpan(["mfracnum"], [numernumer]); - var mid = makeSpan(["mfracmid"], [makeSpan()]); - - var denom = buildGroup(group.value.denom, options.withStyle(dstyle).deepen()); + var denom = buildGroup(group.value.denom, options.withStyle(dstyle)); var denomdenom = makeSpan([fstyle.reset(), dstyle.cls()], [denom]) - var denomrow = makeSpan(["mfracden"], [denomdenom]); + + var fontSizer = makeFontSizer(options, + Math.max(numer.maxFontSize, denom.maxFontSize)); + + var numerrow = makeSpan(["mfracnum"], [fontSizer, numernumer]); + var mid = makeSpan(["mfracmid"], [fontSizer, makeSpan(["line"])]); + var denomrow = makeSpan(["mfracden"], [fontSizer, denomdenom]); var theta = fontMetrics.metrics.defaultRuleThickness; @@ -306,7 +339,8 @@ var groupTypes = { denomrow.height = 0; denomrow.depth = denomrow.depth + v; - var fixIE = makeSpan(["fix-ie"], [new domTree.textNode("\u00a0")]); + var fixIE = makeSpan(["fix-ie"], [ + fontSizer, new domTree.textNode("\u00a0")]); var frac = makeSpan([], [numerrow, mid, denomrow, fixIE]); @@ -366,14 +400,14 @@ var groupTypes = { llap: function(group, options, prev) { var inner = makeSpan( - ["inner"], [buildGroup(group.value, options.deepen())]); + ["inner"], [buildGroup(group.value, options.reset())]); var fix = makeSpan(["fix"], []); return makeSpan(["llap", options.style.cls()], [inner, fix]); }, rlap: function(group, options, prev) { var inner = makeSpan( - ["inner"], [buildGroup(group.value, options.deepen())]); + ["inner"], [buildGroup(group.value, options.reset())]); var fix = makeSpan(["fix"], []); return makeSpan(["rlap", options.style.cls()], [inner, fix]); }, @@ -422,14 +456,18 @@ var groupTypes = { overline: function(group, options, prev) { var innerGroup = buildGroup(group.value.result, - options.withStyle(options.style.cramp()).deepen()); + options.withStyle(options.style.cramp())); + + var fontSizer = makeFontSizer(options, innerGroup.maxFontSize); // The theta variable in the TeXbook var lineWidth = fontMetrics.metrics.defaultRuleThickness; - var line = makeSpan(["overline-line"], [makeSpan([])]); - var inner = makeSpan(["overline-inner"], [innerGroup]); - var fixIE = makeSpan(["fix-ie"], []); + var line = makeSpan( + ["overline-line"], [fontSizer, makeSpan(["line"])]); + var inner = makeSpan(["overline-inner"], [fontSizer, innerGroup]); + var fixIE = makeSpan( + ["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]); line.style.top = (-inner.height - 3 * lineWidth) + "em"; // The line is supposed to have 1 extra line width above it in height @@ -445,10 +483,27 @@ var groupTypes = { var inner = buildGroup(group.value.value, options.withSize(group.value.size), prev); - return makeSpan( - ["sizing", "reset-" + options.size, group.value.size, - getTypeOfGroup(group.value.value)], - [inner]); + var span = makeSpan([getTypeOfGroup(group.value.value)], + [makeSpan(["sizing", "reset-" + options.size, group.value.size], + [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]; + span.maxFontSize = fontSize * options.style.sizeMultiplier; + + return span; }, delimsizing: function(group, options, prev) { @@ -518,9 +573,21 @@ var groupTypes = { var inner = mathrmSize( original, group.value.size, group.mode); - return makeSpan( - ["delimsizing", size, groupToType[group.value.type]], - [inner], options.getColor()); + var node = makeSpan( + [options.style.reset(), Style.TEXT.cls(), + groupToType[group.value.type]], + [makeSpan( + ["delimsizing", size, groupToType[group.value.type]], + [inner], options.getColor())]); + + var multiplier = Style.TEXT.sizeMultiplier / + options.style.sizeMultiplier; + + node.height *= multiplier; + node.depth *= multiplier; + node.maxFontSize = 1.0; + + return node; } else if (utils.contains(stackDelimiters, original)) { // These delimiters can be created by stacking other delimiters on // top of each other to create the correct size @@ -602,9 +669,20 @@ var groupTypes = { var fixIE = makeSpan(["fix-ie"], [new domTree.textNode("\u00a0")]); inners.push(fixIE); - return makeSpan( - ["delimsizing", "mult", groupToType[group.value.type]], - inners, options.getColor()); + var node = makeSpan( + [options.style.reset(), Style.TEXT.cls(), + groupToType[group.value.type]], + [makeSpan(["delimsizing", "mult"], + inners, options.getColor())]); + + var multiplier = Style.TEXT.sizeMultiplier / + options.style.sizeMultiplier; + + node.height *= multiplier; + node.depth *= multiplier; + node.maxFontSize = 1.0; + + return node; } else { throw new ParseError("Illegal delimiter: '" + original + "'"); } @@ -644,11 +722,6 @@ var buildGroup = function(group, options, prev) { var multiplier = sizingMultiplier[options.size] / sizingMultiplier[options.parentSize]; - if (options.deep) { - throw new ParseError( - "Can't use sizing outside of the root node"); - } - groupNode.height *= multiplier; groupNode.depth *= multiplier; } diff --git a/domTree.js b/domTree.js index b8e183cd0..d87607cff 100644 --- a/domTree.js +++ b/domTree.js @@ -3,11 +3,12 @@ // function. They are useful for both storing extra properties on the nodes, as // well as providing a way to easily work with the DOM. -function span(classes, children, height, depth, style) { +function span(classes, children, height, depth, maxFontSize, style) { this.classes = classes || []; this.children = children || []; this.height = height || 0; this.depth = depth || 0; + this.maxFontSize = maxFontSize || 0; this.style = style || {}; } diff --git a/static/katex.less b/static/katex.less index c60d249b5..822b9c3ca 100644 --- a/static/katex.less +++ b/static/katex.less @@ -34,6 +34,11 @@ big parens font-family: KaTeX_AMS; } + .fix-ie { + display: inline-table; + table-layout: fixed; + } + @thinspace: 0.16667em; @mediumspace: 0.22222em; @thickspace: 0.27778em; @@ -188,10 +193,6 @@ big parens .baseline-align-hack-inner; } } - - .fix-ie { - display: inline-block; - } } .mfrac { @@ -210,11 +211,7 @@ big parens } } - .fix-ie { - display: inline-block; - } - - .mfracmid > span { + .mfracmid > .line { width: 100%; &:before { @@ -323,11 +320,7 @@ big parens } } - > .fix-ie { - display: inline-block; - } - - > .overline-line > span { + > .overline-line > .line { width: 100%; &:before { @@ -347,7 +340,7 @@ big parens } } - .sizing { + .sizing, .fontsize-ensurer { display: inline-block; @size1: 0.5; diff --git a/test/huxley/DeepFontSizing.hux/firefox-1.png b/test/huxley/DeepFontSizing.hux/firefox-1.png new file mode 100644 index 000000000..99b18ddad Binary files /dev/null and b/test/huxley/DeepFontSizing.hux/firefox-1.png differ diff --git a/test/huxley/DeepFontSizing.hux/record.json b/test/huxley/DeepFontSizing.hux/record.json new file mode 100644 index 000000000..3cae6ac65 --- /dev/null +++ b/test/huxley/DeepFontSizing.hux/record.json @@ -0,0 +1,5 @@ +[ + { + "action": "screenshot" + } +] diff --git a/test/huxley/DelimiterSizing.hux/firefox-1.png b/test/huxley/DelimiterSizing.hux/firefox-1.png index 4ad62c262..cf432632b 100644 Binary files a/test/huxley/DelimiterSizing.hux/firefox-1.png and b/test/huxley/DelimiterSizing.hux/firefox-1.png differ diff --git a/test/huxley/Huxleyfile.json b/test/huxley/Huxleyfile.json index d265f333e..c023443ab 100644 --- a/test/huxley/Huxleyfile.json +++ b/test/huxley/Huxleyfile.json @@ -105,5 +105,17 @@ "name": "Overline", "screenSize": [1024, 768], "url": "http://localhost:7936/test/huxley/test.html?m=\\overline{x}\\overline{x}\\overline{x^{x^{x^x}}} \\blue\\overline{y}" + }, + + { + "name": "DeepFontSizing", + "screenSize": [1024, 768], + "url": "http://localhost:7936/test/huxley/test.html?m=a^{\\big| x^{\\big(}}_{\\Big\\uparrow} + i^{i^{\\Huge x}_y}_{\\Huge z} + \\dfrac{\\Huge x}{y}" + }, + + { + "name": "VerticalSpacing", + "screenSize": [1024, 768], + "url": "http://localhost:7936/test/huxley/test.html?pre=potato
&post=
moo&m=x^{\\Huge y}z" } ] diff --git a/test/huxley/Overline.hux/firefox-1.png b/test/huxley/Overline.hux/firefox-1.png index d16429077..0ae10a096 100644 Binary files a/test/huxley/Overline.hux/firefox-1.png and b/test/huxley/Overline.hux/firefox-1.png differ diff --git a/test/huxley/VerticalSpacing.hux/firefox-1.png b/test/huxley/VerticalSpacing.hux/firefox-1.png new file mode 100644 index 000000000..302f89b80 Binary files /dev/null and b/test/huxley/VerticalSpacing.hux/firefox-1.png differ diff --git a/test/huxley/VerticalSpacing.hux/record.json b/test/huxley/VerticalSpacing.hux/record.json new file mode 100644 index 000000000..3cae6ac65 --- /dev/null +++ b/test/huxley/VerticalSpacing.hux/record.json @@ -0,0 +1,5 @@ +[ + { + "action": "screenshot" + } +]