RenderMathMLFraction::FractionParameters RenderMathMLFraction::fractionParameters()
{
    ASSERT(!isStack());
    FractionParameters parameters;

    // We try and read constants to draw the fraction from the OpenType MATH and use fallback values otherwise.
    const auto& primaryFont = style().fontCascade().primaryFont();
    const auto* mathData = style().fontCascade().primaryFont().mathData();
    bool display = mathMLStyle()->displayStyle();
    if (mathData) {
        parameters.numeratorGapMin = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::FractionNumDisplayStyleGapMin : OpenTypeMathData::FractionNumeratorGapMin);
        parameters.denominatorGapMin = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::FractionDenomDisplayStyleGapMin : OpenTypeMathData::FractionDenominatorGapMin);
        parameters.numeratorMinShiftUp = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::FractionNumeratorDisplayStyleShiftUp : OpenTypeMathData::FractionNumeratorShiftUp);
        parameters.denominatorMinShiftDown = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::FractionDenominatorDisplayStyleShiftDown : OpenTypeMathData::FractionDenominatorShiftDown);
    } else {
        // The MATH table specification suggests default rule thickness or (in displaystyle) 3 times default rule thickness for the gaps.
        parameters.numeratorGapMin = display ? 3 * ruleThicknessFallback() : ruleThicknessFallback();
        parameters.denominatorGapMin = parameters.numeratorGapMin;

        // The MATH table specification does not suggest any values for shifts, so we leave them at zero.
        parameters.numeratorMinShiftUp = 0;
        parameters.denominatorMinShiftDown = 0;
    }

    return parameters;
}
void RenderMathMLFraction::getStackParameters(LayoutUnit& gapMin, LayoutUnit& topShiftUp, LayoutUnit& bottomShiftDown)
{
    ASSERT(isStack());

    // We try and read constants to draw the stack from the OpenType MATH and use fallback values otherwise.
    const auto& primaryFont = style().fontCascade().primaryFont();
    const auto* mathData = style().fontCascade().primaryFont().mathData();
    bool display = mathMLStyle()->displayStyle();
    if (mathData) {
        gapMin = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::StackDisplayStyleGapMin : OpenTypeMathData::StackGapMin);
        topShiftUp = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::StackTopDisplayStyleShiftUp : OpenTypeMathData::StackTopShiftUp);
        bottomShiftDown = mathData->getMathConstant(primaryFont, display ? OpenTypeMathData::StackBottomDisplayStyleShiftDown : OpenTypeMathData::StackBottomShiftDown);
    } else {
        // We use the values suggested in the MATH table specification.
        gapMin = display ? 7 * ruleThicknessFallback() : 3 * ruleThicknessFallback();

        // The MATH table specification does not suggest any values for shifts, so we leave them at zero.
        topShiftUp = 0;
        bottomShiftDown = 0;
    }
}
void RenderMathMLFraction::updateLineThickness()
{
    // We first determine the default line thickness.
    const auto& primaryFont = style().fontCascade().primaryFont();
    const auto* mathData = style().fontCascade().primaryFont().mathData();
    if (mathData)
        m_defaultLineThickness = mathData->getMathConstant(primaryFont, OpenTypeMathData::FractionRuleThickness);
    else
        m_defaultLineThickness = ruleThicknessFallback();

    // Next we resolve the thickness using m_defaultLineThickness as the default value.
    m_lineThickness = toUserUnits(element().lineThickness(), style(), m_defaultLineThickness);
    if (m_lineThickness < 0)
        m_lineThickness = 0;
}
void RenderMathMLRoot::updateStyle()
{
    // We try and read constants to draw the radical from the OpenType MATH and use fallback values otherwise.
    const auto& primaryFont = style().fontCascade().primaryFont();
    if (auto* mathData = style().fontCascade().primaryFont().mathData()) {
        m_ruleThickness = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalRuleThickness);
        m_verticalGap = mathData->getMathConstant(primaryFont, mathMLStyle()->displayStyle() ? OpenTypeMathData::RadicalDisplayStyleVerticalGap : OpenTypeMathData::RadicalVerticalGap);
        m_extraAscender = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalExtraAscender);

        if (m_kind == RootWithIndex) {
            m_kernBeforeDegree = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalKernBeforeDegree);
            m_kernAfterDegree = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalKernAfterDegree);
            m_degreeBottomRaisePercent = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalDegreeBottomRaisePercent);
        }
    } else {
        // RadicalVerticalGap: Suggested value is 5/4 default rule thickness.
        // RadicalDisplayStyleVerticalGap: Suggested value is default rule thickness + 1/4 x-height.
        // RadicalRuleThickness: Suggested value is default rule thickness.
        // RadicalExtraAscender: Suggested value is RadicalRuleThickness.
        // RadicalKernBeforeDegree: No suggested value provided. OT Math Illuminated mentions 5/18 em, Gecko uses 0.
        // RadicalKernAfterDegree: Suggested value is -10/18 of em.
        // RadicalDegreeBottomRaisePercent: Suggested value is 60%.
        m_ruleThickness = ruleThicknessFallback();
        if (mathMLStyle()->displayStyle())
            m_verticalGap = m_ruleThickness + style().fontMetrics().xHeight() / 4;
        else
            m_verticalGap = 5 * m_ruleThickness / 4;

        if (m_kind == RootWithIndex) {
            m_extraAscender = m_ruleThickness;
            m_kernBeforeDegree = 5 * style().fontCascade().size() / 18;
            m_kernAfterDegree = -10 * style().fontCascade().size() / 18;
            m_degreeBottomRaisePercent = 0.6f;
        }
    }
}