Example #1
0
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::layoutBlock(bool relayoutChildren, LayoutUnit)
{
    ASSERT(needsLayout());

    if (!relayoutChildren && simplifiedLayout())
        return;

    if (!isValid()) {
        setLogicalWidth(0);
        setLogicalHeight(0);
        clearNeedsLayout();
        return;
    }

    numerator().layoutIfNeeded();
    denominator().layoutIfNeeded();

    setLogicalWidth(std::max(numerator().logicalWidth(), denominator().logicalWidth()));

    updateLineThickness();
    LayoutUnit verticalOffset = 0; // This is the top of the renderer.
    LayoutPoint numeratorLocation(horizontalOffset(numerator(), element().numeratorAlignment()), verticalOffset);
    numerator().setLocation(numeratorLocation);

    LayoutUnit numeratorAscent = ascentForChild(numerator());
    LayoutUnit numeratorDescent = numerator().logicalHeight() - numeratorAscent;
    LayoutUnit denominatorAscent = ascentForChild(denominator());
    LayoutUnit denominatorDescent = denominator().logicalHeight() - denominatorAscent;
    if (isStack()) {
        LayoutUnit gapMin, topShiftUp, bottomShiftDown;
        getStackParameters(gapMin, topShiftUp, bottomShiftDown);
        LayoutUnit gap = topShiftUp - numeratorDescent + bottomShiftDown - denominatorAscent;
        if (gap < gapMin) {
            // If the gap is not large enough, we increase the shifts by the same value.
            LayoutUnit delta = (gapMin - gap) / 2;
            topShiftUp += delta;
            bottomShiftDown += delta;
        }
        verticalOffset += numeratorAscent + topShiftUp; // This is the middle of the stack gap.
        m_ascent = verticalOffset + mathAxisHeight();
        verticalOffset += bottomShiftDown - denominatorAscent;
    } else {
        LayoutUnit numeratorGapMin, denominatorGapMin, numeratorMinShiftUp, denominatorMinShiftDown;
        getFractionParameters(numeratorGapMin, denominatorGapMin, numeratorMinShiftUp, denominatorMinShiftDown);
        verticalOffset += std::max(numerator().logicalHeight() + numeratorGapMin + m_lineThickness / 2, numeratorAscent + numeratorMinShiftUp); // This is the middle of the fraction bar.
        m_ascent = verticalOffset + mathAxisHeight();
        verticalOffset += std::max(m_lineThickness / 2 + denominatorGapMin, denominatorMinShiftDown - denominatorAscent);
    }

    LayoutPoint denominatorLocation(horizontalOffset(denominator(), element().denominatorAlignment()), verticalOffset);
    denominator().setLocation(denominatorLocation);

    verticalOffset = std::max(verticalOffset + denominator().logicalHeight(), m_ascent + denominatorDescent); // This is the bottom of our renderer.
    setLogicalHeight(verticalOffset);

    clearNeedsLayout();
}
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::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
    RenderMathMLBlock::paint(info, paintOffset);
    if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !isValid() || isStack())
        return;

    IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + LayoutPoint(0, m_ascent - mathAxisHeight()));

    GraphicsContextStateSaver stateSaver(info.context());

    info.context().setStrokeThickness(m_lineThickness);
    info.context().setStrokeStyle(SolidStroke);
    info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor));
    info.context().drawLine(adjustedPaintOffset, roundedIntPoint(LayoutPoint(adjustedPaintOffset.x() + logicalWidth(), adjustedPaintOffset.y())));
}