extract overline, underline, and rule into their own files (#999)

This commit is contained in:
Kevin Barabash
2017-11-27 23:42:55 -05:00
committed by GitHub
parent 7036eb85cd
commit 98203ad6ba
9 changed files with 195 additions and 158 deletions

View File

@@ -9,6 +9,7 @@ import domTree from "./domTree";
import fontMetrics from "./fontMetrics"; import fontMetrics from "./fontMetrics";
import symbols from "./symbols"; import symbols from "./symbols";
import utils from "./utils"; import utils from "./utils";
import stretchy from "./stretchy";
import type Options from "./Options"; import type Options from "./Options";
import type ParseNode from "./ParseNode"; import type ParseNode from "./ParseNode";
@@ -274,6 +275,19 @@ const makeSpan = function(
return span; return span;
}; };
const makeLineSpan = function(
className: string,
options: Options,
) {
// Fill the entire span instead of just a border. That way, the min-height
// value in katex.less will ensure that at least one screen pixel displays.
const line = stretchy.ruleSpan(className, options);
line.height = options.fontMetrics().defaultRuleThickness;
line.style.height = line.height + "em";
line.maxFontSize = 1.0;
return line;
};
/** /**
* Makes an anchor with the given href, list of classes, list of children, * Makes an anchor with the given href, list of classes, list of children,
* and options. * and options.
@@ -612,6 +626,7 @@ export default {
makeSymbol, makeSymbol,
mathsym, mathsym,
makeSpan, makeSpan,
makeLineSpan,
makeAnchor, makeAnchor,
makeFragment, makeFragment,
makeVList, makeVList,

View File

@@ -474,63 +474,6 @@ groupTypes.spacing = function(group, options) {
} }
}; };
export const makeLineSpan = function(className, options, thickness) {
// Fill the entire span instead of just a border. That way, the min-height
// value in katex.less will ensure that at least one screen pixel displays.
const line = stretchy.ruleSpan(className, options);
line.height = thickness || options.fontMetrics().defaultRuleThickness;
line.style.height = line.height + "em";
line.maxFontSize = 1.0;
return line;
};
groupTypes.overline = function(group, options) {
// Overlines are handled in the TeXbook pg 443, Rule 9.
// Build the inner group in the cramped style.
const innerGroup = buildGroup(group.value.body,
options.havingCrampedStyle());
// Create the line above the body
const line = makeLineSpan("overline-line", options);
// Generate the vlist, with the appropriate kerns
const vlist = buildCommon.makeVList({
positionType: "firstBaseline",
children: [
{type: "elem", elem: innerGroup},
{type: "kern", size: 3 * line.height},
{type: "elem", elem: line},
{type: "kern", size: line.height},
],
}, options);
return makeSpan(["mord", "overline"], [vlist], options);
};
groupTypes.underline = function(group, options) {
// Underlines are handled in the TeXbook pg 443, Rule 10.
// Build the inner group.
const innerGroup = buildGroup(group.value.body, options);
// Create the line above the body
const line = makeLineSpan("underline-line", options);
// Generate the vlist, with the appropriate kerns
const vlist = buildCommon.makeVList({
positionType: "top",
positionData: innerGroup.height,
children: [
{type: "kern", size: line.height},
{type: "elem", elem: line},
{type: "kern", size: 3 * line.height},
{type: "elem", elem: innerGroup},
],
}, options);
return makeSpan(["mord", "underline"], [vlist], options);
};
groupTypes.sqrt = function(group, options) { groupTypes.sqrt = function(group, options) {
// Square roots are handled in the TeXbook pg. 443, Rule 11. // Square roots are handled in the TeXbook pg. 443, Rule 11.
@@ -705,36 +648,6 @@ groupTypes.verb = function(group, options) {
body, newOptions); body, newOptions);
}; };
groupTypes.rule = function(group, options) {
// Make an empty span for the rule
const rule = makeSpan(["mord", "rule"], [], options);
// Calculate the shift, width, and height of the rule, and account for units
let shift = 0;
if (group.value.shift) {
shift = calculateSize(group.value.shift, options);
}
const width = calculateSize(group.value.width, options);
const height = calculateSize(group.value.height, options);
// Style the rule to the right size
rule.style.borderRightWidth = width + "em";
rule.style.borderTopWidth = height + "em";
rule.style.bottom = shift + "em";
// Record the height and width
rule.width = width;
rule.height = height + shift;
rule.depth = -shift;
// Font size is the number large enough that the browser will
// reserve at least `absHeight` space above the baseline.
// The 1.125 factor was empirically determined
rule.maxFontSize = height * 1.125 * options.sizeMultiplier;
return rule;
};
groupTypes.accent = function(group, options) { groupTypes.accent = function(group, options) {
// Accents are handled in the TeXbook pg. 443, rule 12. // Accents are handled in the TeXbook pg. 443, rule 12.
let base = group.value.base; let base = group.value.base;

View File

@@ -359,32 +359,6 @@ groupTypes.verb = function(group, options) {
return node; return node;
}; };
groupTypes.overline = function(group, options) {
const operator = new mathMLTree.MathNode(
"mo", [new mathMLTree.TextNode("\u203e")]);
operator.setAttribute("stretchy", "true");
const node = new mathMLTree.MathNode(
"mover",
[buildGroup(group.value.body, options), operator]);
node.setAttribute("accent", "true");
return node;
};
groupTypes.underline = function(group, options) {
const operator = new mathMLTree.MathNode(
"mo", [new mathMLTree.TextNode("\u203e")]);
operator.setAttribute("stretchy", "true");
const node = new mathMLTree.MathNode(
"munder",
[buildGroup(group.value.body, options), operator]);
node.setAttribute("accentunder", "true");
return node;
};
groupTypes.accentUnder = function(group, options) { groupTypes.accentUnder = function(group, options) {
const accentNode = stretchy.mathMLnode(group.value.label); const accentNode = stretchy.mathMLnode(group.value.label);
const node = new mathMLTree.MathNode( const node = new mathMLTree.MathNode(
@@ -460,14 +434,6 @@ groupTypes.xArrow = function(group, options) {
return node; return node;
}; };
groupTypes.rule = function(group) {
// TODO(emily): Figure out if there's an actual way to draw black boxes
// in MathML.
const node = new mathMLTree.MathNode("mrow");
return node;
};
groupTypes.mclass = function(group, options) { groupTypes.mclass = function(group, options) {
const inner = buildExpression(group.value.value, options); const inner = buildExpression(group.value.value, options);
return new mathMLTree.MathNode("mstyle", inner); return new mathMLTree.MathNode("mstyle", inner);

View File

@@ -59,6 +59,7 @@ class span implements CombinableDomNode {
children: DomChildNode[]; children: DomChildNode[];
height: number; height: number;
depth: number; depth: number;
width: ?number;
maxFontSize: number; maxFontSize: number;
style: {[string]: string}; style: {[string]: string};
attributes: {[string]: string}; attributes: {[string]: string};

View File

@@ -124,44 +124,11 @@ defineFunction(["\\fcolorbox"], {
}; };
}); });
// An overline import "./functions/overline";
defineFunction(["\\overline"], {
numArgs: 1,
}, function(context, args) {
const body = args[0];
return {
type: "overline",
body: body,
};
});
// An underline import "./functions/underline";
defineFunction(["\\underline"], {
numArgs: 1,
}, function(context, args) {
const body = args[0];
return {
type: "underline",
body: body,
};
});
// A box of the width and height import "./functions/rule";
defineFunction(["\\rule"], {
numArgs: 2,
numOptionalArgs: 1,
argTypes: ["size", "size", "size"],
}, function(context, args, optArgs) {
const shift = optArgs[0];
const width = args[0];
const height = args[1];
return {
type: "rule",
shift: shift && shift.value,
width: width.value,
height: height.value,
};
});
import "./functions/kern"; import "./functions/kern";

View File

@@ -93,7 +93,7 @@ defineFunction({
let ruleWidth; let ruleWidth;
let ruleSpacing; let ruleSpacing;
if (group.value.hasBarLine) { if (group.value.hasBarLine) {
rule = html.makeLineSpan("frac-line", options); rule = buildCommon.makeLineSpan("frac-line", options);
ruleWidth = rule.height; ruleWidth = rule.height;
ruleSpacing = rule.height; ruleSpacing = rule.height;
} else { } else {

57
src/functions/overline.js Normal file
View File

@@ -0,0 +1,57 @@
// @flow
import defineFunction from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
defineFunction({
type: "overline",
names: ["\\overline"],
props: {
numArgs: 1,
},
handler(context, args) {
const body = args[0];
return {
type: "overline",
body: body,
};
},
htmlBuilder(group, options) {
// Overlines are handled in the TeXbook pg 443, Rule 9.
// Build the inner group in the cramped style.
const innerGroup = html.buildGroup(group.value.body,
options.havingCrampedStyle());
// Create the line above the body
const line = buildCommon.makeLineSpan("overline-line", options);
// Generate the vlist, with the appropriate kerns
const vlist = buildCommon.makeVList({
positionType: "firstBaseline",
children: [
{type: "elem", elem: innerGroup},
{type: "kern", size: 3 * line.height},
{type: "elem", elem: line},
{type: "kern", size: line.height},
],
}, options);
return buildCommon.makeSpan(["mord", "overline"], [vlist], options);
},
mathmlBuilder(group, options) {
const operator = new mathMLTree.MathNode(
"mo", [new mathMLTree.TextNode("\u203e")]);
operator.setAttribute("stretchy", "true");
const node = new mathMLTree.MathNode(
"mover",
[mml.buildGroup(group.value.body, options), operator]);
node.setAttribute("accent", "true");
return node;
},
});

62
src/functions/rule.js Normal file
View File

@@ -0,0 +1,62 @@
// @flow
import buildCommon from "../buildCommon";
import defineFunction from "../defineFunction";
import mathMLTree from "../mathMLTree";
import {calculateSize} from "../units";
defineFunction({
type: "rule",
names: ["\\rule"],
props: {
numArgs: 2,
numOptionalArgs: 1,
argTypes: ["size", "size", "size"],
},
handler(context, args, optArgs) {
const shift = optArgs[0];
const width = args[0];
const height = args[1];
return {
type: "rule",
shift: shift && shift.value,
width: width.value,
height: height.value,
};
},
htmlBuilder(group, options) {
// Make an empty span for the rule
const rule = buildCommon.makeSpan(["mord", "rule"], [], options);
// Calculate the shift, width, and height of the rule, and account for units
let shift = 0;
if (group.value.shift) {
shift = calculateSize(group.value.shift, options);
}
const width = calculateSize(group.value.width, options);
const height = calculateSize(group.value.height, options);
// Style the rule to the right size
rule.style.borderRightWidth = width + "em";
rule.style.borderTopWidth = height + "em";
rule.style.bottom = shift + "em";
// Record the height and width
rule.width = width;
rule.height = height + shift;
rule.depth = -shift;
// Font size is the number large enough that the browser will
// reserve at least `absHeight` space above the baseline.
// The 1.125 factor was empirically determined
rule.maxFontSize = height * 1.125 * options.sizeMultiplier;
return rule;
},
mathmlBuilder(group, options) {
// TODO(emily): Figure out if there's an actual way to draw black boxes
// in MathML.
const node = new mathMLTree.MathNode("mrow");
return node;
},
});

View File

@@ -0,0 +1,56 @@
// @flow
import defineFunction from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
defineFunction({
type: "underline",
names: ["\\underline"],
props: {
numArgs: 1,
},
handler(context, args) {
const body = args[0];
return {
type: "underline",
body: body,
};
},
htmlBuilder(group, options) {
// Underlines are handled in the TeXbook pg 443, Rule 10.
// Build the inner group.
const innerGroup = html.buildGroup(group.value.body, options);
// Create the line above the body
const line = buildCommon.makeLineSpan("underline-line", options);
// Generate the vlist, with the appropriate kerns
const vlist = buildCommon.makeVList({
positionType: "top",
positionData: innerGroup.height,
children: [
{type: "kern", size: line.height},
{type: "elem", elem: line},
{type: "kern", size: 3 * line.height},
{type: "elem", elem: innerGroup},
],
}, options);
return buildCommon.makeSpan(["mord", "underline"], [vlist], options);
},
mathmlBuilder(group, options) {
const operator = new mathMLTree.MathNode(
"mo", [new mathMLTree.TextNode("\u203e")]);
operator.setAttribute("stretchy", "true");
const node = new mathMLTree.MathNode(
"munder",
[mml.buildGroup(group.value.body, options), operator]);
node.setAttribute("accentunder", "true");
return node;
},
});