Changeset 205441 in webkit


Ignore:
Timestamp:
Sep 5, 2016 2:19:48 AM (8 years ago)
Author:
fred.wang@free.fr
Message:

More refactoring of RenderMathMLScripts
https://bugs.webkit.org/show_bug.cgi?id=161371

Patch by Frederic Wang <fwang@igalia.com> on 2016-09-05
Reviewed by Darin Adler.

This is a follow-up of bug 161084. The function getScriptMetricsAndLayoutIfNeeded was quite
complicated and it was not obvious that we have to call it twice with the same reference
to a struture holding vertical metrics. We extract the part retrieving layout parameters
into verticalParameters and move its layoutIfNeeded calls into layoutBlock. Then it can
be reduced to a simple function that retrieve the vertical metrics in one call.
We also improve getBaseAndScripts to make clear that it is performing validation. It returns
a ReferenceChildren structure encapsulating pointers to important children so that we no
longer pass these pointers as function parameters. We continue to need them to browse the
list of prescripts & postscripts but we refactor a bit the loop to avoid explicit mention
of RenderBox*.

No new tests, already covered by existing tests.

  • rendering/mathml/RenderMathMLScripts.cpp:

(WebCore::RenderMathMLScripts::validateAndGetReferenceChildren): We now store the pointers to
the base, firstPostScript and firstPreScript children in the ReferenceChildren structure. We
also add a pointer to the prescriptDelimiter for convenience.
(WebCore::RenderMathMLScripts::italicCorrection): Use the ReferenceChildren structure so that
we are sure the base has been validated before calling this function.
(WebCore::RenderMathMLScripts::computePreferredLogicalWidths): Retrieve the reference
children with validateAndGetReferenceChildren instead of calling getBaseAndScripts and use
ReferenceChildren to handle these children and to call italicCorrection. The loops for
SubSup, UnderOver, Multiscripts are also rewritten a bit to avoid declaring a null RenderBox*
outside of them and hence allow to use auto.
(WebCore::RenderMathMLScripts::verticalParameters): This part to extract the layout
parameters is extracted from getScriptMetricsAndLayoutIfNeeded. The parameters are returned
as a VerticalParameters struct.
(WebCore::RenderMathMLScripts::verticalMetrics): This is the remaining part of
getScriptMetricsAndLayoutIfNeeded It used to call layoutIfNeeded on children and to
calculate maximum vertical metrics. For Multiscripts it was called twice: We did a first
call to handle the prescripts and then pass the result again in the second call to handle
the postscripts. We modify a bit the loop so that all the scripts are handled in one call and
hence we can directly return a VerticalMetrics. Again, the reference children are now handled
using the ReferenceChildren structure passed as a parameter.
(WebCore::RenderMathMLScripts::layoutBlock): We retrieve the reference children with
validateAndGetReferenceChildren instead of calling getBaseAndScripts and use
ReferenceChildren to handle these children and to call italicCorrection. We layout all the
children if needed in one loop at the beginning instead of doing that when their vertical
metrics are needed. We can now also retrieve vertical metrics with a single call.
(WebCore::RenderMathMLScripts::getBaseAndScripts): Renamed validateAndGetReferenceChildren.
(WebCore::RenderMathMLScripts::getScriptMetricsAndLayoutIfNeeded): Deleted. Split into
verticalParameters and verticalMetrics.

  • rendering/mathml/RenderMathMLScripts.h: New structure to handle the pointers to reference

children. Update the signature of getBaseAndScripts to use this struture and give a clearer
name. Update the signature of italicCorrection to use this structure too. Add a new structure
VerticalParameters and declare the helper function to retrieve them. Rename ScriptMetrics
to VerticalMetrics and update the signature of the function needed to retrieve it.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r205430 r205441  
     12016-09-05  Frederic Wang  <fwang@igalia.com>
     2
     3        More refactoring of RenderMathMLScripts
     4        https://bugs.webkit.org/show_bug.cgi?id=161371
     5
     6        Reviewed by Darin Adler.
     7
     8        This is a follow-up of bug 161084. The function getScriptMetricsAndLayoutIfNeeded was quite
     9        complicated and it was not obvious that we have to call it twice with the same reference
     10        to a struture holding vertical metrics. We extract the part retrieving layout parameters
     11        into verticalParameters and move its layoutIfNeeded calls into layoutBlock. Then it can
     12        be reduced to a simple function that retrieve the vertical metrics in one call.
     13        We also improve getBaseAndScripts to make clear that it is performing validation. It returns
     14        a ReferenceChildren structure encapsulating pointers to important children so that we no
     15        longer pass these pointers as function parameters. We continue to need them to browse the
     16        list of prescripts & postscripts but we refactor a bit the loop to avoid explicit mention
     17        of RenderBox*.
     18
     19        No new tests, already covered by existing tests.
     20
     21        * rendering/mathml/RenderMathMLScripts.cpp:
     22        (WebCore::RenderMathMLScripts::validateAndGetReferenceChildren): We now store the pointers to
     23        the base, firstPostScript and firstPreScript children in the ReferenceChildren structure. We
     24        also add a pointer to the prescriptDelimiter for convenience.
     25        (WebCore::RenderMathMLScripts::italicCorrection): Use the ReferenceChildren structure so that
     26        we are sure the base has been validated before calling this function.
     27        (WebCore::RenderMathMLScripts::computePreferredLogicalWidths): Retrieve the reference
     28        children with validateAndGetReferenceChildren instead of calling getBaseAndScripts and use
     29        ReferenceChildren to handle these children and to call italicCorrection. The loops for
     30        SubSup, UnderOver, Multiscripts are also rewritten a bit to avoid declaring a null RenderBox*
     31        outside of them and hence allow to use auto.
     32        (WebCore::RenderMathMLScripts::verticalParameters): This part to extract the layout
     33        parameters is extracted from getScriptMetricsAndLayoutIfNeeded. The parameters are returned
     34        as a VerticalParameters struct.
     35        (WebCore::RenderMathMLScripts::verticalMetrics): This is the remaining part of
     36        getScriptMetricsAndLayoutIfNeeded It used to call layoutIfNeeded on children and to
     37        calculate maximum vertical metrics. For Multiscripts it was called twice: We did a first
     38        call to handle the prescripts and then pass the result again in the second call to handle
     39        the postscripts. We modify a bit the loop so that all the scripts are handled in one call and
     40        hence we can directly return a VerticalMetrics. Again, the reference children are now handled
     41        using the ReferenceChildren structure passed as a parameter.
     42        (WebCore::RenderMathMLScripts::layoutBlock): We retrieve the reference children with
     43        validateAndGetReferenceChildren instead of calling getBaseAndScripts and use
     44        ReferenceChildren to handle these children and to call italicCorrection. We layout all the
     45        children if needed in one loop at the beginning instead of doing that when their vertical
     46        metrics are needed. We can now also retrieve vertical metrics with a single call.
     47        (WebCore::RenderMathMLScripts::getBaseAndScripts): Renamed validateAndGetReferenceChildren.
     48        (WebCore::RenderMathMLScripts::getScriptMetricsAndLayoutIfNeeded): Deleted. Split into
     49        verticalParameters and verticalMetrics.
     50        * rendering/mathml/RenderMathMLScripts.h: New structure to handle the pointers to reference
     51        children. Update the signature of getBaseAndScripts to use this struture and give a clearer
     52        name. Update the signature of italicCorrection to use this structure too. Add a new structure
     53        VerticalParameters and declare the helper function to retrieve them. Rename ScriptMetrics
     54        to VerticalMetrics and update the signature of the function needed to retrieve it.
     55
    1562016-09-05  Zan Dobersek  <zdobersek@igalia.com>
    257
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLScripts.cpp

    r205105 r205441  
    7777}
    7878
    79 bool RenderMathMLScripts::getBaseAndScripts(RenderBox*& base, RenderBox*& firstPostScript, RenderBox*& firstPreScript)
     79Optional<RenderMathMLScripts::ReferenceChildren> RenderMathMLScripts::validateAndGetReferenceChildren()
    8080{
    8181    // All scripted elements must have at least one child.
    8282    // The first child is the base.
    83     base = firstChildBox();
    84     firstPostScript = nullptr;
    85     firstPreScript = nullptr;
     83    auto base = firstChildBox();
    8684    if (!base)
    87         return false;
     85        return Nullopt;
     86
     87    ReferenceChildren reference;
     88    reference.base = base;
     89    reference.firstPostScript = nullptr;
     90    reference.firstPreScript = nullptr;
     91    reference.prescriptDelimiter = nullptr;
    8892
    8993    switch (m_scriptType) {
     
    9195    case Super:
    9296    case Under:
    93     case Over:
     97    case Over: {
    9498        // These elements must have exactly two children.
    9599        // The second child is a postscript and there are no prescripts.
     
    98102        // <munder> base underscript </munder>
    99103        // <mover> base overscript </mover>
    100         firstPostScript = base->nextSiblingBox();
    101         return firstPostScript && !isPrescriptDelimiter(*firstPostScript) && !firstPostScript->nextSiblingBox();
     104        auto script = base->nextSiblingBox();
     105        if (!script || isPrescriptDelimiter(*script) || script->nextSiblingBox())
     106            return Nullopt;
     107        reference.firstPostScript = script;
     108        return reference;
     109    }
    102110    case SubSup:
    103111    case UnderOver: {
     
    106114        // <msubsup> base subscript superscript </msubsup>
    107115        // <munderover> base subscript superscript </munderover>
    108         firstPostScript = base->nextSiblingBox();
    109         if (!firstPostScript || isPrescriptDelimiter(*firstPostScript))
    110             return false;
    111         auto superScript = firstPostScript->nextSiblingBox();
    112         return superScript && !isPrescriptDelimiter(*superScript) && !superScript->nextSiblingBox();
     116        auto subScript = base->nextSiblingBox();
     117        if (!subScript || isPrescriptDelimiter(*subScript))
     118            return Nullopt;
     119        auto superScript = subScript->nextSiblingBox();
     120        if (!superScript || isPrescriptDelimiter(*superScript) || superScript->nextSiblingBox())
     121            return Nullopt;
     122        reference.firstPostScript = subScript;
     123        return reference;
    113124    }
    114125    case Multiscripts: {
     
    125136        // We set the first postscript, unless (subscript superscript)* is empty.
    126137        if (base->nextSiblingBox() && !isPrescriptDelimiter(*base->nextSiblingBox()))
    127             firstPostScript = base->nextSiblingBox();
     138            reference.firstPostScript = base->nextSiblingBox();
    128139
    129140        // We browse the children in order to
     
    137148            if (isPrescriptDelimiter(*script)) {
    138149                // This is a <mprescripts/>. Let's check 2a) and 2c).
    139                 if (!numberOfScriptIsEven || firstPreScript)
    140                     return false;
    141                 firstPreScript = script->nextSiblingBox(); // We do 1).
     150                if (!numberOfScriptIsEven || reference.firstPreScript)
     151                    return Nullopt;
     152                reference.firstPreScript = script->nextSiblingBox(); // We do 1).
     153                reference.prescriptDelimiter = script;
    142154                continue;
    143155            }
    144156            numberOfScriptIsEven = !numberOfScriptIsEven;
    145157        }
    146         return numberOfScriptIsEven; // We verify 2b).
     158        return numberOfScriptIsEven ? Optional<ReferenceChildren>(reference) : Nullopt; // We verify 2b).
    147159    }
    148160    }
    149161
    150162    ASSERT_NOT_REACHED();
    151     return false;
     163    return Nullopt;
    152164}
    153165
     
    160172}
    161173
    162 LayoutUnit RenderMathMLScripts::italicCorrection(RenderBox* base)
    163 {
    164     if (is<RenderMathMLBlock>(*base)) {
    165         if (auto* renderOperator = downcast<RenderMathMLBlock>(*base).unembellishedOperator())
     174LayoutUnit RenderMathMLScripts::italicCorrection(const ReferenceChildren& reference)
     175{
     176    if (is<RenderMathMLBlock>(*reference.base)) {
     177        if (auto* renderOperator = downcast<RenderMathMLBlock>(*reference.base).unembellishedOperator())
    166178            return renderOperator->italicCorrection();
    167179    }
     
    174186    m_maxPreferredLogicalWidth = 0;
    175187
    176     RenderBox* base;
    177     RenderBox* firstPostScript;
    178     RenderBox* firstPreScript;
    179     if (!getBaseAndScripts(base, firstPostScript, firstPreScript))
     188    auto possibleReference = validateAndGetReferenceChildren();
     189    if (!possibleReference)
    180190        return;
    181 
    182     LayoutUnit baseItalicCorrection = std::min(base->maxPreferredLogicalWidth(), italicCorrection(base));
     191    auto& reference = possibleReference.value();
     192
     193    LayoutUnit baseItalicCorrection = std::min(reference.base->maxPreferredLogicalWidth(), italicCorrection(reference));
    183194    LayoutUnit space = spaceAfterScript();
    184195
     
    186197    case Sub:
    187198    case Under:
    188         m_maxPreferredLogicalWidth += base->maxPreferredLogicalWidth();
    189         m_maxPreferredLogicalWidth += std::max(LayoutUnit(0), firstPostScript->maxPreferredLogicalWidth() - baseItalicCorrection + space);
     199        m_maxPreferredLogicalWidth += reference.base->maxPreferredLogicalWidth();
     200        m_maxPreferredLogicalWidth += std::max(LayoutUnit(0), reference.firstPostScript->maxPreferredLogicalWidth() - baseItalicCorrection + space);
    190201        break;
    191202    case Super:
    192203    case Over:
    193         m_maxPreferredLogicalWidth += base->maxPreferredLogicalWidth();
    194         m_maxPreferredLogicalWidth += std::max(LayoutUnit(0), firstPostScript->maxPreferredLogicalWidth() + space);
     204        m_maxPreferredLogicalWidth += reference.base->maxPreferredLogicalWidth();
     205        m_maxPreferredLogicalWidth += std::max(LayoutUnit(0), reference.firstPostScript->maxPreferredLogicalWidth() + space);
    195206        break;
    196207    case SubSup:
    197208    case UnderOver:
    198209    case Multiscripts: {
    199         RenderBox* supScript;
    200         for (auto* subScript = firstPreScript; subScript; subScript = supScript->nextSiblingBox()) {
    201             supScript = subScript->nextSiblingBox();
     210        auto subScript = reference.firstPreScript;
     211        while (subScript) {
     212            auto supScript = subScript->nextSiblingBox();
    202213            ASSERT(supScript);
    203214            LayoutUnit subSupPairWidth = std::max(subScript->maxPreferredLogicalWidth(), supScript->maxPreferredLogicalWidth());
    204215            m_maxPreferredLogicalWidth += subSupPairWidth + space;
    205         }
    206         m_maxPreferredLogicalWidth += base->maxPreferredLogicalWidth();
    207         for (auto* subScript = firstPostScript; subScript && !isPrescriptDelimiter(*subScript); subScript = supScript->nextSiblingBox()) {
    208             supScript = subScript->nextSiblingBox();
     216            subScript = supScript->nextSiblingBox();
     217        }
     218        m_maxPreferredLogicalWidth += reference.base->maxPreferredLogicalWidth();
     219        subScript = reference.firstPostScript;
     220        while (subScript && subScript != reference.prescriptDelimiter) {
     221            auto supScript = subScript->nextSiblingBox();
    209222            ASSERT(supScript);
    210223            LayoutUnit subSupPairWidth = std::max(std::max(LayoutUnit(0), subScript->maxPreferredLogicalWidth() - baseItalicCorrection), supScript->maxPreferredLogicalWidth());
    211224            m_maxPreferredLogicalWidth += subSupPairWidth + space;
     225            subScript = supScript->nextSiblingBox();
    212226        }
    213227    }
     
    217231}
    218232
    219 void RenderMathMLScripts::getScriptMetricsAndLayoutIfNeeded(RenderBox* base, RenderBox* script, ScriptMetrics& metrics)
    220 {
    221     LayoutUnit baseAscent = ascentForChild(*base);
    222     LayoutUnit baseDescent = base->logicalHeight() - baseAscent;
    223     LayoutUnit subscriptShiftDown;
    224     LayoutUnit superscriptShiftUp;
    225     LayoutUnit subscriptBaselineDropMin;
    226     LayoutUnit superScriptBaselineDropMax;
    227     LayoutUnit subSuperscriptGapMin;
    228     LayoutUnit superscriptBottomMin;
    229     LayoutUnit subscriptTopMax;
    230     LayoutUnit superscriptBottomMaxWithSubscript;
    231 
     233auto RenderMathMLScripts::verticalParameters() const -> VerticalParameters
     234{
     235    VerticalParameters parameters;
    232236    const auto& primaryFont = style().fontCascade().primaryFont();
    233237    if (auto* mathData = primaryFont.mathData()) {
    234         subscriptShiftDown = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubscriptShiftDown);
    235         superscriptShiftUp = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptShiftUp);
    236         subscriptBaselineDropMin = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubscriptBaselineDropMin);
    237         superScriptBaselineDropMax = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptBaselineDropMax);
    238         subSuperscriptGapMin = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubSuperscriptGapMin);
    239         superscriptBottomMin = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptBottomMin);
    240         subscriptTopMax = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubscriptTopMax);
    241         superscriptBottomMaxWithSubscript = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptBottomMaxWithSubscript);
     238        parameters.subscriptShiftDown = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubscriptShiftDown);
     239        parameters.superscriptShiftUp = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptShiftUp);
     240        parameters.subscriptBaselineDropMin = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubscriptBaselineDropMin);
     241        parameters.superScriptBaselineDropMax = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptBaselineDropMax);
     242        parameters.subSuperscriptGapMin = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubSuperscriptGapMin);
     243        parameters.superscriptBottomMin = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptBottomMin);
     244        parameters.subscriptTopMax = mathData->getMathConstant(primaryFont, OpenTypeMathData::SubscriptTopMax);
     245        parameters.superscriptBottomMaxWithSubscript = mathData->getMathConstant(primaryFont, OpenTypeMathData::SuperscriptBottomMaxWithSubscript);
    242246    } else {
    243247        // Default heuristic values when you do not have a font.
    244         subscriptShiftDown = style().fontMetrics().xHeight() / 3;
    245         superscriptShiftUp = style().fontMetrics().xHeight();
    246         subscriptBaselineDropMin = style().fontMetrics().xHeight() / 2;
    247         superScriptBaselineDropMax = style().fontMetrics().xHeight() / 2;
    248         subSuperscriptGapMin = style().fontCascade().size() / 5;
    249         superscriptBottomMin = style().fontMetrics().xHeight() / 4;
    250         subscriptTopMax = 4 * style().fontMetrics().xHeight() / 5;
    251         superscriptBottomMaxWithSubscript = 4 * style().fontMetrics().xHeight() / 5;
    252     }
    253 
     248        parameters.subscriptShiftDown = style().fontMetrics().xHeight() / 3;
     249        parameters.superscriptShiftUp = style().fontMetrics().xHeight();
     250        parameters.subscriptBaselineDropMin = style().fontMetrics().xHeight() / 2;
     251        parameters.superScriptBaselineDropMax = style().fontMetrics().xHeight() / 2;
     252        parameters.subSuperscriptGapMin = style().fontCascade().size() / 5;
     253        parameters.superscriptBottomMin = style().fontMetrics().xHeight() / 4;
     254        parameters.subscriptTopMax = 4 * style().fontMetrics().xHeight() / 5;
     255        parameters.superscriptBottomMaxWithSubscript = 4 * style().fontMetrics().xHeight() / 5;
     256    }
     257    return parameters;
     258}
     259
     260RenderMathMLScripts::VerticalMetrics RenderMathMLScripts::verticalMetrics(const ReferenceChildren& reference)
     261{
     262    VerticalParameters parameters = verticalParameters();
     263    VerticalMetrics metrics = { 0, 0, 0, 0 };
     264
     265    LayoutUnit baseAscent = ascentForChild(*reference.base);
     266    LayoutUnit baseDescent = reference.base->logicalHeight() - baseAscent;
    254267    if (m_scriptType == Sub || m_scriptType == SubSup || m_scriptType == Multiscripts || m_scriptType == Under || m_scriptType == UnderOver) {
    255         metrics.subShift = std::max(subscriptShiftDown, baseDescent + subscriptBaselineDropMin);
     268        metrics.subShift = std::max(parameters.subscriptShiftDown, baseDescent + parameters.subscriptBaselineDropMin);
    256269        if (!isRenderMathMLUnderOver()) {
    257270            // It is not clear how to interpret the default shift and it is not available yet anyway.
     
    262275    }
    263276    if (m_scriptType == Super || m_scriptType == SubSup || m_scriptType == Multiscripts  || m_scriptType == Over || m_scriptType == UnderOver) {
    264         metrics.supShift = std::max(superscriptShiftUp, baseAscent - superScriptBaselineDropMax);
     277        metrics.supShift = std::max(parameters.superscriptShiftUp, baseAscent - parameters.superScriptBaselineDropMax);
    265278        if (!isRenderMathMLUnderOver()) {
    266279            // It is not clear how to interpret the default shift and it is not available yet anyway.
     
    274287    case Sub:
    275288    case Under: {
    276         script->layoutIfNeeded();
    277         LayoutUnit subAscent = ascentForChild(*script);
    278         LayoutUnit subDescent = script->logicalHeight() - subAscent;
     289        LayoutUnit subAscent = ascentForChild(*reference.firstPostScript);
     290        LayoutUnit subDescent = reference.firstPostScript->logicalHeight() - subAscent;
    279291        metrics.descent = subDescent;
    280         metrics.subShift = std::max(metrics.subShift, subAscent - subscriptTopMax);
     292        metrics.subShift = std::max(metrics.subShift, subAscent - parameters.subscriptTopMax);
    281293    }
    282294        break;
    283295    case Super:
    284296    case Over: {
    285         script->layoutIfNeeded();
    286         LayoutUnit supAscent = ascentForChild(*script);
    287         LayoutUnit supDescent = script->logicalHeight() - supAscent;
     297        LayoutUnit supAscent = ascentForChild(*reference.firstPostScript);
     298        LayoutUnit supDescent = reference.firstPostScript->logicalHeight() - supAscent;
    288299        metrics.ascent = supAscent;
    289         metrics.supShift = std::max(metrics.supShift, superscriptBottomMin + supDescent);
     300        metrics.supShift = std::max(metrics.supShift, parameters.superscriptBottomMin + supDescent);
    290301    }
    291302        break;
     
    293304    case UnderOver:
    294305    case Multiscripts: {
    295         RenderBox* supScript;
    296         for (auto* subScript = script; subScript && !isPrescriptDelimiter(*subScript); subScript = supScript->nextSiblingBox()) {
    297             supScript = subScript->nextSiblingBox();
    298             ASSERT(supScript);
    299             subScript->layoutIfNeeded();
    300             supScript->layoutIfNeeded();
     306        // FIXME: We should move the code updating VerticalMetrics for each sub/sup pair in a helper
     307        // function. That way, SubSup/UnderOver can just make one call and the loop for Multiscripts
     308        // can be rewritten in a more readable.
     309        auto subScript = reference.firstPostScript ? reference.firstPostScript : reference.firstPreScript;
     310        while (subScript) {
     311            auto supScript = subScript->nextSiblingBox();
     312            ASSERT(supScript);
    301313            LayoutUnit subAscent = ascentForChild(*subScript);
    302314            LayoutUnit subDescent = subScript->logicalHeight() - subAscent;
     
    305317            metrics.ascent = std::max(metrics.ascent, supAscent);
    306318            metrics.descent = std::max(metrics.descent, subDescent);
    307             LayoutUnit subScriptShift = std::max(subscriptShiftDown, baseDescent + subscriptBaselineDropMin);
    308             subScriptShift = std::max(subScriptShift, subAscent - subscriptTopMax);
    309             LayoutUnit supScriptShift = std::max(superscriptShiftUp, baseAscent - superScriptBaselineDropMax);
    310             supScriptShift = std::max(supScriptShift, superscriptBottomMin + supDescent);
     319            LayoutUnit subScriptShift = std::max(parameters.subscriptShiftDown, baseDescent + parameters.subscriptBaselineDropMin);
     320            subScriptShift = std::max(subScriptShift, subAscent - parameters.subscriptTopMax);
     321            LayoutUnit supScriptShift = std::max(parameters.superscriptShiftUp, baseAscent - parameters.superScriptBaselineDropMax);
     322            supScriptShift = std::max(supScriptShift, parameters.superscriptBottomMin + supDescent);
    311323
    312324            LayoutUnit subSuperscriptGap = (subScriptShift - subAscent) + (supScriptShift - supDescent);
    313             if (subSuperscriptGap < subSuperscriptGapMin) {
     325            if (subSuperscriptGap < parameters.subSuperscriptGapMin) {
    314326                // First, we try and push the superscript up.
    315                 LayoutUnit delta = superscriptBottomMaxWithSubscript - (supScriptShift - supDescent);
     327                LayoutUnit delta = parameters.superscriptBottomMaxWithSubscript - (supScriptShift - supDescent);
    316328                if (delta > 0) {
    317                     delta = std::min(delta, subSuperscriptGapMin - subSuperscriptGap);
     329                    delta = std::min(delta, parameters.subSuperscriptGapMin - subSuperscriptGap);
    318330                    supScriptShift += delta;
    319331                    subSuperscriptGap += delta;
    320332                }
    321333                // If that is not enough, we push the subscript down.
    322                 if (subSuperscriptGap < subSuperscriptGapMin)
    323                     subScriptShift += subSuperscriptGapMin - subSuperscriptGap;
     334                if (subSuperscriptGap < parameters.subSuperscriptGapMin)
     335                    subScriptShift += parameters.subSuperscriptGapMin - subSuperscriptGap;
    324336            }
    325337
    326338            metrics.subShift = std::max(metrics.subShift, subScriptShift);
    327339            metrics.supShift = std::max(metrics.supShift, supScriptShift);
    328         }
    329     }
    330     }
     340
     341            subScript = supScript->nextSiblingBox();
     342            if (subScript == reference.prescriptDelimiter)
     343                subScript = reference.firstPreScript;
     344        }
     345    }
     346    }
     347
     348    return metrics;
    331349}
    332350
     
    338356        return;
    339357
    340     RenderBox* base;
    341     RenderBox* firstPostScript;
    342     RenderBox* firstPreScript;
    343     if (!getBaseAndScripts(base, firstPostScript, firstPreScript)) {
     358    auto possibleReference = validateAndGetReferenceChildren();
     359    if (!possibleReference) {
    344360        setLogicalWidth(0);
    345361        setLogicalHeight(0);
     
    347363        return;
    348364    }
     365    auto& reference = possibleReference.value();
     366
    349367    recomputeLogicalWidth();
    350     base->layoutIfNeeded();
     368    for (auto child = firstChildBox(); child; child = child->nextSiblingBox())
     369        child->layoutIfNeeded();
    351370
    352371    LayoutUnit space = spaceAfterScript();
    353372
    354373    // We determine the minimal shift/size of each script and take the maximum of the values.
    355     ScriptMetrics metrics;
    356     metrics.subShift = 0;
    357     metrics.supShift = 0;
    358     metrics.descent = 0;
    359     metrics.ascent = 0;
    360     if (m_scriptType == Multiscripts)
    361         getScriptMetricsAndLayoutIfNeeded(base, firstPreScript, metrics);
    362     getScriptMetricsAndLayoutIfNeeded(base, firstPostScript, metrics);
    363 
    364     LayoutUnit baseAscent = ascentForChild(*base);
    365     LayoutUnit baseDescent = base->logicalHeight() - baseAscent;
    366     LayoutUnit baseItalicCorrection = std::min(base->logicalWidth(), italicCorrection(base));
     374    VerticalMetrics metrics = verticalMetrics(reference);
     375
     376    LayoutUnit baseAscent = ascentForChild(*reference.base);
     377    LayoutUnit baseDescent = reference.base->logicalHeight() - baseAscent;
     378    LayoutUnit baseItalicCorrection = std::min(reference.base->logicalWidth(), italicCorrection(reference));
    367379    LayoutUnit horizontalOffset = 0;
    368380
     
    374386    case Sub:
    375387    case Under: {
    376         setLogicalWidth(base->logicalWidth() + std::max(LayoutUnit(0), firstPostScript->logicalWidth() - baseItalicCorrection + space));
    377         LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, *base), ascent - baseAscent);
    378         base->setLocation(baseLocation);
    379         horizontalOffset += base->logicalWidth();
    380         LayoutUnit scriptAscent = ascentForChild(*firstPostScript);
    381         LayoutPoint scriptLocation(mirrorIfNeeded(horizontalOffset - baseItalicCorrection, *firstPostScript), ascent + metrics.subShift - scriptAscent);
    382         firstPostScript->setLocation(scriptLocation);
     388        setLogicalWidth(reference.base->logicalWidth() + std::max(LayoutUnit(0), reference.firstPostScript->logicalWidth() - baseItalicCorrection + space));
     389        LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, *reference.base), ascent - baseAscent);
     390        reference.base->setLocation(baseLocation);
     391        horizontalOffset += reference.base->logicalWidth();
     392        LayoutUnit scriptAscent = ascentForChild(*reference.firstPostScript);
     393        LayoutPoint scriptLocation(mirrorIfNeeded(horizontalOffset - baseItalicCorrection, *reference.firstPostScript), ascent + metrics.subShift - scriptAscent);
     394        reference.firstPostScript->setLocation(scriptLocation);
    383395    }
    384396        break;
    385397    case Super:
    386398    case Over: {
    387         setLogicalWidth(base->logicalWidth() + std::max(LayoutUnit(0), firstPostScript->logicalWidth() + space));
    388         LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, *base), ascent - baseAscent);
    389         base->setLocation(baseLocation);
    390         horizontalOffset += base->logicalWidth();
    391         LayoutUnit scriptAscent = ascentForChild(*firstPostScript);
    392         LayoutPoint scriptLocation(mirrorIfNeeded(horizontalOffset, *firstPostScript), ascent - metrics.supShift - scriptAscent);
    393         firstPostScript->setLocation(scriptLocation);
     399        setLogicalWidth(reference.base->logicalWidth() + std::max(LayoutUnit(0), reference.firstPostScript->logicalWidth() + space));
     400        LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, *reference.base), ascent - baseAscent);
     401        reference.base->setLocation(baseLocation);
     402        horizontalOffset += reference.base->logicalWidth();
     403        LayoutUnit scriptAscent = ascentForChild(*reference.firstPostScript);
     404        LayoutPoint scriptLocation(mirrorIfNeeded(horizontalOffset, *reference.firstPostScript), ascent - metrics.supShift - scriptAscent);
     405        reference.firstPostScript->setLocation(scriptLocation);
    394406    }
    395407        break;
     
    397409    case UnderOver:
    398410    case Multiscripts: {
    399         RenderBox* supScript;
    400 
    401411        // Calculate the logical width.
    402412        LayoutUnit logicalWidth = 0;
    403         for (auto* subScript = firstPreScript; subScript; subScript = supScript->nextSiblingBox()) {
    404             supScript = subScript->nextSiblingBox();
     413        auto subScript = reference.firstPreScript;
     414        while (subScript) {
     415            auto supScript = subScript->nextSiblingBox();
    405416            ASSERT(supScript);
    406417            LayoutUnit subSupPairWidth = std::max(subScript->logicalWidth(), supScript->logicalWidth());
    407418            logicalWidth += subSupPairWidth + space;
    408         }
    409         logicalWidth += base->logicalWidth();
    410         for (auto* subScript = firstPostScript; subScript && !isPrescriptDelimiter(*subScript); subScript = supScript->nextSiblingBox()) {
    411             supScript = subScript->nextSiblingBox();
     419            subScript = supScript->nextSiblingBox();
     420        }
     421        logicalWidth += reference.base->logicalWidth();
     422        subScript = reference.firstPostScript;
     423        while (subScript && subScript != reference.prescriptDelimiter) {
     424            auto supScript = subScript->nextSiblingBox();
    412425            ASSERT(supScript);
    413426            LayoutUnit subSupPairWidth = std::max(std::max(LayoutUnit(0), subScript->logicalWidth() - baseItalicCorrection), supScript->logicalWidth());
    414427            logicalWidth += subSupPairWidth + space;
     428            subScript = supScript->nextSiblingBox();
    415429        }
    416430        setLogicalWidth(logicalWidth);
    417431
    418         for (auto* subScript = firstPreScript; subScript; subScript = supScript->nextSiblingBox()) {
    419             supScript = subScript->nextSiblingBox();
     432        subScript = reference.firstPreScript;
     433        while (subScript) {
     434            auto supScript = subScript->nextSiblingBox();
    420435            ASSERT(supScript);
    421436            LayoutUnit subSupPairWidth = std::max(subScript->logicalWidth(), supScript->logicalWidth());
     
    427442            LayoutPoint supScriptLocation(mirrorIfNeeded(horizontalOffset - supScript->logicalWidth(), *supScript), ascent - metrics.supShift - supAscent);
    428443            supScript->setLocation(supScriptLocation);
    429         }
    430         LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, *base), ascent - baseAscent);
    431         base->setLocation(baseLocation);
    432         horizontalOffset += base->logicalWidth();
    433         for (auto* subScript = firstPostScript; subScript && !isPrescriptDelimiter(*subScript); subScript = supScript->nextSiblingBox()) {
    434             supScript = subScript->nextSiblingBox();
     444            subScript = supScript->nextSiblingBox();
     445        }
     446        LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, *reference.base), ascent - baseAscent);
     447        reference.base->setLocation(baseLocation);
     448        horizontalOffset += reference.base->logicalWidth();
     449        subScript = reference.firstPostScript;
     450        while (subScript && subScript != reference.prescriptDelimiter) {
     451            auto supScript = subScript->nextSiblingBox();
    435452            ASSERT(supScript);
    436453            LayoutUnit subAscent = ascentForChild(*subScript);
     
    443460            LayoutUnit subSupPairWidth = std::max(subScript->logicalWidth(), supScript->logicalWidth());
    444461            horizontalOffset += subSupPairWidth + space;
     462            subScript = supScript->nextSiblingBox();
    445463        }
    446464    }
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLScripts.h

    r205105 r205441  
    5454    MathMLScriptsElement& element() const;
    5555    Optional<int> firstLineBaseline() const final;
    56     bool getBaseAndScripts(RenderBox*& base, RenderBox*& firstPostScript, RenderBox*& firstPreScript);
     56    struct ReferenceChildren {
     57        RenderBox* base;
     58        RenderBox* prescriptDelimiter;
     59        RenderBox* firstPostScript;
     60        RenderBox* firstPreScript;
     61    };
     62    Optional<ReferenceChildren> validateAndGetReferenceChildren();
    5763    LayoutUnit spaceAfterScript();
    58     LayoutUnit italicCorrection(RenderBox* base);
    59     struct ScriptMetrics {
     64    LayoutUnit italicCorrection(const ReferenceChildren&);
     65    struct VerticalParameters {
     66        LayoutUnit subscriptShiftDown;
     67        LayoutUnit superscriptShiftUp;
     68        LayoutUnit subscriptBaselineDropMin;
     69        LayoutUnit superScriptBaselineDropMax;
     70        LayoutUnit subSuperscriptGapMin;
     71        LayoutUnit superscriptBottomMin;
     72        LayoutUnit subscriptTopMax;
     73        LayoutUnit superscriptBottomMaxWithSubscript;
     74    };
     75    VerticalParameters verticalParameters() const;
     76    struct VerticalMetrics {
    6077        LayoutUnit subShift;
    6178        LayoutUnit supShift;
     
    6380        LayoutUnit descent;
    6481    };
    65     void getScriptMetricsAndLayoutIfNeeded(RenderBox* base, RenderBox* script, ScriptMetrics&);
     82    VerticalMetrics verticalMetrics(const ReferenceChildren&);
    6683};
    6784
Note: See TracChangeset for help on using the changeset viewer.