|
|
|
import buildCommon from "../../buildCommon"; |
|
import * as html from "../../buildHTML"; |
|
import utils from "../../utils"; |
|
import type {StyleInterface} from "../../Style"; |
|
import type Options from "../../Options"; |
|
import type {DomSpan, SymbolNode} from "../../domTree"; |
|
import type {AnyParseNode} from "../../parseNode"; |
|
import {makeEm} from "../../units"; |
|
|
|
|
|
|
|
export const assembleSupSub = ( |
|
base: DomSpan | SymbolNode, |
|
supGroup: ?AnyParseNode, |
|
subGroup: ?AnyParseNode, |
|
options: Options, |
|
style: StyleInterface, |
|
slant: number, |
|
baseShift: number, |
|
): DomSpan => { |
|
base = buildCommon.makeSpan([], [base]); |
|
const subIsSingleCharacter = subGroup && utils.isCharacterBox(subGroup); |
|
let sub; |
|
let sup; |
|
|
|
|
|
if (supGroup) { |
|
const elem = html.buildGroup( |
|
supGroup, options.havingStyle(style.sup()), options); |
|
|
|
sup = { |
|
elem, |
|
kern: Math.max( |
|
options.fontMetrics().bigOpSpacing1, |
|
options.fontMetrics().bigOpSpacing3 - elem.depth), |
|
}; |
|
} |
|
|
|
if (subGroup) { |
|
const elem = html.buildGroup( |
|
subGroup, options.havingStyle(style.sub()), options); |
|
|
|
sub = { |
|
elem, |
|
kern: Math.max( |
|
options.fontMetrics().bigOpSpacing2, |
|
options.fontMetrics().bigOpSpacing4 - elem.height), |
|
}; |
|
} |
|
|
|
|
|
|
|
let finalGroup; |
|
if (sup && sub) { |
|
const bottom = options.fontMetrics().bigOpSpacing5 + |
|
sub.elem.height + sub.elem.depth + |
|
sub.kern + |
|
base.depth + baseShift; |
|
|
|
finalGroup = buildCommon.makeVList({ |
|
positionType: "bottom", |
|
positionData: bottom, |
|
children: [ |
|
{type: "kern", size: options.fontMetrics().bigOpSpacing5}, |
|
{type: "elem", elem: sub.elem, marginLeft: makeEm(-slant)}, |
|
{type: "kern", size: sub.kern}, |
|
{type: "elem", elem: base}, |
|
{type: "kern", size: sup.kern}, |
|
{type: "elem", elem: sup.elem, marginLeft: makeEm(slant)}, |
|
{type: "kern", size: options.fontMetrics().bigOpSpacing5}, |
|
], |
|
}, options); |
|
} else if (sub) { |
|
const top = base.height - baseShift; |
|
|
|
|
|
|
|
|
|
|
|
finalGroup = buildCommon.makeVList({ |
|
positionType: "top", |
|
positionData: top, |
|
children: [ |
|
{type: "kern", size: options.fontMetrics().bigOpSpacing5}, |
|
{type: "elem", elem: sub.elem, marginLeft: makeEm(-slant)}, |
|
{type: "kern", size: sub.kern}, |
|
{type: "elem", elem: base}, |
|
], |
|
}, options); |
|
} else if (sup) { |
|
const bottom = base.depth + baseShift; |
|
|
|
finalGroup = buildCommon.makeVList({ |
|
positionType: "bottom", |
|
positionData: bottom, |
|
children: [ |
|
{type: "elem", elem: base}, |
|
{type: "kern", size: sup.kern}, |
|
{type: "elem", elem: sup.elem, marginLeft: makeEm(slant)}, |
|
{type: "kern", size: options.fontMetrics().bigOpSpacing5}, |
|
], |
|
}, options); |
|
} else { |
|
|
|
|
|
|
|
return base; |
|
} |
|
|
|
const parts = [finalGroup]; |
|
if (sub && slant !== 0 && !subIsSingleCharacter) { |
|
|
|
|
|
const spacer = buildCommon.makeSpan(["mspace"], [], options); |
|
spacer.style.marginRight = makeEm(slant); |
|
parts.unshift(spacer); |
|
} |
|
return buildCommon.makeSpan(["mop", "op-limits"], parts, options); |
|
}; |
|
|