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()))); }