⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 201854 in webkit


Ignore:
Timestamp:
Jun 8, 2016, 11:17:40 PM (10 years ago)
Author:
fred.wang@free.fr
Message:

Move selection and drawing of stretchy operators into a separate MathOperator class
https://bugs.webkit.org/show_bug.cgi?id=156921

Patch by Frederic Wang <fwang@igalia.com> on 2016-06-08
Reviewed by Martin Robinson.

No new tests, behavior is not changed.

  • CMakeLists.txt: Add the MathOperator files.
  • WebCore.xcodeproj/project.pbxproj: Ditto.
  • rendering/mathml/MathOperator.cpp: Added.

(WebCore::boundsForGlyph): Moved from RenderMathMLOperator.
(WebCore::heightForGlyph): Moved from RenderMathMLOperator.
(WebCore::advanceWidthForGlyph): Moved from RenderMathMLOperator.
(WebCore::MathOperator::MathOperator):
(WebCore::MathOperator::setOperator):
(WebCore::MathOperator::getBaseGlyph): Moved from RenderMathMLOperator.
(WebCore::MathOperator::setSizeVariant): Moved from RenderMathMLOperator.
(WebCore::MathOperator::setGlyphAssembly): Moved from RenderMathMLOperator.
(WebCore::MathOperator::calculateDisplayStyleLargeOperator): Moved from RenderMathMLOperator with additional style parameter.
(WebCore::MathOperator::calculateGlyphAssemblyFallBack): Ditto.
(WebCore::MathOperator::calculateStretchyData): Ditto.
(WebCore::MathOperator::paintGlyph): Ditto.
(WebCore::MathOperator::fillWithVerticalExtensionGlyph): Ditto.
(WebCore::MathOperator::fillWithHorizontalExtensionGlyph): Ditto.
(WebCore::MathOperator::paintVerticalGlyphAssembly): Ditto.
(WebCore::MathOperator::paintHorizontalGlyphAssembly): Ditto.

  • rendering/mathml/MathOperator.h: Added.

(WebCore::MathOperator::italicCorrection):
(WebCore::MathOperator::isStretched):
(WebCore::MathOperator::unstretch):
(WebCore::MathOperator::GlyphAssemblyData::GlyphAssemblyData): Moved from RenderMathMLOperator.
(WebCore::MathOperator::stretchSize):

  • rendering/mathml/RenderMathMLOperator.cpp:

(WebCore::RenderMathMLOperator::computePreferredLogicalWidths): Updated to use MathOperator members.
For now we call setOperator to transmit information to m_mathOperator.
(WebCore::RenderMathMLOperator::updateStyle): Updated to use MathOperator members.
For now we set some m_mathOperator members to transmit it some information.
(WebCore::RenderMathMLOperator::firstLineBaseline): Updated to use MathOperator members.
(WebCore::RenderMathMLOperator::computeLogicalHeight): Ditto.
(WebCore::RenderMathMLOperator::paint): Ditto.
For now we set some m_mathOperator members to transmit it some information.
(WebCore::RenderMathMLOperator::paintChildren): Updated to use MathOperator members.
(WebCore::RenderMathMLOperator::trailingSpaceError): Ditto.
(WebCore::RenderMathMLOperator::getBaseGlyph): Deleted.
(WebCore::RenderMathMLOperator::setSizeVariant): Deleted.
(WebCore::RenderMathMLOperator::setGlyphAssembly): Deleted.
(WebCore::RenderMathMLOperator::calculateGlyphAssemblyFallBack): Deleted.
(WebCore::RenderMathMLOperator::calculateDisplayStyleLargeOperator): Deleted.
(WebCore::RenderMathMLOperator::calculateStretchyData): Deleted.
(WebCore::RenderMathMLOperator::paintGlyph): Deleted.
(WebCore::RenderMathMLOperator::fillWithVerticalExtensionGlyph): Deleted.
(WebCore::RenderMathMLOperator::fillWithHorizontalExtensionGlyph): Deleted.
(WebCore::RenderMathMLOperator::paintVerticalGlyphAssembly): Deleted.
(WebCore::RenderMathMLOperator::paintHorizontalGlyphAssembly): Deleted.

  • rendering/mathml/RenderMathMLOperator.h:

(WebCore::RenderMathMLOperator::italicCorrection): Updated to use MathOperator members.
(WebCore::RenderMathMLOperator::GlyphAssemblyData::GlyphAssemblyData): Deleted.

Location:
trunk/Source/WebCore
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/CMakeLists.txt

    r201810 r201854  
    25182518
    25192519    rendering/mathml/MathMLOperatorDictionary.cpp
     2520    rendering/mathml/MathOperator.cpp
    25202521    rendering/mathml/RenderMathMLBlock.cpp
    25212522    rendering/mathml/RenderMathMLFenced.cpp
  • trunk/Source/WebCore/ChangeLog

    r201852 r201854  
     12016-06-08  Frederic Wang  <fwang@igalia.com>
     2
     3        Move selection and drawing of stretchy operators into a separate MathOperator class
     4        https://bugs.webkit.org/show_bug.cgi?id=156921
     5
     6        Reviewed by Martin Robinson.
     7
     8        No new tests, behavior is not changed.
     9
     10        * CMakeLists.txt: Add the MathOperator files.
     11        * WebCore.xcodeproj/project.pbxproj: Ditto.
     12        * rendering/mathml/MathOperator.cpp: Added.
     13        (WebCore::boundsForGlyph): Moved from RenderMathMLOperator.
     14        (WebCore::heightForGlyph): Moved from RenderMathMLOperator.
     15        (WebCore::advanceWidthForGlyph): Moved from RenderMathMLOperator.
     16        (WebCore::MathOperator::MathOperator):
     17        (WebCore::MathOperator::setOperator):
     18        (WebCore::MathOperator::getBaseGlyph): Moved from RenderMathMLOperator.
     19        (WebCore::MathOperator::setSizeVariant): Moved from RenderMathMLOperator.
     20        (WebCore::MathOperator::setGlyphAssembly): Moved from RenderMathMLOperator.
     21        (WebCore::MathOperator::calculateDisplayStyleLargeOperator): Moved from RenderMathMLOperator with additional style parameter.
     22        (WebCore::MathOperator::calculateGlyphAssemblyFallBack): Ditto.
     23        (WebCore::MathOperator::calculateStretchyData): Ditto.
     24        (WebCore::MathOperator::paintGlyph): Ditto.
     25        (WebCore::MathOperator::fillWithVerticalExtensionGlyph): Ditto.
     26        (WebCore::MathOperator::fillWithHorizontalExtensionGlyph): Ditto.
     27        (WebCore::MathOperator::paintVerticalGlyphAssembly): Ditto.
     28        (WebCore::MathOperator::paintHorizontalGlyphAssembly): Ditto.
     29        * rendering/mathml/MathOperator.h: Added.
     30        (WebCore::MathOperator::italicCorrection):
     31        (WebCore::MathOperator::isStretched):
     32        (WebCore::MathOperator::unstretch):
     33        (WebCore::MathOperator::GlyphAssemblyData::GlyphAssemblyData): Moved from RenderMathMLOperator.
     34        (WebCore::MathOperator::stretchSize):
     35        * rendering/mathml/RenderMathMLOperator.cpp:
     36        (WebCore::RenderMathMLOperator::computePreferredLogicalWidths): Updated to use MathOperator members.
     37        For now we call setOperator to transmit information to m_mathOperator.
     38        (WebCore::RenderMathMLOperator::updateStyle): Updated to use MathOperator members.
     39        For now we set some m_mathOperator members to transmit it some information.
     40        (WebCore::RenderMathMLOperator::firstLineBaseline): Updated to use MathOperator members.
     41        (WebCore::RenderMathMLOperator::computeLogicalHeight): Ditto.
     42        (WebCore::RenderMathMLOperator::paint): Ditto.
     43        For now we set some m_mathOperator members to transmit it some information.
     44        (WebCore::RenderMathMLOperator::paintChildren): Updated to use MathOperator members.
     45        (WebCore::RenderMathMLOperator::trailingSpaceError): Ditto.
     46        (WebCore::RenderMathMLOperator::getBaseGlyph): Deleted.
     47        (WebCore::RenderMathMLOperator::setSizeVariant): Deleted.
     48        (WebCore::RenderMathMLOperator::setGlyphAssembly): Deleted.
     49        (WebCore::RenderMathMLOperator::calculateGlyphAssemblyFallBack): Deleted.
     50        (WebCore::RenderMathMLOperator::calculateDisplayStyleLargeOperator): Deleted.
     51        (WebCore::RenderMathMLOperator::calculateStretchyData): Deleted.
     52        (WebCore::RenderMathMLOperator::paintGlyph): Deleted.
     53        (WebCore::RenderMathMLOperator::fillWithVerticalExtensionGlyph): Deleted.
     54        (WebCore::RenderMathMLOperator::fillWithHorizontalExtensionGlyph): Deleted.
     55        (WebCore::RenderMathMLOperator::paintVerticalGlyphAssembly): Deleted.
     56        (WebCore::RenderMathMLOperator::paintHorizontalGlyphAssembly): Deleted.
     57        * rendering/mathml/RenderMathMLOperator.h:
     58        (WebCore::RenderMathMLOperator::italicCorrection): Updated to use MathOperator members.
     59        (WebCore::RenderMathMLOperator::GlyphAssemblyData::GlyphAssemblyData): Deleted.
     60
    1612016-06-08  Chris Dumez  <cdumez@apple.com>
    262
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r201831 r201854  
    16711671                439046E912DA25E800AF80A2 /* RenderMathMLUnderOver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 439046D512DA25E800AF80A2 /* RenderMathMLUnderOver.cpp */; };
    16721672                439046EA12DA25E800AF80A2 /* RenderMathMLUnderOver.h in Headers */ = {isa = PBXBuildFile; fileRef = 439046D612DA25E800AF80A2 /* RenderMathMLUnderOver.h */; };
     1673                439046E912DA25E812AF80AC /* MathOperator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 439046D512DA25E812AF80AC /* MathOperator.cpp */; };
     1674                439046EA12DA25E812AF80AC /* MathOperator.h in Headers */ = {isa = PBXBuildFile; fileRef = 439046D612DA25E812AF80AC /* MathOperator.h */; };
    16731675                439046EB12DA25E800AF80A9 /* RenderMathMLToken.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 439046D712DA25E800AF80A9 /* RenderMathMLToken.cpp */; };
    16741676                439046EC12DA25E800AF80A9 /* RenderMathMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 439046D812DA25E800AF80A9 /* RenderMathMLToken.h */; };
     
    92349236                439046D512DA25E800AF80A2 /* RenderMathMLUnderOver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMathMLUnderOver.cpp; sourceTree = "<group>"; };
    92359237                439046D612DA25E800AF80A2 /* RenderMathMLUnderOver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderMathMLUnderOver.h; sourceTree = "<group>"; };
     9238                439046D512DA25E812AF80AC /* MathOperator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathOperator.cpp; sourceTree = "<group>"; };
     9239                439046D612DA25E812AF80AC /* MathOperator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathOperator.h; sourceTree = "<group>"; };
    92369240                439046D712DA25E800AF80A9 /* RenderMathMLToken.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMathMLToken.cpp; sourceTree = "<group>"; };
    92379241                439046D812DA25E800AF80A9 /* RenderMathMLToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderMathMLToken.h; sourceTree = "<group>"; };
     
    1698416988                                439046D512DA25E800AF80A2 /* RenderMathMLUnderOver.cpp */,
    1698516989                                439046D612DA25E800AF80A2 /* RenderMathMLUnderOver.h */,
     16990                                439046D512DA25E812AF80AC /* MathOperator.cpp */,
     16991                                439046D612DA25E812AF80AC /* MathOperator.h */,
    1698616992                        );
    1698716993                        path = mathml;
     
    2770227708                                439046EC12DA25E800AF80A9 /* RenderMathMLToken.h in Headers */,
    2770327709                                439046EA12DA25E800AF80A2 /* RenderMathMLUnderOver.h in Headers */,
     27710                                439046EA12DA25E812AF80AC /* MathOperator.h in Headers */,
    2770427711                                E4C279590CF9741900E97B98 /* RenderMedia.h in Headers */,
    2770527712                                DEBCCDD216646E8200A452E1 /* RenderMediaControlElements.h in Headers */,
     
    3138231389                                439046EB12DA25E800AF80A9 /* RenderMathMLToken.cpp in Sources */,
    3138331390                                439046E912DA25E800AF80A2 /* RenderMathMLUnderOver.cpp in Sources */,
     31391                                439046E912DA25E812AF80AC /* MathOperator.cpp in Sources */,
    3138431392                                E4C279580CF9741900E97B98 /* RenderMedia.cpp in Sources */,
    3138531393                                DE49B309165F2FE10010338D /* RenderMediaControlElements.cpp in Sources */,
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp

    r200569 r201854  
    4646using namespace MathMLNames;
    4747
    48 // FIXME: The OpenType MATH table contains information that should override this table (http://wkbug/122297).
    49 struct StretchyCharacter {
    50     UChar character;
    51     UChar topChar;
    52     UChar extensionChar;
    53     UChar bottomChar;
    54     UChar middleChar;
    55 };
    56 // The first leftRightPairsCount pairs correspond to left/right fences that can easily be mirrored in RTL.
    57 static const short leftRightPairsCount = 5;
    58 static const StretchyCharacter stretchyCharacters[14] = {
    59     { 0x28  , 0x239b, 0x239c, 0x239d, 0x0    }, // left parenthesis
    60     { 0x29  , 0x239e, 0x239f, 0x23a0, 0x0    }, // right parenthesis
    61     { 0x5b  , 0x23a1, 0x23a2, 0x23a3, 0x0    }, // left square bracket
    62     { 0x5d  , 0x23a4, 0x23a5, 0x23a6, 0x0    }, // right square bracket
    63     { 0x7b  , 0x23a7, 0x23aa, 0x23a9, 0x23a8 }, // left curly bracket
    64     { 0x7d  , 0x23ab, 0x23aa, 0x23ad, 0x23ac }, // right curly bracket
    65     { 0x2308, 0x23a1, 0x23a2, 0x23a2, 0x0    }, // left ceiling
    66     { 0x2309, 0x23a4, 0x23a5, 0x23a5, 0x0    }, // right ceiling
    67     { 0x230a, 0x23a2, 0x23a2, 0x23a3, 0x0    }, // left floor
    68     { 0x230b, 0x23a5, 0x23a5, 0x23a6, 0x0    }, // right floor
    69     { 0x7c  , 0x7c,   0x7c,   0x7c,   0x0    }, // vertical bar
    70     { 0x2016, 0x2016, 0x2016, 0x2016, 0x0    }, // double vertical line
    71     { 0x2225, 0x2225, 0x2225, 0x2225, 0x0    }, // parallel to
    72     { 0x222b, 0x2320, 0x23ae, 0x2321, 0x0    } // integral sign
    73 };
    74 
    7548RenderMathMLOperator::RenderMathMLOperator(MathMLElement& element, RenderStyle&& style)
    7649    : RenderMathMLToken(element, WTFMove(style))
     
    295268    }
    296269
     270    m_mathOperator.setOperator(m_textContent, m_isVertical);
    297271    GlyphData baseGlyph;
    298     float maximumGlyphWidth = getBaseGlyph(style(), baseGlyph) ? advanceWidthForGlyph(baseGlyph) : 0;
     272    float maximumGlyphWidth = m_mathOperator.getBaseGlyph(style(), baseGlyph) ? advanceWidthForGlyph(baseGlyph) : 0;
    299273    if (!m_isVertical) {
    300274        if (maximumGlyphWidth < stretchSize())
     
    306280    if (isLargeOperatorInDisplayStyle()) {
    307281        // 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/).
    308         calculateDisplayStyleLargeOperator();
    309         if (m_stretchType == StretchType::SizeVariant)
    310             maximumGlyphWidth = boundsForGlyph(m_variant).width();
     282        m_mathOperator.calculateDisplayStyleLargeOperator(style());
     283        if (m_mathOperator.m_stretchType == MathOperator::StretchType::SizeVariant)
     284            maximumGlyphWidth = boundsForGlyph(m_mathOperator.m_variant).width();
    311285    } else {
    312286        // FIXME: some glyphs (e.g. the one for "FRACTION SLASH" in the STIX Math font or large operators) have a width that depends on the height, resulting in large gaps (https://bugs.webkit.org/show_bug.cgi?id=130326).
    313         calculateStretchyData(&maximumGlyphWidth);
     287        m_mathOperator.calculateStretchyData(style(), &maximumGlyphWidth);
    314288    }
    315289    m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth = m_leadingSpace + maximumGlyphWidth + m_trailingSpace;
     
    375349}
    376350
    377 bool RenderMathMLOperator::getBaseGlyph(const RenderStyle& style, GlyphData& baseGlyph) const
    378 {
    379     baseGlyph = style.fontCascade().glyphDataForCharacter(m_textContent, !style.isLeftToRightDirection());
    380     return baseGlyph.isValid() && baseGlyph.font == &style.fontCascade().primaryFont();
    381 }
    382 
    383 void RenderMathMLOperator::setSizeVariant(const GlyphData& sizeVariant)
    384 {
    385     ASSERT(sizeVariant.isValid() && sizeVariant.font->mathData());
    386     m_stretchType = StretchType::SizeVariant;
    387     m_variant = sizeVariant;
    388 }
    389 
    390 void RenderMathMLOperator::setGlyphAssembly(const GlyphAssemblyData& assemblyData)
    391 {
    392     m_stretchType = StretchType::GlyphAssembly;
    393     m_assembly = assemblyData;
    394 }
    395 
    396 bool RenderMathMLOperator::calculateGlyphAssemblyFallBack(const Vector<OpenTypeMathData::AssemblyPart>& assemblyParts, GlyphAssemblyData& assemblyData) const
    397 {
    398     // The structure of the Open Type Math table is a bit more general than the one currently used by the RenderMathMLOperator code, so we try to fallback in a reasonable way.
    399     // FIXME: RenderMathMLOperator should support the most general format (https://bugs.webkit.org/show_bug.cgi?id=130327).
    400     // We use the approach of the copyComponents function in github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py
    401 
    402     // We count the number of non extender pieces.
    403     int nonExtenderCount = 0;
    404     for (auto& part : assemblyParts) {
    405         if (!part.isExtender)
    406             nonExtenderCount++;
    407     }
    408     if (nonExtenderCount > 3)
    409         return false; // This is not supported: there are too many pieces.
    410 
    411     // We now browse the list of pieces from left to right for horizontal operators and from bottom to top for vertical operators.
    412     enum PartType {
    413         Start,
    414         ExtenderBetweenStartAndMiddle,
    415         Middle,
    416         ExtenderBetweenMiddleAndEnd,
    417         End,
    418         None
    419     };
    420     PartType expectedPartType = Start;
    421     assemblyData.extension.glyph = 0;
    422     assemblyData.middle.glyph = 0;
    423     for (auto& part : assemblyParts) {
    424         if (nonExtenderCount < 3) {
    425             // If we only have at most two non-extenders then we skip the middle glyph.
    426             if (expectedPartType == ExtenderBetweenStartAndMiddle)
    427                 expectedPartType = ExtenderBetweenMiddleAndEnd;
    428             else if (expectedPartType == Middle)
    429                 expectedPartType = End;
    430         }
    431         if (part.isExtender) {
    432             if (!assemblyData.extension.glyph)
    433                 assemblyData.extension.glyph = part.glyph; // We copy the extender part.
    434             else if (assemblyData.extension.glyph != part.glyph)
    435                 return false; // This is not supported: the assembly has different extenders.
    436 
    437             switch (expectedPartType) {
    438             case Start:
    439                 // We ignore the left/bottom part.
    440                 expectedPartType = ExtenderBetweenStartAndMiddle;
    441                 continue;
    442             case Middle:
    443                 // We ignore the middle part.
    444                 expectedPartType = ExtenderBetweenMiddleAndEnd;
    445                 continue;
    446             case End:
    447             case None:
    448                 // This is not supported: we got an unexpected extender.
    449                 return false;
    450             case ExtenderBetweenStartAndMiddle:
    451             case ExtenderBetweenMiddleAndEnd:
    452                 // We ignore multiple consecutive extenders.
    453                 continue;
    454             }
    455         }
    456 
    457         switch (expectedPartType) {
    458         case Start:
    459             // We copy the left/bottom part.
    460             assemblyData.bottomOrLeft.glyph = part.glyph;
    461             expectedPartType = ExtenderBetweenStartAndMiddle;
    462             continue;
    463         case ExtenderBetweenStartAndMiddle:
    464         case Middle:
    465             // We copy the middle part.
    466             assemblyData.middle.glyph = part.glyph;
    467             expectedPartType = ExtenderBetweenMiddleAndEnd;
    468             continue;
    469         case ExtenderBetweenMiddleAndEnd:
    470         case End:
    471             // We copy the right/top part.
    472             assemblyData.topOrRight.glyph = part.glyph;
    473             expectedPartType = None;
    474             continue;
    475         case None:
    476             // This is not supported: we got an unexpected non-extender part.
    477             return false;
    478         }
    479     }
    480 
    481     if (!assemblyData.extension.glyph)
    482         return false; // This is not supported: we always assume that we have an extension glyph.
    483 
    484     // If we don't have top/right or left/bottom glyphs, we use the extension glyph.
    485     if (!assemblyData.topOrRight.glyph)
    486         assemblyData.topOrRight.glyph = assemblyData.extension.glyph;
    487     if (!assemblyData.bottomOrLeft.glyph)
    488         assemblyData.bottomOrLeft.glyph = assemblyData.extension.glyph;
    489 
    490     assemblyData.topOrRight.font = &style().fontCascade().primaryFont();
    491     assemblyData.extension.font = assemblyData.topOrRight.font;
    492     assemblyData.bottomOrLeft.font = assemblyData.topOrRight.font;
    493     assemblyData.middle.font = assemblyData.middle.glyph ? assemblyData.topOrRight.font : nullptr;
    494 
    495     return true;
    496 }
    497 
    498 void RenderMathMLOperator::calculateDisplayStyleLargeOperator()
    499 {
    500     ASSERT(m_isVertical && isLargeOperatorInDisplayStyle());
    501 
    502     GlyphData baseGlyph;
    503     if (!getBaseGlyph(style(), baseGlyph) || !baseGlyph.font->mathData())
    504         return;
    505 
    506     Vector<Glyph> sizeVariants;
    507     Vector<OpenTypeMathData::AssemblyPart> assemblyParts;
    508 
    509     // The value of displayOperatorMinHeight is sometimes too small, so we ensure that it is at least \sqrt{2} times the size of the base glyph.
    510     float displayOperatorMinHeight = std::max(baseGlyph.font->boundsForGlyph(baseGlyph.glyph).height() * sqrtOfTwoFloat, baseGlyph.font->mathData()->getMathConstant(*baseGlyph.font, OpenTypeMathData::DisplayOperatorMinHeight));
    511 
    512     baseGlyph.font->mathData()->getMathVariants(baseGlyph.glyph, true, sizeVariants, assemblyParts);
    513 
    514     // We choose the first size variant that is larger than the expected displayOperatorMinHeight and otherwise fallback to the largest variant.
    515     for (auto& sizeVariant : sizeVariants) {
    516         GlyphData glyphData(sizeVariant, baseGlyph.font);
    517         setSizeVariant(glyphData);
    518         m_italicCorrection = glyphData.font->mathData()->getItalicCorrection(*glyphData.font, glyphData.glyph);
    519         if (heightForGlyph(glyphData) >= displayOperatorMinHeight)
    520             break;
    521     }
    522 }
    523 
    524 void RenderMathMLOperator::calculateStretchyData(float* maximumGlyphWidth, LayoutUnit targetSize)
    525 {
    526     ASSERT(!maximumGlyphWidth || m_isVertical);
    527 
    528     GlyphData baseGlyph;
    529     if (!getBaseGlyph(style(), baseGlyph))
    530         return;
    531    
    532     if (!maximumGlyphWidth) {
    533         // We do not stretch if the base glyph is large enough.
    534         float baseSize = m_isVertical ? heightForGlyph(baseGlyph) : advanceWidthForGlyph(baseGlyph);
    535         if (targetSize <= baseSize)
    536             return;
    537     }
    538 
    539     GlyphAssemblyData assemblyData;
    540     if (baseGlyph.font->mathData()) {
    541         Vector<Glyph> sizeVariants;
    542         Vector<OpenTypeMathData::AssemblyPart> assemblyParts;
    543         baseGlyph.font->mathData()->getMathVariants(baseGlyph.glyph, m_isVertical, sizeVariants, assemblyParts);
    544         // We verify the size variants.
    545         for (auto& sizeVariant : sizeVariants) {
    546             GlyphData glyphData(sizeVariant, baseGlyph.font);
    547             if (maximumGlyphWidth)
    548                 *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceWidthForGlyph(glyphData));
    549             else {
    550                 setSizeVariant(glyphData);
    551                 float size = m_isVertical ? heightForGlyph(glyphData) : advanceWidthForGlyph(glyphData);
    552                 if (size >= targetSize)
    553                     return;
    554             }
    555         }
    556 
    557         // We verify if there is a construction.
    558         if (!calculateGlyphAssemblyFallBack(assemblyParts, assemblyData))
    559             return;
    560     } else {
    561         if (!m_isVertical)
    562             return;
    563 
    564         // If the font does not have a MATH table, we fallback to the Unicode-only constructions.
    565         const StretchyCharacter* stretchyCharacter = nullptr;
    566         const unsigned maxIndex = WTF_ARRAY_LENGTH(stretchyCharacters);
    567         for (unsigned index = 0; index < maxIndex; ++index) {
    568             if (stretchyCharacters[index].character == m_textContent) {
    569                 stretchyCharacter = &stretchyCharacters[index];
    570                 if (!style().isLeftToRightDirection() && index < leftRightPairsCount * 2) {
    571                     // If we are in right-to-left direction we select the mirrored form by adding -1 or +1 according to the parity of index.
    572                     index += index % 2 ? -1 : 1;
    573                 }
    574                 break;
    575             }
    576         }
    577 
    578         // If we didn't find a stretchy character set for this character, we don't know how to stretch it.
    579         if (!stretchyCharacter)
    580             return;
    581 
    582         // We convert the list of Unicode characters into a list of glyph data.
    583         assemblyData.topOrRight = style().fontCascade().glyphDataForCharacter(stretchyCharacter->topChar, false);
    584         assemblyData.extension = style().fontCascade().glyphDataForCharacter(stretchyCharacter->extensionChar, false);
    585         assemblyData.bottomOrLeft = style().fontCascade().glyphDataForCharacter(stretchyCharacter->bottomChar, false);
    586         assemblyData.middle = stretchyCharacter->middleChar ? style().fontCascade().glyphDataForCharacter(stretchyCharacter->middleChar, false) : GlyphData();
    587     }
    588 
    589     // If we are measuring the maximum width, verify each component.
    590     if (maximumGlyphWidth) {
    591         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceWidthForGlyph(assemblyData.topOrRight));
    592         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceWidthForGlyph(assemblyData.extension));
    593         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceWidthForGlyph(assemblyData.middle));
    594         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceWidthForGlyph(assemblyData.bottomOrLeft));
    595         return;
    596     }
    597 
    598     // We ensure that the size is large enough to avoid glyph overlaps.
    599     float minSize = m_isVertical ?
    600         heightForGlyph(assemblyData.topOrRight) + heightForGlyph(assemblyData.middle) + heightForGlyph(assemblyData.bottomOrLeft)
    601         : advanceWidthForGlyph(assemblyData.bottomOrLeft) + advanceWidthForGlyph(assemblyData.middle) + advanceWidthForGlyph(assemblyData.topOrRight);
    602     if (minSize > targetSize)
    603         return;
    604 
    605     setGlyphAssembly(assemblyData);
    606 }
    607 
    608351void RenderMathMLOperator::updateStyle()
    609352{
     
    612355        return;
    613356
    614     m_stretchType = StretchType::Unstretched;
    615     m_italicCorrection = 0;
     357    m_mathOperator.unstretch();
     358    m_mathOperator.m_italicCorrection = 0;
    616359    // We add spacing around the operator.
    617360    // FIXME: The spacing should be added to the whole embellished operator (https://bugs.webkit.org/show_bug.cgi?id=124831).
     
    627370        return;
    628371
     372    m_mathOperator.setOperator(m_textContent, m_isVertical);
    629373    if (m_isVertical && isLargeOperatorInDisplayStyle())
    630         calculateDisplayStyleLargeOperator();
     374        m_mathOperator.calculateDisplayStyleLargeOperator(style());
    631375    else {
    632         calculateStretchyData(nullptr, stretchSize());
    633         if (m_stretchType == StretchType::Unstretched)
     376        m_mathOperator.calculateStretchyData(style(), nullptr, stretchSize());
     377        if (!m_mathOperator.isStretched())
    634378            return;
    635379    }
    636380
    637     if (m_isVertical && m_stretchType == StretchType::SizeVariant) {
     381    if (m_isVertical && m_mathOperator.m_stretchType == MathOperator::StretchType::SizeVariant) {
    638382        // We resize the operator to match the one of the size variant.
    639383        if (isLargeOperatorInDisplayStyle()) {
    640384            // The stretch size is actually not involved in the selection of the size variant in findDisplayStyleLargeOperator.
    641385            // We simply use the height and depth of the selected size variant glyph.
    642             FloatRect glyphBounds = boundsForGlyph(m_variant);
     386            FloatRect glyphBounds = boundsForGlyph(m_mathOperator.m_variant);
    643387            m_stretchHeightAboveBaseline = -glyphBounds.y();
    644388            m_stretchDepthBelowBaseline = glyphBounds.maxY();
    645389        } else {
    646390            // We rescale the height and depth proportionately.
    647             float variantSize = heightForGlyph(m_variant);
     391            float variantSize = heightForGlyph(m_mathOperator.m_variant);
    648392            float size = stretchSize();
    649393            float aspect = size > 0 ? variantSize / size : 1.0;
     
    654398
    655399    if (!m_isVertical) {
    656         if (m_stretchType == StretchType::SizeVariant) {
    657             FloatRect glyphBounds = boundsForGlyph(m_variant);
     400        if (m_mathOperator.m_stretchType == MathOperator::StretchType::SizeVariant) {
     401            FloatRect glyphBounds = boundsForGlyph(m_mathOperator.m_variant);
    658402            m_stretchHeightAboveBaseline = -glyphBounds.y();
    659403            m_stretchDepthBelowBaseline = glyphBounds.maxY();
    660             m_stretchWidth = advanceWidthForGlyph(m_variant);
    661         } else if (m_stretchType == StretchType::GlyphAssembly) {
     404            m_stretchWidth = advanceWidthForGlyph(m_mathOperator.m_variant);
     405        } else if (m_mathOperator.m_stretchType == MathOperator::StretchType::GlyphAssembly) {
    662406            FloatRect glyphBounds;
    663407            m_stretchHeightAboveBaseline = 0;
    664408            m_stretchDepthBelowBaseline = 0;
    665409
    666             glyphBounds = boundsForGlyph(m_assembly.bottomOrLeft);
     410            glyphBounds = boundsForGlyph(m_mathOperator.m_assembly.bottomOrLeft);
    667411            m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
    668412            m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
    669413
    670             glyphBounds = boundsForGlyph(m_assembly.topOrRight);
     414            glyphBounds = boundsForGlyph(m_mathOperator.m_assembly.topOrRight);
    671415            m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
    672416            m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
    673417
    674             glyphBounds = boundsForGlyph(m_assembly.extension);
     418            glyphBounds = boundsForGlyph(m_mathOperator.m_assembly.extension);
    675419            m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
    676420            m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
    677421
    678             if (m_assembly.middle.isValid()) {
    679                 glyphBounds = boundsForGlyph(m_assembly.middle);
     422            if (m_mathOperator.m_assembly.middle.isValid()) {
     423                glyphBounds = boundsForGlyph(m_mathOperator.m_assembly.middle);
    680424                m_stretchHeightAboveBaseline = std::max<LayoutUnit>(m_stretchHeightAboveBaseline, -glyphBounds.y());
    681425                m_stretchDepthBelowBaseline = std::max<LayoutUnit>(m_stretchDepthBelowBaseline, glyphBounds.maxY());
     
    687431Optional<int> RenderMathMLOperator::firstLineBaseline() const
    688432{
    689     if (m_stretchType != StretchType::Unstretched)
     433    if (m_mathOperator.isStretched())
    690434        return Optional<int>(m_stretchHeightAboveBaseline);
    691435    return RenderMathMLToken::firstLineBaseline();
     
    694438void RenderMathMLOperator::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
    695439{
    696     if (m_stretchType != StretchType::Unstretched)
     440    if (m_mathOperator.isStretched())
    697441        logicalHeight = m_stretchHeightAboveBaseline + m_stretchDepthBelowBaseline;
    698442    RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
    699443}
    700444
    701 LayoutRect RenderMathMLOperator::paintGlyph(PaintInfo& info, const GlyphData& data, const LayoutPoint& origin, GlyphPaintTrimming trim)
    702 {
    703     FloatRect glyphBounds = boundsForGlyph(data);
    704 
    705     LayoutRect glyphPaintRect(origin, LayoutSize(glyphBounds.x() + glyphBounds.width(), glyphBounds.height()));
    706     glyphPaintRect.setY(origin.y() + glyphBounds.y());
    707 
    708     // In order to have glyphs fit snugly with one another we snap the connecting edges to pixel boundaries
    709     // and trim off one pixel. The pixel trim is to account for fonts that have edge pixels that have less
    710     // than full coverage. These edge pixels can introduce small seams between connected glyphs.
    711     FloatRect clipBounds = info.rect;
    712     switch (trim) {
    713     case TrimTop:
    714         glyphPaintRect.shiftYEdgeTo(glyphPaintRect.y().ceil() + 1);
    715         clipBounds.shiftYEdgeTo(glyphPaintRect.y());
    716         break;
    717     case TrimBottom:
    718         glyphPaintRect.shiftMaxYEdgeTo(glyphPaintRect.maxY().floor() - 1);
    719         clipBounds.shiftMaxYEdgeTo(glyphPaintRect.maxY());
    720         break;
    721     case TrimTopAndBottom:
    722         glyphPaintRect.shiftYEdgeTo(glyphPaintRect.y().ceil() + 1);
    723         glyphPaintRect.shiftMaxYEdgeTo(glyphPaintRect.maxY().floor() - 1);
    724         clipBounds.shiftYEdgeTo(glyphPaintRect.y());
    725         clipBounds.shiftMaxYEdgeTo(glyphPaintRect.maxY());
    726         break;
    727     case TrimLeft:
    728         glyphPaintRect.shiftXEdgeTo(glyphPaintRect.x().ceil() + 1);
    729         clipBounds.shiftXEdgeTo(glyphPaintRect.x());
    730         break;
    731     case TrimRight:
    732         glyphPaintRect.shiftMaxXEdgeTo(glyphPaintRect.maxX().floor() - 1);
    733         clipBounds.shiftMaxXEdgeTo(glyphPaintRect.maxX());
    734         break;
    735     case TrimLeftAndRight:
    736         glyphPaintRect.shiftXEdgeTo(glyphPaintRect.x().ceil() + 1);
    737         glyphPaintRect.shiftMaxXEdgeTo(glyphPaintRect.maxX().floor() - 1);
    738         clipBounds.shiftXEdgeTo(glyphPaintRect.x());
    739         clipBounds.shiftMaxXEdgeTo(glyphPaintRect.maxX());
    740     }
    741 
    742     // Clipping the enclosing IntRect avoids any potential issues at joined edges.
    743     GraphicsContextStateSaver stateSaver(info.context());
    744     info.context().clip(clipBounds);
    745 
    746     GlyphBuffer buffer;
    747     buffer.add(data.glyph, data.font, advanceWidthForGlyph(data));
    748     info.context().drawGlyphs(style().fontCascade(), *data.font, buffer, 0, 1, origin);
    749 
    750     return glyphPaintRect;
    751 }
    752 
    753 void RenderMathMLOperator::fillWithVerticalExtensionGlyph(PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
    754 {
    755     ASSERT(m_isVertical);
    756     ASSERT(m_stretchType == StretchType::GlyphAssembly);
    757     ASSERT(m_assembly.extension.isValid());
    758     ASSERT(from.y() <= to.y());
    759 
    760     // If there is no space for the extension glyph, we don't need to do anything.
    761     if (from.y() == to.y())
    762         return;
    763 
    764     GraphicsContextStateSaver stateSaver(info.context());
    765 
    766     FloatRect glyphBounds = boundsForGlyph(m_assembly.extension);
    767 
    768     // Clipping the extender region here allows us to draw the bottom extender glyph into the
    769     // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
    770     LayoutRect clipBounds = info.rect;
    771     clipBounds.shiftYEdgeTo(from.y());
    772     clipBounds.shiftMaxYEdgeTo(to.y());
    773     info.context().clip(clipBounds);
    774 
    775     // Trimming may remove up to two pixels from the top of the extender glyph, so we move it up by two pixels.
    776     float offsetToGlyphTop = glyphBounds.y() + 2;
    777     LayoutPoint glyphOrigin = LayoutPoint(from.x(), from.y() - offsetToGlyphTop);
    778     FloatRect lastPaintedGlyphRect(from, FloatSize());
    779 
    780     while (lastPaintedGlyphRect.maxY() < to.y()) {
    781         lastPaintedGlyphRect = paintGlyph(info, m_assembly.extension, glyphOrigin, TrimTopAndBottom);
    782         glyphOrigin.setY(glyphOrigin.y() + lastPaintedGlyphRect.height());
    783 
    784         // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
    785         // with trimming. In that case we just draw nothing.
    786         if (lastPaintedGlyphRect.isEmpty())
    787             break;
    788     }
    789 }
    790 
    791 void RenderMathMLOperator::fillWithHorizontalExtensionGlyph(PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
    792 {
    793     ASSERT(!m_isVertical);
    794     ASSERT(m_stretchType == StretchType::GlyphAssembly);
    795     ASSERT(m_assembly.extension.isValid());
    796     ASSERT(from.x() <= to.x());
    797 
    798     // If there is no space for the extension glyph, we don't need to do anything.
    799     if (from.x() == to.x())
    800         return;
    801 
    802     GraphicsContextStateSaver stateSaver(info.context());
    803 
    804     // Clipping the extender region here allows us to draw the bottom extender glyph into the
    805     // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
    806     LayoutRect clipBounds = info.rect;
    807     clipBounds.shiftXEdgeTo(from.x());
    808     clipBounds.shiftMaxXEdgeTo(to.x());
    809     info.context().clip(clipBounds);
    810 
    811     // Trimming may remove up to two pixels from the left of the extender glyph, so we move it left by two pixels.
    812     float offsetToGlyphLeft = -2;
    813     LayoutPoint glyphOrigin = LayoutPoint(from.x() + offsetToGlyphLeft, std::min(from.y(), to.y()) + m_stretchHeightAboveBaseline);
    814     FloatRect lastPaintedGlyphRect(from, FloatSize());
    815 
    816     while (lastPaintedGlyphRect.maxX() < to.x()) {
    817         lastPaintedGlyphRect = paintGlyph(info, m_assembly.extension, glyphOrigin, TrimLeftAndRight);
    818         glyphOrigin.setX(glyphOrigin.x() + lastPaintedGlyphRect.width());
    819 
    820         // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
    821         // with trimming. In that case we just draw nothing.
    822         if (lastPaintedGlyphRect.isEmpty())
    823             break;
    824     }
    825 }
    826 
    827445void RenderMathMLOperator::paint(PaintInfo& info, const LayoutPoint& paintOffset)
    828446{
    829447    RenderMathMLToken::paint(info, paintOffset);
    830448
    831     if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || m_stretchType == StretchType::Unstretched)
     449    if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !m_mathOperator.isStretched())
    832450        return;
    833451
     
    835453    info.context().setFillColor(style().visitedDependentColor(CSSPropertyColor));
    836454
    837     if (m_stretchType == StretchType::SizeVariant) {
    838         ASSERT(m_variant.isValid());
     455    if (m_mathOperator.m_stretchType == MathOperator::StretchType::SizeVariant) {
     456        ASSERT(m_mathOperator.m_variant.isValid());
    839457        GlyphBuffer buffer;
    840         buffer.add(m_variant.glyph, m_variant.font, advanceWidthForGlyph(m_variant));
     458        buffer.add(m_mathOperator.m_variant.glyph, m_mathOperator.m_variant.font, advanceWidthForGlyph(m_mathOperator.m_variant));
    841459        LayoutPoint operatorTopLeft = ceiledIntPoint(paintOffset + location());
    842         FloatRect glyphBounds = boundsForGlyph(m_variant);
     460        FloatRect glyphBounds = boundsForGlyph(m_mathOperator.m_variant);
    843461        LayoutPoint operatorOrigin(operatorTopLeft.x(), operatorTopLeft.y() - glyphBounds.y());
    844         info.context().drawGlyphs(style().fontCascade(), *m_variant.font, buffer, 0, 1, operatorOrigin);
    845         return;
    846     }
    847 
    848     if (m_isVertical)
    849         paintVerticalGlyphAssembly(info, paintOffset);
    850     else
    851         paintHorizontalGlyphAssembly(info, paintOffset);
    852 }
    853 
    854 void RenderMathMLOperator::paintVerticalGlyphAssembly(PaintInfo& info, const LayoutPoint& paintOffset)
    855 {
    856     ASSERT(m_isVertical);
    857     ASSERT(m_stretchType == StretchType::GlyphAssembly);
    858     ASSERT(m_assembly.topOrRight.isValid());
    859     ASSERT(m_assembly.bottomOrLeft.isValid());
    860 
    861     // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
     462        info.context().drawGlyphs(style().fontCascade(), *m_mathOperator.m_variant.font, buffer, 0, 1, operatorOrigin);
     463        return;
     464    }
     465
     466    m_mathOperator.m_ascent = m_stretchHeightAboveBaseline;
     467    m_mathOperator.m_descent = m_stretchDepthBelowBaseline;
     468    m_mathOperator.m_width = logicalWidth();
    862469    LayoutPoint operatorTopLeft = paintOffset + location();
    863470    operatorTopLeft.move(style().isLeftToRightDirection() ? m_leadingSpace : m_trailingSpace, 0);
    864     operatorTopLeft = ceiledIntPoint(operatorTopLeft);
    865     FloatRect topGlyphBounds = boundsForGlyph(m_assembly.topOrRight);
    866     LayoutPoint topGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() - topGlyphBounds.y());
    867     LayoutRect topGlyphPaintRect = paintGlyph(info, m_assembly.topOrRight, topGlyphOrigin, TrimBottom);
    868 
    869     FloatRect bottomGlyphBounds = boundsForGlyph(m_assembly.bottomOrLeft);
    870     LayoutPoint bottomGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + offsetHeight() - (bottomGlyphBounds.height() + bottomGlyphBounds.y()));
    871     LayoutRect bottomGlyphPaintRect = paintGlyph(info, m_assembly.bottomOrLeft, bottomGlyphOrigin, TrimTop);
    872 
    873     if (m_assembly.middle.isValid()) {
    874         // Center the glyph origin between the start and end glyph paint extents. Then shift it half the paint height toward the bottom glyph.
    875         FloatRect middleGlyphBounds = boundsForGlyph(m_assembly.middle);
    876         LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), topGlyphOrigin.y());
    877         middleGlyphOrigin.moveBy(LayoutPoint(0, (bottomGlyphPaintRect.y() - topGlyphPaintRect.maxY()) / 2.0));
    878         middleGlyphOrigin.moveBy(LayoutPoint(0, middleGlyphBounds.height() / 2.0));
    879 
    880         LayoutRect middleGlyphPaintRect = paintGlyph(info, m_assembly.middle, middleGlyphOrigin, TrimTopAndBottom);
    881         fillWithVerticalExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
    882         fillWithVerticalExtensionGlyph(info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
    883     } else
    884         fillWithVerticalExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
    885 }
    886 
    887 void RenderMathMLOperator::paintHorizontalGlyphAssembly(PaintInfo& info, const LayoutPoint& paintOffset)
    888 {
    889     ASSERT(!m_isVertical);
    890     ASSERT(m_stretchType == StretchType::GlyphAssembly);
    891     ASSERT(m_assembly.bottomOrLeft.isValid());
    892     ASSERT(m_assembly.topOrRight.isValid());
    893 
    894     // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
    895     LayoutPoint operatorTopLeft = paintOffset + location();
    896     operatorTopLeft.move(m_leadingSpace, 0);
    897     operatorTopLeft = ceiledIntPoint(operatorTopLeft);
    898     LayoutPoint leftGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + m_stretchHeightAboveBaseline);
    899     LayoutRect leftGlyphPaintRect = paintGlyph(info, m_assembly.bottomOrLeft, leftGlyphOrigin, TrimRight);
    900 
    901     FloatRect rightGlyphBounds = boundsForGlyph(m_assembly.topOrRight);
    902     LayoutPoint rightGlyphOrigin(operatorTopLeft.x() + offsetWidth() - rightGlyphBounds.width(), operatorTopLeft.y() + m_stretchHeightAboveBaseline);
    903     LayoutRect rightGlyphPaintRect = paintGlyph(info, m_assembly.topOrRight, rightGlyphOrigin, TrimLeft);
    904 
    905     if (m_assembly.middle.isValid()) {
    906         // Center the glyph origin between the start and end glyph paint extents.
    907         LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), leftGlyphOrigin.y());
    908         middleGlyphOrigin.moveBy(LayoutPoint((rightGlyphPaintRect.x() - leftGlyphPaintRect.maxX()) / 2.0, 0));
    909         LayoutRect middleGlyphPaintRect = paintGlyph(info, m_assembly.middle, middleGlyphOrigin, TrimLeftAndRight);
    910         fillWithHorizontalExtensionGlyph(info, leftGlyphPaintRect.maxXMinYCorner(), middleGlyphPaintRect.minXMinYCorner());
    911         fillWithHorizontalExtensionGlyph(info, middleGlyphPaintRect.maxXMinYCorner(), rightGlyphPaintRect.minXMinYCorner());
    912     } else
    913         fillWithHorizontalExtensionGlyph(info, leftGlyphPaintRect.maxXMinYCorner(), rightGlyphPaintRect.minXMinYCorner());
     471    if (m_isVertical)
     472        m_mathOperator.paintVerticalGlyphAssembly(style(), info, operatorTopLeft);
     473    else
     474        m_mathOperator.paintHorizontalGlyphAssembly(style(), info, operatorTopLeft);
    914475}
    915476
     
    917478{
    918479    // We skip painting for invisible operators too to avoid some "missing character" glyph to appear if appropriate math fonts are not available.
    919     if (m_stretchType != StretchType::Unstretched || isInvisibleOperator())
     480    if (m_mathOperator.isStretched() || isInvisibleOperator())
    920481        return;
    921482    RenderMathMLToken::paintChildren(paintInfo, paintOffset, paintInfoForChild, usePrintRect);
     
    932493    LayoutUnit width = logicalWidth();
    933494
    934     if (m_stretchType == StretchType::Unstretched) {
     495    if (!m_mathOperator.isStretched()) {
    935496        GlyphData data = style().fontCascade().glyphDataForCharacter(textContent(), !style().isLeftToRightDirection());
    936497        return width - advanceWidthForGlyph(data);
    937498    }
    938499
    939     if (m_stretchType == StretchType::SizeVariant)
    940         return width - advanceWidthForGlyph(m_variant);
    941 
    942     float assemblyWidth = advanceWidthForGlyph(m_assembly.topOrRight);
    943     assemblyWidth = std::max(assemblyWidth, advanceWidthForGlyph(m_assembly.bottomOrLeft));
    944     assemblyWidth = std::max(assemblyWidth, advanceWidthForGlyph(m_assembly.extension));
    945     if (m_assembly.middle.isValid())
    946         assemblyWidth = std::max(assemblyWidth, advanceWidthForGlyph(m_assembly.middle));
     500    if (m_mathOperator.m_stretchType == MathOperator::StretchType::SizeVariant)
     501        return width - advanceWidthForGlyph(m_mathOperator.m_variant);
     502
     503    float assemblyWidth = advanceWidthForGlyph(m_mathOperator.m_assembly.topOrRight);
     504    assemblyWidth = std::max(assemblyWidth, advanceWidthForGlyph(m_mathOperator.m_assembly.bottomOrLeft));
     505    assemblyWidth = std::max(assemblyWidth, advanceWidthForGlyph(m_mathOperator.m_assembly.extension));
     506    if (m_mathOperator.m_assembly.middle.isValid())
     507        assemblyWidth = std::max(assemblyWidth, advanceWidthForGlyph(m_mathOperator.m_assembly.middle));
    947508    return width - assemblyWidth;
    948509}
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.h

    r200569 r201854  
    3333#include "MathMLElement.h"
    3434#include "MathMLOperatorDictionary.h"
     35#include "MathOperator.h"
    3536#include "OpenTypeMathData.h"
    3637#include "RenderMathMLToken.h"
     
    5253    bool isLargeOperatorInDisplayStyle() const { return !hasOperatorFlag(MathMLOperatorDictionary::Stretchy) && hasOperatorFlag(MathMLOperatorDictionary::LargeOp); }
    5354    bool isVertical() const { return m_isVertical; }
    54     LayoutUnit italicCorrection() const { return m_italicCorrection; }
     55    LayoutUnit italicCorrection() const { return m_mathOperator.italicCorrection(); }
    5556
    5657    void styleDidChange(StyleDifference, const RenderStyle* oldStyle) final;
     
    7475
    7576private:
    76     struct GlyphAssemblyData {
    77         GlyphData topOrRight;
    78         GlyphData extension;
    79         GlyphData bottomOrLeft;
    80         GlyphData middle;
    81     };
    82     enum class StretchType { Unstretched, SizeVariant, GlyphAssembly };
    83     StretchType m_stretchType;
    84     union {
    85         GlyphData m_variant;
    86         GlyphAssemblyData m_assembly;
    87     };
    88     LayoutUnit m_italicCorrection;
    89 
    9077    const char* renderName() const override { return isAnonymous() ? "RenderMathMLOperator (anonymous)" : "RenderMathMLOperator"; }
    9178    void paintChildren(PaintInfo& forSelf, const LayoutPoint&, PaintInfo& forChild, bool usePrintRect) final;
     
    10188    bool shouldAllowStretching() const;
    10289
    103     bool getBaseGlyph(const RenderStyle&, GlyphData&) const;
    104     void setSizeVariant(const GlyphData&);
    105     void setGlyphAssembly(const GlyphAssemblyData&);
    106     bool calculateGlyphAssemblyFallBack(const Vector<OpenTypeMathData::AssemblyPart>&, GlyphAssemblyData&) const;
    107     void calculateDisplayStyleLargeOperator();
    108     void calculateStretchyData(float* maximumGlyphWidth, LayoutUnit targetSize = 0);
    109 
    110     enum GlyphPaintTrimming {
    111         TrimTop,
    112         TrimBottom,
    113         TrimTopAndBottom,
    114         TrimLeft,
    115         TrimRight,
    116         TrimLeftAndRight
    117     };
    118 
    119     LayoutRect paintGlyph(PaintInfo&, const GlyphData&, const LayoutPoint& origin, GlyphPaintTrimming);
    120     void fillWithVerticalExtensionGlyph(PaintInfo&, const LayoutPoint& from, const LayoutPoint& to);
    121     void fillWithHorizontalExtensionGlyph(PaintInfo&, const LayoutPoint& from, const LayoutPoint& to);
    122     void paintVerticalGlyphAssembly(PaintInfo&, const LayoutPoint&);
    123     void paintHorizontalGlyphAssembly(PaintInfo&, const LayoutPoint&);
    12490    void setOperatorFlagFromAttribute(MathMLOperatorDictionary::Flag, const QualifiedName&);
    12591    void setOperatorFlagFromAttributeValue(MathMLOperatorDictionary::Flag, const AtomicString& attributeValue);
     
    138104    LayoutUnit m_minSize;
    139105    LayoutUnit m_maxSize;
     106    MathOperator m_mathOperator;
    140107};
    141108
Note: See TracChangeset for help on using the changeset viewer.