Changeset 169607 in webkit


Ignore:
Timestamp:
Jun 4, 2014 11:35:04 PM (10 years ago)
Author:
fred.wang@free.fr
Message:

MathML operators not stretched horizontally
https://bugs.webkit.org/show_bug.cgi?id=72828

Reviewed by Chris Fleizach.

Source/WebCore:
This patch adds basic horizontal stretching rules for operators inside
an <munder>, <mover> or <munderover> elements. The stretchy operators
in such an element stretch to cover the size of the non-stretchy
operators. This only works when fonts that have an OpenType MATH table
are used.

Tests: mathml/opentype/horizontal-LatinModern.html

mathml/opentype/opentype-stretchy-horizontal.html
mathml/opentype/horizontal-LatinModern-munderover.html

  • rendering/mathml/RenderMathMLOperator.cpp:

(WebCore::MathMLOperatorDictionary::ExtractKeyHorizontal): We add an ordered list of operators that have horizontal stretch direction.
(WebCore::RenderMathMLOperator::RenderMathMLOperator): init m_Vertical
(WebCore::RenderMathMLOperator::SetOperatorProperties): set m_Vertical by checking whether the operator is in the horizontalOperators list.
(WebCore::RenderMathMLOperator::stretchTo): We do not stretch vertically
if the operator has horizontal direction.
We also add a new version stretchTo(LayoutUnit width) for horizontal stretching only.
(WebCore::RenderMathMLOperator::computePreferredLogicalWidths): Handle horizontal stretching: the maximumGlyphWidth is the maximum of
the base size or of the stretch size.
(WebCore::RenderMathMLOperator::getDisplayStyleLargeOperator): Add an ASSERT to ensure that this function is only called for vertical stretching.
(WebCore::RenderMathMLOperator::findStretchyData): Add an ASSERT to ensure that this function is not called to get the maximum width of a horizontal stretchy operator.
We take into account m_isVertical when calling getMathVariants or computing sizes.
There is not any Unicode-only construction for horizontal stretching, so a MATH table is required for horizontal stretching.
(WebCore::RenderMathMLOperator::updateStyle): Ignore some code paths specific to vertical stretching and take into account the m_Vertical parameters.
For horizontal stretching, the m_stretch*Baseline parameters are now updated to match the metrics of the size variant or of the maximum of the parts in the glyph assembly.
(WebCore::RenderMathMLOperator::computeLogicalHeight): logicalHeight is now explicitely the sum of m_stretchHeightAboveBaseline and m_stretchDepthBelowBaseline, since it can be different from the stretchSize() in horizontal stretching.
(WebCore::RenderMathMLOperator::paintGlyph): handle trimming for horizontal stretching.
(WebCore::RenderMathMLOperator::fillWithVerticalExtensionGlyph): rename the function and ensure it is only call for m_isVertical.
(WebCore::RenderMathMLOperator::fillWithHorizontalExtensionGlyph): same as fillWithVerticalExtensionGlyph, but for horizontal stretching.
(WebCore::RenderMathMLOperator::paint): For glyph assembly, choose between paintVerticalGlyphAssembly or paintHorizontalGlyphAssembly.
(WebCore::RenderMathMLOperator::paintVerticalGlyphAssembly): rename the function and ensure it is only call for m_isVertical.
(WebCore::RenderMathMLOperator::paintHorizontalGlyphAssembly): same as paintVerticalGlyphAssembly but for horizontal stretching.

  • rendering/mathml/RenderMathMLOperator.h: we add a m_isVertical member to indicate the stretch direction and a m_stretchWidth to indicate the width of the stretchy character.

We define the horizontal counterparts of fillWith*ExtensionGlyph, paint*GlyphAssembly, GlyphPaintTrimming StretchyData.
Finally stretchSize() takes into account the stretch direction.

  • rendering/mathml/RenderMathMLUnderOver.cpp: We override the layout() function to stretch munderover children horizontally.

(WebCore::RenderMathMLUnderOver::layout):

  • rendering/mathml/RenderMathMLUnderOver.h: we declare layout().

LayoutTests:
Add some tests to verify horizontal stretching with the MATH data.

  • mathml/opentype/horizontal-LatinModern-munderover.html: Added.
  • mathml/opentype/horizontal-LatinModern.html: Added.
  • mathml/opentype/opentype-stretchy-horizontal.html: Added.
  • platform/efl/TestExpectations: mark tests as failing.
  • platform/gtk/mathml/opentype/horizontal-LatinModern-expected.png: Added.
  • platform/gtk/mathml/opentype/horizontal-LatinModern-expected.txt: Added.
  • platform/gtk/mathml/opentype/horizontal-LatinModern-munderover-expected.png: Added.
  • platform/gtk/mathml/opentype/horizontal-LatinModern-munderover-expected.txt: Added.
  • platform/gtk/mathml/opentype/opentype-stretchy-horizontal-expected.png: Added.
  • platform/gtk/mathml/opentype/opentype-stretchy-horizontal-expected.txt: Added.
  • platform/mac/TestExpectations: mark tests as failing.
  • platform/win/TestExpectations: ditto.
Location:
trunk
Files:
9 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r169606 r169607  
     12014-06-05  Frédéric Wang  <fred.wang@free.fr>
     2
     3        MathML operators not stretched horizontally
     4        https://bugs.webkit.org/show_bug.cgi?id=72828
     5
     6        Reviewed by Chris Fleizach.
     7
     8        Add some tests to verify horizontal stretching with the MATH data.
     9
     10        * mathml/opentype/horizontal-LatinModern-munderover.html: Added.
     11        * mathml/opentype/horizontal-LatinModern.html: Added.
     12        * mathml/opentype/opentype-stretchy-horizontal.html: Added.
     13        * platform/efl/TestExpectations: mark tests as failing.
     14        * platform/gtk/mathml/opentype/horizontal-LatinModern-expected.png: Added.
     15        * platform/gtk/mathml/opentype/horizontal-LatinModern-expected.txt: Added.
     16        * platform/gtk/mathml/opentype/horizontal-LatinModern-munderover-expected.png: Added.
     17        * platform/gtk/mathml/opentype/horizontal-LatinModern-munderover-expected.txt: Added.
     18        * platform/gtk/mathml/opentype/opentype-stretchy-horizontal-expected.png: Added.
     19        * platform/gtk/mathml/opentype/opentype-stretchy-horizontal-expected.txt: Added.
     20        * platform/mac/TestExpectations: mark tests as failing.
     21        * platform/win/TestExpectations: ditto.
     22
    1232014-06-04  Bem Jones-Bey  <bjonesbe@adobe.com>
    224
  • trunk/LayoutTests/platform/efl/TestExpectations

    r169526 r169607  
    16271627
    16281628webkit.org/b/133308 fast/selectors/hover-quirks.html [ Failure ]
     1629
     1630# Missing or bad references
     1631webkit.org/b/130322 mathml/opentype/large-operators-LatinModern.html [ Failure ]
     1632webkit.org/b/130322 mathml/opentype/opentype-stretchy.html [ Failure ]
     1633webkit.org/b/130322 mathml/opentype/vertical-LatinModern.html [ Failure ]
     1634webkit.org/b/72828 mathml/opentype/horizontal-LatinModern.html [ Failure ]
     1635webkit.org/b/72828 mathml/opentype/opentype-stretchy-horizontal.html [ Failure ]
     1636webkit.org/b/72828 mathml/opentype/horizontal-LatinModern-munderover.html [ Failure ]
  • trunk/LayoutTests/platform/mac/TestExpectations

    r169515 r169607  
    13261326webkit.org/b/130322 [ MountainLion Mavericks ] mathml/opentype/opentype-stretchy.html [ Failure ]
    13271327webkit.org/b/130322 [ MountainLion Mavericks ] mathml/opentype/vertical-LatinModern.html [ Failure ]
     1328webkit.org/b/72828 mathml/opentype/horizontal-LatinModern.html [ Failure ]
     1329webkit.org/b/72828 mathml/opentype/opentype-stretchy-horizontal.html [ Failure ]
     1330webkit.org/b/72828 mathml/opentype/horizontal-LatinModern-munderover.html [ Failure ]
    13281331
    13291332# WebKitDataCue is supported, not DataCue
  • trunk/LayoutTests/platform/win/TestExpectations

    r169334 r169607  
    27472747webkit.org/b/130322 mathml/opentype/opentype-stretchy.html [ Failure ]
    27482748webkit.org/b/130322 mathml/opentype/vertical-LatinModern.html [ Failure ]
     2749webkit.org/b/72828 mathml/opentype/horizontal-LatinModern.html [ Failure ]
     2750webkit.org/b/72828 mathml/opentype/opentype-stretchy-horizontal.html [ Failure ]
     2751webkit.org/b/72828 mathml/opentype/horizontal-LatinModern-munderover.html [ Failure ]
  • trunk/Source/WebCore/ChangeLog

    r169606 r169607  
     12014-06-05  Frédéric Wang  <fred.wang@free.fr>
     2
     3        MathML operators not stretched horizontally
     4        https://bugs.webkit.org/show_bug.cgi?id=72828
     5
     6        Reviewed by Chris Fleizach.
     7
     8        This patch adds basic horizontal stretching rules for operators inside
     9        an <munder>, <mover> or <munderover> elements. The stretchy operators
     10        in such an element stretch to cover the size of the non-stretchy
     11        operators. This only works when fonts that have an OpenType MATH table
     12        are used.
     13
     14        Tests: mathml/opentype/horizontal-LatinModern.html
     15               mathml/opentype/opentype-stretchy-horizontal.html
     16               mathml/opentype/horizontal-LatinModern-munderover.html
     17
     18        * rendering/mathml/RenderMathMLOperator.cpp:
     19        (WebCore::MathMLOperatorDictionary::ExtractKeyHorizontal): We add an ordered list of operators that have horizontal stretch direction.
     20        (WebCore::RenderMathMLOperator::RenderMathMLOperator): init m_Vertical
     21        (WebCore::RenderMathMLOperator::SetOperatorProperties): set m_Vertical by checking whether the operator is in the horizontalOperators list.
     22        (WebCore::RenderMathMLOperator::stretchTo): We do not stretch vertically
     23        if the operator has horizontal direction.
     24        We also add a new version stretchTo(LayoutUnit width) for horizontal stretching only.
     25        (WebCore::RenderMathMLOperator::computePreferredLogicalWidths): Handle horizontal stretching: the maximumGlyphWidth is the maximum of
     26        the base size or of the stretch size.
     27        (WebCore::RenderMathMLOperator::getDisplayStyleLargeOperator): Add an ASSERT to ensure that this function is only called for vertical stretching.
     28        (WebCore::RenderMathMLOperator::findStretchyData): Add an ASSERT to ensure that this function is not called to get the maximum width of a horizontal stretchy operator.
     29        We take into account m_isVertical when calling getMathVariants or computing sizes.
     30        There is not any Unicode-only construction for horizontal stretching, so a MATH table is required for horizontal stretching.
     31        (WebCore::RenderMathMLOperator::updateStyle): Ignore some code paths specific to vertical stretching and take into account the m_Vertical parameters.
     32        For horizontal stretching, the m_stretch*Baseline parameters are now updated to match the metrics of the size variant or of the maximum of the parts in the glyph assembly.
     33        (WebCore::RenderMathMLOperator::computeLogicalHeight): logicalHeight is now explicitely the sum of m_stretchHeightAboveBaseline and m_stretchDepthBelowBaseline, since it can be different from the stretchSize() in horizontal stretching.
     34        (WebCore::RenderMathMLOperator::paintGlyph): handle trimming for horizontal stretching.
     35        (WebCore::RenderMathMLOperator::fillWithVerticalExtensionGlyph): rename the function and ensure it is only call for m_isVertical.
     36        (WebCore::RenderMathMLOperator::fillWithHorizontalExtensionGlyph): same as fillWithVerticalExtensionGlyph, but for horizontal stretching.
     37        (WebCore::RenderMathMLOperator::paint): For glyph assembly, choose between paintVerticalGlyphAssembly or paintHorizontalGlyphAssembly.
     38        (WebCore::RenderMathMLOperator::paintVerticalGlyphAssembly): rename the function and ensure it is only call for m_isVertical.
     39        (WebCore::RenderMathMLOperator::paintHorizontalGlyphAssembly): same as paintVerticalGlyphAssembly but for horizontal stretching.
     40        * rendering/mathml/RenderMathMLOperator.h: we add a m_isVertical member to indicate the stretch direction and a m_stretchWidth to indicate the width of the stretchy character.
     41        We define the horizontal counterparts of fillWith*ExtensionGlyph, paint*GlyphAssembly, GlyphPaintTrimming  StretchyData.
     42        Finally stretchSize() takes into account the stretch direction.
     43        * rendering/mathml/RenderMathMLUnderOver.cpp: We override the layout() function to stretch munderover children horizontally.
     44        (WebCore::RenderMathMLUnderOver::layout):
     45        * rendering/mathml/RenderMathMLUnderOver.h: we declare layout().
     46
    1472014-06-04  Bem Jones-Bey  <bjonesbe@adobe.com>
    248
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp

    r169305 r169607  
    11261126};
    11271127
     1128// A list of operators that stretch in the horizontal direction. This has been generated from Mozilla's MathML operator dictionary.
     1129inline UChar ExtractKeyHorizontal(const UChar* entry) { return *entry; }
     1130static const UChar horizontalOperators[] = {
     1131    0x003D, 0x005E, 0x005F, 0x007E, 0x00AF, 0x02C6, 0x02C7, 0x02C9, 0x02CD, 0x02DC, 0x02F7, 0x0302, 0x0332, 0x203E, 0x20D0, 0x20D1, 0x20D6, 0x20D7, 0x20E1, 0x2190, 0x2192, 0x2194, 0x2198, 0x2199, 0x219C, 0x219D, 0x219E, 0x21A0, 0x21A2, 0x21A3, 0x21A4, 0x21A6, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21B4, 0x21B9, 0x21BC, 0x21BD, 0x21C0, 0x21C1, 0x21C4, 0x21C6, 0x21C7, 0x21C9, 0x21CB, 0x21CC, 0x21D0, 0x21D2, 0x21D4, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21E0, 0x21E2, 0x21E4, 0x21E5, 0x21E6, 0x21E8, 0x21F0, 0x21F6, 0x21FD, 0x21FE, 0x21FF, 0x23B4, 0x23B5, 0x23DC, 0x23DD, 0x23DE, 0x23DF, 0x23E0, 0x23E1, 0x2500, 0x27F5, 0x27F6, 0x27F7, 0x27F8, 0x27F9, 0x27FA, 0x27FB, 0x27FC, 0x27FD, 0x27FE, 0x27FF, 0x290C, 0x290D, 0x290E, 0x290F, 0x2910, 0x294E, 0x2950, 0x2952, 0x2953, 0x2956, 0x2957, 0x295A, 0x295B, 0x295E, 0x295F, 0x2B45, 0x2B46, 0xFE35, 0xFE36, 0xFE37, 0xFE38
     1132};
     1133
    11281134}
    11291135
     
    11331139    , m_stretchDepthBelowBaseline(0)
    11341140    , m_operator(0)
     1141    , m_isVertical(true)
    11351142{
    11361143    updateTokenContent();
     
    11421149    , m_stretchDepthBelowBaseline(0)
    11431150    , m_operator(0)
     1151    , m_isVertical(true)
    11441152    , m_operatorForm(form)
    11451153    , m_operatorFlags(flag)
     
    11741182void RenderMathMLOperator::SetOperatorProperties()
    11751183{
     1184    // We determine the stretch direction (default is vertical).
     1185    m_isVertical = !(tryBinarySearch<const UChar, UChar>(MathMLOperatorDictionary::horizontalOperators, WTF_ARRAY_LENGTH(MathMLOperatorDictionary::horizontalOperators), m_operator, MathMLOperatorDictionary::ExtractKeyHorizontal));
     1186
    11761187    // We determine the form of the operator.
    11771188    bool explicitForm = true;
     
    12541265void RenderMathMLOperator::stretchTo(LayoutUnit heightAboveBaseline, LayoutUnit depthBelowBaseline)
    12551266{
    1256     if (heightAboveBaseline == m_stretchHeightAboveBaseline && depthBelowBaseline == m_stretchDepthBelowBaseline)
     1267    if (!m_isVertical || (heightAboveBaseline == m_stretchHeightAboveBaseline && depthBelowBaseline == m_stretchDepthBelowBaseline))
    12571268        return;
    12581269
     
    12811292    m_stretchHeightAboveBaseline *= aspect;
    12821293    m_stretchDepthBelowBaseline *= aspect;
     1294    updateStyle();
     1295}
     1296
     1297void RenderMathMLOperator::stretchTo(LayoutUnit width)
     1298{
     1299    if (m_isVertical || m_stretchWidth == width)
     1300        return;
     1301
     1302    m_stretchWidth = width;
     1303
     1304    SetOperatorProperties();
     1305
    12831306    updateStyle();
    12841307}
     
    13191342    GlyphData data = style().font().glyphDataForCharacter(m_operator, false);
    13201343    float maximumGlyphWidth = advanceForGlyph(data);
     1344    if (!m_isVertical) {
     1345        if (maximumGlyphWidth < stretchSize())
     1346            maximumGlyphWidth = stretchSize();
     1347        m_maxPreferredLogicalWidth = m_leadingSpace + maximumGlyphWidth + m_trailingSpace;
     1348        m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
     1349        return;
     1350    }
    13211351    if (isLargeOperatorInDisplayStyle()) {
    13221352        // Large operators in STIX Word have incorrect advance width, causing misplacement of superscript, so we use the glyph bound instead (http://sourceforge.net/p/stixfonts/tracking/49/).
     
    14821512    StretchyData data;
    14831513
    1484     ASSERT(isLargeOperatorInDisplayStyle());
     1514    ASSERT(m_isVertical && isLargeOperatorInDisplayStyle());
    14851515
    14861516    const auto& primaryFontData = style().font().primaryFont();
     
    15111541RenderMathMLOperator::StretchyData RenderMathMLOperator::findStretchyData(UChar character, float* maximumGlyphWidth)
    15121542{
     1543    ASSERT(!maximumGlyphWidth || m_isVertical);
     1544
    15131545    StretchyData data;
    15141546    StretchyData assemblyData;
     
    15201552        Vector<Glyph> sizeVariants;
    15211553        Vector<OpenTypeMathData::AssemblyPart> assemblyParts;
    1522         primaryFontData->mathData()->getMathVariants(baseGlyph.glyph, true, sizeVariants, assemblyParts);
     1554        primaryFontData->mathData()->getMathVariants(baseGlyph.glyph, m_isVertical, sizeVariants, assemblyParts);
    15231555        // We verify the size variants.
    15241556        for (auto& variant : sizeVariants) {
     
    15301562            else {
    15311563                data.setSizeVariantMode(sizeVariant);
    1532                 if (heightForGlyph(sizeVariant) >= stretchSize())
     1564                float size = m_isVertical ? heightForGlyph(sizeVariant) : advanceForGlyph(sizeVariant);
     1565                if (size >= stretchSize())
    15331566                    return data;
    15341567            }
     
    15391572            return data;
    15401573    } else {
     1574        if (!m_isVertical)
     1575            return data;
     1576
    15411577        // If the font does not have a MATH table, we fallback to the Unicode-only constructions.
    15421578        const StretchyCharacter* stretchyCharacter = nullptr;
     
    15751611    }
    15761612
    1577     // We ensure that the stretch height is large enough to avoid glyph overlaps.
    1578     float height = heightForGlyph(assemblyData.top()) + heightForGlyph(assemblyData.bottom());
    1579     if (assemblyData.middle().glyph)
    1580         height += heightForGlyph(assemblyData.middle());
    1581     if (height > stretchSize())
     1613    // We ensure that the size is large enough to avoid glyph overlaps.
     1614    float size;
     1615    if (m_isVertical) {
     1616        size = heightForGlyph(assemblyData.top()) + heightForGlyph(assemblyData.bottom());
     1617        if (assemblyData.middle().glyph)
     1618            size += heightForGlyph(assemblyData.middle());
     1619    } else {
     1620        size = advanceForGlyph(assemblyData.left()) + advanceForGlyph(assemblyData.right());
     1621        if (assemblyData.middle().glyph)
     1622            size += advanceForGlyph(assemblyData.middle());
     1623    }
     1624    if (size > stretchSize())
    15821625        return data;
    15831626
     
    16071650        return;
    16081651
    1609     if (isLargeOperatorInDisplayStyle())
     1652    if (m_isVertical && isLargeOperatorInDisplayStyle())
    16101653        m_stretchyData = getDisplayStyleLargeOperator(m_operator);
    16111654    else {
    16121655        // We do not stretch if the base glyph is large enough.
    16131656        GlyphData baseGlyph = style().font().glyphDataForCharacter(m_operator, false);
    1614         float baseHeight = heightForGlyph(baseGlyph);
    1615         if (stretchSize() <= baseHeight)
     1657        float baseSize = m_isVertical ? heightForGlyph(baseGlyph) : advanceForGlyph(baseGlyph);
     1658        if (stretchSize() <= baseSize)
    16161659            return;
    16171660        m_stretchyData = findStretchyData(m_operator, nullptr);
    16181661    }
    16191662
    1620     if (m_stretchyData.mode() == DrawSizeVariant) {
     1663    if (m_isVertical && m_stretchyData.mode() == DrawSizeVariant) {
    16211664        // We resize the operator to match the one of the size variant.
    16221665        if (isLargeOperatorInDisplayStyle()) {
     
    16351678        }
    16361679    }
     1680
     1681    if (!m_isVertical) {
     1682        if (m_stretchyData.mode() == DrawSizeVariant) {
     1683            FloatRect glyphBounds = boundsForGlyph(m_stretchyData.variant());
     1684            m_stretchHeightAboveBaseline = -glyphBounds.y();
     1685            m_stretchDepthBelowBaseline = glyphBounds.maxY();
     1686            m_stretchWidth = advanceForGlyph(m_stretchyData.variant());
     1687        } else if (m_stretchyData.mode() == DrawGlyphAssembly) {
     1688            FloatRect glyphBounds;
     1689            m_stretchHeightAboveBaseline = 0;
     1690            m_stretchDepthBelowBaseline = 0;
     1691
     1692            glyphBounds = boundsForGlyph(m_stretchyData.left());
     1693            m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
     1694            m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
     1695
     1696            glyphBounds = boundsForGlyph(m_stretchyData.right());
     1697            m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
     1698            m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
     1699
     1700            glyphBounds = boundsForGlyph(m_stretchyData.extension());
     1701            m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
     1702            m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
     1703
     1704            if (m_stretchyData.middle().glyph) {
     1705                glyphBounds = boundsForGlyph(m_stretchyData.middle());
     1706                m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
     1707                m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
     1708            }
     1709        }
     1710    }
    16371711}
    16381712
     
    16471721{
    16481722    if (m_stretchyData.mode() != DrawNormal)
    1649         logicalHeight = stretchSize();
     1723        logicalHeight = m_stretchHeightAboveBaseline + m_stretchDepthBelowBaseline;
    16501724    RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
    16511725}
     
    16711745        clipBounds.shiftMaxYEdgeTo(glyphPaintRect.maxY());
    16721746        break;
    1673     case TrimTopAndBottom:
     1747    case TrimTopAndBottom: {
    16741748        LayoutUnit temp = glyphPaintRect.y() + 1;
    16751749        glyphPaintRect.shiftYEdgeTo(temp.ceil());
     
    16771751        clipBounds.shiftYEdgeTo(glyphPaintRect.y());
    16781752        clipBounds.shiftMaxYEdgeTo(glyphPaintRect.maxY());
     1753    }
    16791754        break;
     1755    case TrimLeft:
     1756        glyphPaintRect.shiftXEdgeTo(glyphPaintRect.x().ceil() + 1);
     1757        clipBounds.shiftXEdgeTo(glyphPaintRect.x());
     1758        break;
     1759    case TrimRight:
     1760        glyphPaintRect.shiftMaxXEdgeTo(glyphPaintRect.maxX().floor() - 1);
     1761        clipBounds.shiftMaxXEdgeTo(glyphPaintRect.maxX());
     1762        break;
     1763    case TrimLeftAndRight: {
     1764        LayoutUnit temp = glyphPaintRect.x() + 1;
     1765        glyphPaintRect.shiftXEdgeTo(temp.ceil());
     1766        glyphPaintRect.shiftMaxXEdgeTo(glyphPaintRect.maxX().floor() - 1);
     1767        clipBounds.shiftXEdgeTo(glyphPaintRect.x());
     1768        clipBounds.shiftMaxXEdgeTo(glyphPaintRect.maxX());
     1769    }
    16801770    }
    16811771
     
    16911781}
    16921782
    1693 void RenderMathMLOperator::fillWithExtensionGlyph(PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
    1694 {
     1783void RenderMathMLOperator::fillWithVerticalExtensionGlyph(PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
     1784{
     1785    ASSERT(m_isVertical);
    16951786    ASSERT(m_stretchyData.mode() == DrawGlyphAssembly);
    16961787    ASSERT(m_stretchyData.extension().glyph);
     
    17201811        lastPaintedGlyphRect = paintGlyph(info, m_stretchyData.extension(), glyphOrigin, TrimTopAndBottom);
    17211812        glyphOrigin.setY(glyphOrigin.y() + lastPaintedGlyphRect.height());
     1813
     1814        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
     1815        // with trimming. In that case we just draw nothing.
     1816        if (lastPaintedGlyphRect.isEmpty())
     1817            break;
     1818    }
     1819}
     1820
     1821void RenderMathMLOperator::fillWithHorizontalExtensionGlyph(PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
     1822{
     1823    ASSERT(!m_isVertical);
     1824    ASSERT(m_stretchyData.mode() == DrawGlyphAssembly);
     1825    ASSERT(m_stretchyData.extension().glyph);
     1826    ASSERT(from.x() <= to.x());
     1827
     1828    // If there is no space for the extension glyph, we don't need to do anything.
     1829    if (from.x() == to.x())
     1830        return;
     1831
     1832    GraphicsContextStateSaver stateSaver(*info.context);
     1833
     1834    // Clipping the extender region here allows us to draw the bottom extender glyph into the
     1835    // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
     1836    LayoutRect clipBounds = info.rect;
     1837    clipBounds.shiftXEdgeTo(from.x());
     1838    clipBounds.shiftMaxXEdgeTo(to.x());
     1839    info.context->clip(clipBounds);
     1840
     1841    // Trimming may remove up to two pixels from the left of the extender glyph, so we move it left by two pixels.
     1842    float offsetToGlyphLeft = -2;
     1843    LayoutPoint glyphOrigin = LayoutPoint(from.x() + offsetToGlyphLeft, std::min(from.y(), to.y()) + m_stretchHeightAboveBaseline);
     1844    FloatRect lastPaintedGlyphRect(from, FloatSize());
     1845
     1846    while (lastPaintedGlyphRect.maxX() < to.x()) {
     1847        lastPaintedGlyphRect = paintGlyph(info, m_stretchyData.extension(), glyphOrigin, TrimLeftAndRight);
     1848        glyphOrigin.setX(glyphOrigin.x() + lastPaintedGlyphRect.width());
    17221849
    17231850        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
     
    17511878    }
    17521879
     1880    if (m_isVertical)
     1881        paintVerticalGlyphAssembly(info, paintOffset);
     1882    else
     1883        paintHorizontalGlyphAssembly(info, paintOffset);
     1884}
     1885
     1886void RenderMathMLOperator::paintVerticalGlyphAssembly(PaintInfo& info, const LayoutPoint& paintOffset)
     1887{
     1888    ASSERT(m_isVertical);
    17531889    ASSERT(m_stretchyData.mode() == DrawGlyphAssembly);
    17541890    ASSERT(m_stretchyData.top().glyph);
     
    17751911
    17761912        LayoutRect middleGlyphPaintRect = paintGlyph(info, m_stretchyData.middle(), middleGlyphOrigin, TrimTopAndBottom);
    1777         fillWithExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
    1778         fillWithExtensionGlyph(info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
     1913        fillWithVerticalExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
     1914        fillWithVerticalExtensionGlyph(info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
    17791915    } else
    1780         fillWithExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
     1916        fillWithVerticalExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
     1917}
     1918
     1919void RenderMathMLOperator::paintHorizontalGlyphAssembly(PaintInfo& info, const LayoutPoint& paintOffset)
     1920{
     1921    ASSERT(!m_isVertical);
     1922    ASSERT(m_stretchyData.mode() == DrawGlyphAssembly);
     1923    ASSERT(m_stretchyData.left().glyph);
     1924    ASSERT(m_stretchyData.right().glyph);
     1925
     1926    // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
     1927    LayoutPoint operatorTopLeft = paintOffset + location();
     1928    operatorTopLeft.move(m_leadingSpace, 0);
     1929    operatorTopLeft = ceiledIntPoint(operatorTopLeft);
     1930    LayoutPoint leftGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + m_stretchHeightAboveBaseline);
     1931    LayoutRect leftGlyphPaintRect = paintGlyph(info, m_stretchyData.left(), leftGlyphOrigin, TrimRight);
     1932
     1933    FloatRect rightGlyphBounds = boundsForGlyph(m_stretchyData.right());
     1934    LayoutPoint rightGlyphOrigin(operatorTopLeft.x() + offsetWidth() - rightGlyphBounds.width(), operatorTopLeft.y() + m_stretchHeightAboveBaseline);
     1935    LayoutRect rightGlyphPaintRect = paintGlyph(info, m_stretchyData.right(), rightGlyphOrigin, TrimLeft);
     1936
     1937    if (m_stretchyData.middle().glyph) {
     1938        // Center the glyph origin between the start and end glyph paint extents.
     1939        LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), leftGlyphOrigin.y());
     1940        middleGlyphOrigin.moveBy(LayoutPoint((rightGlyphPaintRect.x() - leftGlyphPaintRect.maxX()) / 2.0, 0));
     1941        LayoutRect middleGlyphPaintRect = paintGlyph(info, m_stretchyData.middle(), middleGlyphOrigin, TrimLeftAndRight);
     1942        fillWithHorizontalExtensionGlyph(info, leftGlyphPaintRect.maxXMinYCorner(), middleGlyphPaintRect.minXMinYCorner());
     1943        fillWithHorizontalExtensionGlyph(info, middleGlyphPaintRect.maxXMinYCorner(), rightGlyphPaintRect.minXMinYCorner());
     1944    } else
     1945        fillWithHorizontalExtensionGlyph(info, leftGlyphPaintRect.maxXMinYCorner(), rightGlyphPaintRect.minXMinYCorner());
    17811946}
    17821947
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.h

    r169305 r169607  
    6565
    6666    void stretchTo(LayoutUnit heightAboveBaseline, LayoutUnit depthBelowBaseline);
    67     LayoutUnit stretchSize() const { return m_stretchHeightAboveBaseline + m_stretchDepthBelowBaseline; }
     67    void stretchTo(LayoutUnit width);
     68    LayoutUnit stretchSize() const { return m_isVertical ? m_stretchHeightAboveBaseline + m_stretchDepthBelowBaseline : m_stretchWidth; }
    6869   
    6970    bool hasOperatorFlag(MathMLOperatorDictionary::Flag flag) const { return m_operatorFlags & flag; }
     
    111112        GlyphData bottom() const { return m_data[2]; }
    112113        GlyphData middle() const { return m_data[3]; }
     114        GlyphData left() const { return m_data[2]; }
     115        GlyphData right() const { return m_data[0]; }
    113116
    114117        void setNormalMode()
     
    158161        TrimBottom,
    159162        TrimTopAndBottom,
     163        TrimLeft,
     164        TrimRight,
     165        TrimLeftAndRight
    160166    };
    161167
    162168    LayoutRect paintGlyph(PaintInfo&, const GlyphData&, const LayoutPoint& origin, GlyphPaintTrimming);
    163     void fillWithExtensionGlyph(PaintInfo&, const LayoutPoint& from, const LayoutPoint& to);
     169    void fillWithVerticalExtensionGlyph(PaintInfo&, const LayoutPoint& from, const LayoutPoint& to);
     170    void fillWithHorizontalExtensionGlyph(PaintInfo&, const LayoutPoint& from, const LayoutPoint& to);
     171    void paintVerticalGlyphAssembly(PaintInfo&, const LayoutPoint&);
     172    void paintHorizontalGlyphAssembly(PaintInfo&, const LayoutPoint&);
    164173
    165174    LayoutUnit m_stretchHeightAboveBaseline;
    166175    LayoutUnit m_stretchDepthBelowBaseline;
     176    LayoutUnit m_stretchWidth;
    167177
    168178    UChar m_operator;
     179    bool m_isVertical;
    169180    StretchyData m_stretchyData;
    170181    MathMLOperatorDictionary::Form m_operatorForm;
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.cpp

    r165699 r169607  
    3131
    3232#include "MathMLElement.h"
     33#include "MathMLNames.h"
     34#include "RenderIterator.h"
     35#include "RenderMathMLOperator.h"
    3336
    3437namespace WebCore {
     
    6972}
    7073
     74void RenderMathMLUnderOver::layout()
     75{
     76    LayoutUnit stretchWidth = 0;
     77    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
     78        if (child->needsLayout())
     79            toRenderElement(child)->layout();
     80        // Skipping the embellished op does not work for nested structures like
     81        // <munder><mover><mo>_</mo>...</mover> <mo>_</mo></munder>.
     82        if (child->isBox())
     83            stretchWidth = std::max<LayoutUnit>(stretchWidth, toRenderBox(child)->logicalWidth());
     84    }
     85
     86    // Set the sizes of (possibly embellished) stretchy operator children.
     87    for (auto& child : childrenOfType<RenderMathMLBlock>(*this)) {
     88        if (auto renderOperator = child.unembellishedOperator())
     89            renderOperator->stretchTo(stretchWidth);
     90    }
     91
     92    RenderMathMLBlock::layout();
     93}
     94
    7195}
    7296
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h

    r162139 r169607  
    4141    virtual int firstLineBaseline() const override;
    4242   
     43protected:
     44    virtual void layout();
     45
    4346private:
    4447    virtual bool isRenderMathMLUnderOver() const override { return true; }
Note: See TracChangeset for help on using the changeset viewer.