diff --git a/packages/math/base-elements.lua b/packages/math/base-elements.lua index f3cd31e55..b743767ff 100644 --- a/packages/math/base-elements.lua +++ b/packages/math/base-elements.lua @@ -1523,7 +1523,7 @@ function elements.sqrt:output (x, y, line) local symbol = { _r(self.radicalRuleThickness), "w", -- line width - 2, + 1, "j", -- round line joins _r(sw + s0), _r(self.extraAscender), @@ -1598,6 +1598,63 @@ end function elements.padded.output (_, _, _, _) end +-- Bevelled fractions are not part of MathML Core, and MathML4 does not +-- exactly specify how to compute the layout. +elements.bevelledFraction = pl.class(elements.fraction) -- Inherit from fraction +elements.fraction._type = "BevelledFraction" + +function elements.bevelledFraction:shape () + local constants = self:getMathMetrics().constants + local scaleDown = self:getScaleDown() + local hSkew = constants.skewedFractionHorizontalGap * scaleDown + -- OpenType has properties which are not totally explicit. + -- The definition of skewedFractionVerticalGap (and its value in fonts + -- such as Libertinus Math) seems to imply that it is measured from the + -- bottom of the numerator to the top of the denominator. + -- This does not seem to be a nice general layout. + -- So we will use superscriptShiftUp(Cramped) for the numerator: + local vSkewUp = isCrampedMode(self.mode) and constants.superscriptShiftUpCramped * scaleDown + or constants.superscriptShiftUp * scaleDown + -- And all good books say that the denominator should not be shifted down: + local vSkewDown = 0 + + self.ruleThickness = self.attributes.linethickness + and SU.cast("measurement", self.attributes.linethickness):tonumber() + or constants.fractionRuleThickness * scaleDown + self.numerator.relX = SILE.types.length(0) + self.numerator.relY = SILE.types.length(-vSkewUp) + self.denominator.relX = self.numerator.width + hSkew + self.denominator.relY = SILE.types.length(vSkewDown) + self.width = self.numerator.width + self.denominator.width + hSkew + self.height = maxLength(self.numerator.height + vSkewUp, self.denominator.height - vSkewDown) + self.depth = maxLength(self.numerator.depth - vSkewUp, self.denominator.depth + vSkewDown) + self.barWidth = SILE.types.length(hSkew) + self.barX = self.numerator.relX + self.numerator.width +end + +function elements.bevelledFraction:output (x, y, line) + local h = self.height:tonumber() + local d = self.depth:tonumber() + local barwidth = scaleWidth(self.barWidth, line):tonumber() + local xscaled = scaleWidth(x + self.barX, line) + local rd = self.ruleThickness / 2 + local symbol = { + _r(self.ruleThickness), + "w", -- line width + 1, + "J", -- round line caps + _r(0), + _r(d + h - rd), + "m", + _r(barwidth), + _r(rd), + "l", + "S", + } + local svg = table.concat(symbol, " ") + SILE.outputter:drawSVG(svg, xscaled, y, barwidth, h, 1) +end + elements.mathMode = mathMode elements.atomType = atomType elements.symbolDefaults = symbolDefaults diff --git a/packages/math/typesetter.lua b/packages/math/typesetter.lua index bbc82f856..dbf9ede78 100644 --- a/packages/math/typesetter.lua +++ b/packages/math/typesetter.lua @@ -147,7 +147,9 @@ function ConvertMathML (_, content) if #children ~= 2 then SU.error("Wrong number of children in mfrac: " .. #children) end - return b.fraction(content.options, children[1], children[2]) + return SU.boolean(content.options.bevelled, false) + and b.bevelledFraction(content.options, children[1], children[2]) + or b.fraction(content.options, children[1], children[2]) elseif content.command == "msqrt" then local children = convertChildren(content) -- "The element generates an anonymous box called the msqrt base