|
|
|
import defineFunction from "../defineFunction"; |
|
import buildCommon from "../buildCommon"; |
|
import mathMLTree from "../mathMLTree"; |
|
import delimiter from "../delimiter"; |
|
import Style from "../Style"; |
|
import {makeEm} from "../units"; |
|
|
|
import * as html from "../buildHTML"; |
|
import * as mml from "../buildMathML"; |
|
|
|
defineFunction({ |
|
type: "sqrt", |
|
names: ["\\sqrt"], |
|
props: { |
|
numArgs: 1, |
|
numOptionalArgs: 1, |
|
}, |
|
handler({parser}, args, optArgs) { |
|
const index = optArgs[0]; |
|
const body = args[0]; |
|
return { |
|
type: "sqrt", |
|
mode: parser.mode, |
|
body, |
|
index, |
|
}; |
|
}, |
|
htmlBuilder(group, options) { |
|
|
|
|
|
|
|
|
|
let inner = html.buildGroup(group.body, options.havingCrampedStyle()); |
|
if (inner.height === 0) { |
|
|
|
inner.height = options.fontMetrics().xHeight; |
|
} |
|
|
|
|
|
|
|
inner = buildCommon.wrapFragment(inner, options); |
|
|
|
|
|
const metrics = options.fontMetrics(); |
|
const theta = metrics.defaultRuleThickness; |
|
|
|
let phi = theta; |
|
if (options.style.id < Style.TEXT.id) { |
|
phi = options.fontMetrics().xHeight; |
|
} |
|
|
|
|
|
let lineClearance = theta + phi / 4; |
|
|
|
const minDelimiterHeight = (inner.height + inner.depth + |
|
lineClearance + theta); |
|
|
|
|
|
const {span: img, ruleWidth, advanceWidth} = |
|
delimiter.sqrtImage(minDelimiterHeight, options); |
|
|
|
const delimDepth = img.height - ruleWidth; |
|
|
|
|
|
if (delimDepth > inner.height + inner.depth + lineClearance) { |
|
lineClearance = |
|
(lineClearance + delimDepth - inner.height - inner.depth) / 2; |
|
} |
|
|
|
|
|
const imgShift = img.height - inner.height - lineClearance - ruleWidth; |
|
|
|
inner.style.paddingLeft = makeEm(advanceWidth); |
|
|
|
|
|
const body = buildCommon.makeVList({ |
|
positionType: "firstBaseline", |
|
children: [ |
|
{type: "elem", elem: inner, wrapperClasses: ["svg-align"]}, |
|
{type: "kern", size: -(inner.height + imgShift)}, |
|
{type: "elem", elem: img}, |
|
{type: "kern", size: ruleWidth}, |
|
], |
|
}, options); |
|
|
|
if (!group.index) { |
|
return buildCommon.makeSpan(["mord", "sqrt"], [body], options); |
|
} else { |
|
|
|
|
|
|
|
const newOptions = options.havingStyle(Style.SCRIPTSCRIPT); |
|
const rootm = html.buildGroup(group.index, newOptions, options); |
|
|
|
|
|
|
|
const toShift = 0.6 * (body.height - body.depth); |
|
|
|
|
|
const rootVList = buildCommon.makeVList({ |
|
positionType: "shift", |
|
positionData: -toShift, |
|
children: [{type: "elem", elem: rootm}], |
|
}, options); |
|
|
|
|
|
const rootVListWrap = buildCommon.makeSpan(["root"], [rootVList]); |
|
|
|
return buildCommon.makeSpan(["mord", "sqrt"], |
|
[rootVListWrap, body], options); |
|
} |
|
}, |
|
mathmlBuilder(group, options) { |
|
const {body, index} = group; |
|
return index ? |
|
new mathMLTree.MathNode( |
|
"mroot", [ |
|
mml.buildGroup(body, options), |
|
mml.buildGroup(index, options), |
|
]) : |
|
new mathMLTree.MathNode( |
|
"msqrt", [mml.buildGroup(body, options)]); |
|
}, |
|
}); |
|
|