Changeset 169305 in webkit


Ignore:
Timestamp:
May 23, 2014 9:56:50 PM (10 years ago)
Author:
fred.wang@free.fr
Message:

Use size variants and glyph assembly from the MATH data.
https://bugs.webkit.org/show_bug.cgi?id=130322

Reviewed by Chris Fleizach.

Source/WebCore:
This patch modifies the RenderMathMLOperator code to use the MATH table
when one is provided in the current font on the <math> tag. More
precisely, the MathVariants table is used to draw a size variant or
a glyph assembly. The displaystyle attribute is not supported yet, so
for now large operators are always assumed to be in display style. The
MATH support does not work well with all platforms+fonts, so at the
moment the default font-family on the <math> is not changed.

Tests: mathml/opentype/large-operators-LatinModern.html

mathml/opentype/opentype-stretchy.html
mathml/opentype/vertical-LatinModern.html

  • css/mathml.css: We only specify the default font-family on the math root, so that people can easily style the mathematics.

For now, old fonts without the MATH table are still used as the default.
(math):
(math, mfenced > *): Deleted.
(mo, mfenced): Deleted.

  • platform/graphics/SimpleFontData.cpp: don't return the math data if the font is loading.

(WebCore::SimpleFontData::mathData):

  • platform/graphics/opentype/OpenTypeMathData.cpp: update #ifdef so that disabling ENABLE_OPENTYPE_MATH won't lead to errors with unused parameters.

(WebCore::OpenTypeMathData::OpenTypeMathData):
(WebCore::OpenTypeMathData::getMathConstant):
(WebCore::OpenTypeMathData::getItalicCorrection):
(WebCore::OpenTypeMathData::getMathVariants):

  • rendering/mathml/RenderMathMLOperator.cpp:

(WebCore::RenderMathMLOperator::boundsForGlyph):
(WebCore::RenderMathMLOperator::heightForGlyph):
(WebCore::RenderMathMLOperator::advanceForGlyph):
(WebCore::RenderMathMLOperator::computePreferredLogicalWidths): We handle preferred width of size variants.
(WebCore::RenderMathMLOperator::shouldAllowStretching): This function now only returns whether the operator will stretch and no longer has side effect.
(WebCore::RenderMathMLOperator::getGlyphAssemblyFallBack): We add a function to convert from the MathVariant table data to the format supported by RenderMathMLOperator.
(WebCore::RenderMathMLOperator::getDisplayStyleLargeOperator): We add a function to get the glyph that will be used for large operators in display style.
(WebCore::RenderMathMLOperator::findStretchyData): We make this function handle size variants.
(WebCore::RenderMathMLOperator::updateStyle): We handle size variants.
(WebCore::RenderMathMLOperator::paint): We handle size variants.

  • rendering/mathml/RenderMathMLOperator.h:

LayoutTests:
This adds some pixel tests for large operators and vertical stretchy operators.

  • mathml/opentype/LICENSE-LatinModern.txt: Added.
  • mathml/opentype/large-operators-LatinModern.html: Added.
  • mathml/opentype/latinmodern-math.woff: Added.
  • mathml/opentype/opentype-stretchy.html: Added.
  • mathml/opentype/stretchy.woff: Added.
  • mathml/opentype/vertical-LatinModern.html: Added.
  • platform/efl/mathml/opentype/large-operators-LatinModern-expected.png: Added.
  • platform/efl/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
  • platform/efl/mathml/opentype/opentype-stretchy-expected.png: Added.
  • platform/efl/mathml/opentype/opentype-stretchy-expected.txt: Added.
  • platform/efl/mathml/opentype/vertical-LatinModern-expected.png: Added.
  • platform/efl/mathml/opentype/vertical-LatinModern-expected.txt: Added.
  • platform/gtk/mathml/opentype/large-operators-LatinModern-expected.png: Added.
  • platform/gtk/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
  • platform/gtk/mathml/opentype/opentype-stretchy-expected.png: Added.
  • platform/gtk/mathml/opentype/opentype-stretchy-expected.txt: Added.
  • platform/gtk/mathml/opentype/vertical-LatinModern-expected.png: Added.
  • platform/gtk/mathml/opentype/vertical-LatinModern-expected.txt: Added.
  • platform/gtk/mathml/presentation/mo-stretch-expected.png: update reference due to change in mathml.css
  • platform/gtk/mathml/presentation/mo-stretch-expected.txt: ditto
  • platform/mac/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
  • platform/mac/mathml/opentype/opentype-stretchy-expected.txt: Added.
  • platform/mac/mathml/opentype/vertical-LatinModern-expected.txt: Added.
  • platform/mac-wk2/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
  • platform/mac-wk2/mathml/opentype/opentype-stretchy-expected.txt: Added.
  • platform/mac-wk2/mathml/opentype/vertical-LatinModern-expected.txt: Added.
  • platform/win/TestExpectations: Mark the OpenType MATH tests as failing
Location:
trunk
Files:
30 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r169298 r169305  
     12014-05-24  Frédéric Wang  <fred.wang@free.fr>
     2
     3        Use size variants and glyph assembly from the MATH data.
     4        https://bugs.webkit.org/show_bug.cgi?id=130322
     5
     6        Reviewed by Chris Fleizach.
     7
     8        This adds some pixel tests for large operators and vertical stretchy operators.
     9
     10        * mathml/opentype/LICENSE-LatinModern.txt: Added.
     11        * mathml/opentype/large-operators-LatinModern.html: Added.
     12        * mathml/opentype/latinmodern-math.woff: Added.
     13        * mathml/opentype/opentype-stretchy.html: Added.
     14        * mathml/opentype/stretchy.woff: Added.
     15        * mathml/opentype/vertical-LatinModern.html: Added.
     16        * platform/efl/mathml/opentype/large-operators-LatinModern-expected.png: Added.
     17        * platform/efl/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
     18        * platform/efl/mathml/opentype/opentype-stretchy-expected.png: Added.
     19        * platform/efl/mathml/opentype/opentype-stretchy-expected.txt: Added.
     20        * platform/efl/mathml/opentype/vertical-LatinModern-expected.png: Added.
     21        * platform/efl/mathml/opentype/vertical-LatinModern-expected.txt: Added.
     22        * platform/gtk/mathml/opentype/large-operators-LatinModern-expected.png: Added.
     23        * platform/gtk/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
     24        * platform/gtk/mathml/opentype/opentype-stretchy-expected.png: Added.
     25        * platform/gtk/mathml/opentype/opentype-stretchy-expected.txt: Added.
     26        * platform/gtk/mathml/opentype/vertical-LatinModern-expected.png: Added.
     27        * platform/gtk/mathml/opentype/vertical-LatinModern-expected.txt: Added.
     28        * platform/gtk/mathml/presentation/mo-stretch-expected.png: update reference due to change in mathml.css
     29        * platform/gtk/mathml/presentation/mo-stretch-expected.txt: ditto
     30        * platform/mac/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
     31        * platform/mac/mathml/opentype/opentype-stretchy-expected.txt: Added.
     32        * platform/mac/mathml/opentype/vertical-LatinModern-expected.txt: Added.
     33        * platform/mac-wk2/mathml/opentype/large-operators-LatinModern-expected.txt: Added.
     34        * platform/mac-wk2/mathml/opentype/opentype-stretchy-expected.txt: Added.
     35        * platform/mac-wk2/mathml/opentype/vertical-LatinModern-expected.txt: Added.
     36        * platform/win/TestExpectations: Mark the OpenType MATH tests as failing
     37
    1382014-05-23  Yusuke Suzuki  <utatane.tea@gmail.com>
    239
  • trunk/LayoutTests/platform/gtk/mathml/presentation/mo-stretch-expected.txt

    r168677 r169305  
    11layer at (0,0) size 800x600
    22  RenderView at (0,0) size 800x600
    3 layer at (0,0) size 800x256
    4   RenderBlock {HTML} at (0,0) size 800x256
    5     RenderBody {BODY} at (8,8) size 784x240
    6       RenderMathMLMath {math} at (0,0) size 126x20 [padding: 0 1 0 1]
    7         RenderMathMLRow {mrow} at (1,0) size 124x20
    8           RenderMathMLOperator {mo} at (0,3) size 7x14
     3layer at (0,0) size 800x260
     4  RenderBlock {HTML} at (0,0) size 800x260
     5    RenderBody {BODY} at (8,8) size 784x244
     6      RenderMathMLMath {math} at (0,0) size 126x24 [padding: 0 1 0 1]
     7        RenderMathMLRow {mrow} at (1,0) size 124x24
     8          RenderMathMLOperator {mo} at (0,5) size 7x14
    99            RenderMathMLBlock (anonymous, flex) at (0,0) size 7x14
    1010              RenderBlock (anonymous) at (0,0) size 5x14
    1111                RenderText at (0,-6) size 5x25
    1212                  text run at (0,-6) width 5: "("
    13           RenderMathMLOperator {mo} at (7,3) size 7x14
     13          RenderMathMLOperator {mo} at (7,5) size 7x14
    1414            RenderMathMLBlock (anonymous, flex) at (0,0) size 7x14
    1515              RenderBlock (anonymous) at (0,0) size 5x14
    1616                RenderText at (0,-6) size 5x25
    1717                  text run at (0,-6) width 5: ")"
    18           RenderMathMLOperator {mo} at (14,3) size 10x14
     18          RenderMathMLOperator {mo} at (14,5) size 10x14
    1919            RenderMathMLBlock (anonymous, flex) at (0,0) size 10x14
    2020              RenderBlock (anonymous) at (0,0) size 8x14
    2121                RenderText at (0,-6) size 8x25
    2222                  text run at (0,-6) width 8: "{"
    23           RenderMathMLOperator {mo} at (24,3) size 10x14
     23          RenderMathMLOperator {mo} at (24,5) size 10x14
    2424            RenderMathMLBlock (anonymous, flex) at (0,0) size 10x14
    2525              RenderBlock (anonymous) at (0,0) size 8x14
    2626                RenderText at (0,-6) size 8x25
    2727                  text run at (0,-6) width 8: "}"
    28           RenderMathMLOperator {mo} at (34,3) size 7x14
     28          RenderMathMLOperator {mo} at (34,5) size 7x14
    2929            RenderMathMLBlock (anonymous, flex) at (0,0) size 7x14
    3030              RenderBlock (anonymous) at (0,0) size 5x14
    3131                RenderText at (0,-6) size 5x25
    3232                  text run at (0,-6) width 5: "["
    33           RenderMathMLOperator {mo} at (41,3) size 7x14
     33          RenderMathMLOperator {mo} at (41,5) size 7x14
    3434            RenderMathMLBlock (anonymous, flex) at (0,0) size 7x14
    3535              RenderBlock (anonymous) at (0,0) size 5x14
    3636                RenderText at (0,-6) size 5x25
    3737                  text run at (0,-6) width 5: "]"
    38           RenderMathMLOperator {mo} at (48,2) size 8x16
     38          RenderMathMLOperator {mo} at (48,4) size 8x16
    3939            RenderMathMLBlock (anonymous, flex) at (0,0) size 8x16
    4040              RenderBlock (anonymous) at (0,0) size 8x16
    4141                RenderText at (0,-5) size 8x25
    4242                  text run at (0,-5) width 8: "\x{2308}"
    43           RenderMathMLOperator {mo} at (56,2) size 8x16
     43          RenderMathMLOperator {mo} at (56,4) size 8x16
    4444            RenderMathMLBlock (anonymous, flex) at (0,0) size 8x16
    4545              RenderBlock (anonymous) at (0,0) size 8x16
    4646                RenderText at (0,-5) size 8x25
    4747                  text run at (0,-5) width 8: "\x{2309}"
    48           RenderMathMLOperator {mo} at (64,2) size 8x16
     48          RenderMathMLOperator {mo} at (64,4) size 8x16
    4949            RenderMathMLBlock (anonymous, flex) at (0,0) size 8x16
    5050              RenderBlock (anonymous) at (0,0) size 8x16
    5151                RenderText at (0,-5) size 8x25
    5252                  text run at (0,-5) width 8: "\x{230A}"
    53           RenderMathMLOperator {mo} at (72,2) size 8x16
     53          RenderMathMLOperator {mo} at (72,4) size 8x16
    5454            RenderMathMLBlock (anonymous, flex) at (0,0) size 8x16
    5555              RenderBlock (anonymous) at (0,0) size 8x16
    5656                RenderText at (0,-5) size 8x25
    5757                  text run at (0,-5) width 8: "\x{230B}"
    58           RenderMathMLOperator {mo} at (80,0) size 12x20
     58          RenderMathMLOperator {mo} at (80,2) size 12x20
    5959            RenderMathMLBlock (anonymous, flex) at (0,0) size 11x20
    6060              RenderBlock (anonymous) at (0,0) size 7x20
    6161                RenderText at (0,-3) size 7x25
    6262                  text run at (0,-3) width 7: "\x{222B}"
    63           RenderMathMLOperator {mo} at (91,3) size 8x12
     63          RenderMathMLOperator {mo} at (91,0) size 8x24
    6464            RenderMathMLBlock (anonymous, flex) at (1,0) size 4x12
    6565              RenderBlock (anonymous) at (0,0) size 3x12
    6666                RenderText at (0,-6) size 3x25
    6767                  text run at (0,-6) width 3: "|"
    68           RenderMathMLOperator {mo} at (98,2) size 9x16
     68          RenderMathMLOperator {mo} at (98,4) size 9x16
    6969            RenderMathMLBlock (anonymous, flex) at (0,0) size 8x16
    7070              RenderBlock (anonymous) at (0,0) size 8x16
    7171                RenderText at (0,-5) size 8x25
    7272                  text run at (0,-5) width 8: "\x{2016}"
    73           RenderMathMLOperator {mo} at (106,2) size 18x16
     73          RenderMathMLOperator {mo} at (106,4) size 18x16
    7474            RenderMathMLBlock (anonymous, flex) at (4,0) size 9x16
    7575              RenderBlock (anonymous) at (0,0) size 8x16
    7676                RenderText at (0,-5) size 8x25
    7777                  text run at (0,-5) width 8: "\x{2225}"
    78       RenderText {#text} at (125,0) size 5x17
    79         text run at (125,0) width 5: " "
     78      RenderText {#text} at (125,2) size 5x17
     79        text run at (125,2) width 5: " "
    8080      RenderBR {BR} at (0,0) size 0x0
    81       RenderMathMLMath {math} at (0,20) size 126x142 [padding: 0 1 0 1]
     81      RenderMathMLMath {math} at (0,24) size 126x142 [padding: 0 1 0 1]
    8282        RenderMathMLRow {mrow} at (1,0) size 124x142
    8383          RenderMathMLOperator {mo} at (0,0) size 7x142
  • trunk/LayoutTests/platform/win/TestExpectations

    r168426 r169305  
    27452745fast/canvas/canvas-path-addPath.html [ Crash ]
    27462746
     2747# Missing references on Windows
     2748webkit.org/b/130322 mathml/opentype/large-operators-LatinModern.html [ Failure ]
     2749webkit.org/b/130322 mathml/opentype/opentype-stretchy.html [ Failure ]
     2750webkit.org/b/130322 mathml/opentype/vertical-LatinModern.html [ Failure ]
  • trunk/Source/WebCore/ChangeLog

    r169299 r169305  
     12014-05-24  Frédéric Wang  <fred.wang@free.fr>
     2
     3        Use size variants and glyph assembly from the MATH data.
     4        https://bugs.webkit.org/show_bug.cgi?id=130322
     5
     6        Reviewed by Chris Fleizach.
     7
     8        This patch modifies the RenderMathMLOperator code to use the MATH table
     9        when one is provided in the current font on the <math> tag. More
     10        precisely, the MathVariants table is used to draw a size variant or
     11        a glyph assembly. The displaystyle attribute is not supported yet, so
     12        for now large operators are always assumed to be in display style. The
     13        MATH support does not work well with all platforms+fonts, so at the
     14        moment the default font-family on the <math> is not changed.
     15
     16        Tests: mathml/opentype/large-operators-LatinModern.html
     17               mathml/opentype/opentype-stretchy.html
     18               mathml/opentype/vertical-LatinModern.html
     19
     20        * css/mathml.css: We only specify the default font-family on the math root, so that people can easily style the mathematics.
     21        For now, old fonts without the MATH table are still used as the default.
     22        (math):
     23        (math, mfenced > *): Deleted.
     24        (mo, mfenced): Deleted.
     25        * platform/graphics/SimpleFontData.cpp: don't return the math data if the font is loading.
     26        (WebCore::SimpleFontData::mathData):
     27        * platform/graphics/opentype/OpenTypeMathData.cpp: update #ifdef so that disabling ENABLE_OPENTYPE_MATH won't lead to errors with unused parameters.
     28        (WebCore::OpenTypeMathData::OpenTypeMathData):
     29        (WebCore::OpenTypeMathData::getMathConstant):
     30        (WebCore::OpenTypeMathData::getItalicCorrection):
     31        (WebCore::OpenTypeMathData::getMathVariants):
     32        * rendering/mathml/RenderMathMLOperator.cpp:
     33        (WebCore::RenderMathMLOperator::boundsForGlyph):
     34        (WebCore::RenderMathMLOperator::heightForGlyph):
     35        (WebCore::RenderMathMLOperator::advanceForGlyph):
     36        (WebCore::RenderMathMLOperator::computePreferredLogicalWidths): We handle preferred width of size variants.
     37        (WebCore::RenderMathMLOperator::shouldAllowStretching): This function now only returns whether the operator will stretch and no longer has side effect.
     38        (WebCore::RenderMathMLOperator::getGlyphAssemblyFallBack): We add a function to convert from the MathVariant table data to the format supported by RenderMathMLOperator.
     39        (WebCore::RenderMathMLOperator::getDisplayStyleLargeOperator): We add a function to get the glyph that will be used for large operators in display style.
     40        (WebCore::RenderMathMLOperator::findStretchyData): We make this function handle size variants.
     41        (WebCore::RenderMathMLOperator::updateStyle): We handle size variants.
     42        (WebCore::RenderMathMLOperator::paint): We handle size variants.
     43        * rendering/mathml/RenderMathMLOperator.h:
     44
    1452014-05-23  Tim Horton  <timothy_horton@apple.com>
    246
  • trunk/Source/WebCore/css/mathml.css

    r165461 r169305  
    1111
    1212/* Keep font-family and other defaults here consistent with http://mxr.mozilla.org/mozilla-central/source/layout/mathml/mathml.css and feedback from www-math. */
    13 math, mfenced > * {
     13math {
    1414#if defined(WTF_PLATFORM_IOS) && WTF_PLATFORM_IOS
    1515    /* We explicitly include the font Symbol as it's the iOS equivalent of font STIXGeneral. */
    1616    font-family: STIXGeneral, Symbol, "Times New Roman", sans-serif;
    1717#else
    18     font-family: MathJax_Main, STIXGeneral, "DejaVu Serif", Cambria, "Cambria Math", Times, serif;
    19 #endif
    20 }
    21 mo, mfenced {
    22 #if defined(WTF_PLATFORM_IOS) && WTF_PLATFORM_IOS
    23     /* We explicitly include the font Symbol as it's the iOS equivalent of font STIXGeneral. */
    24     font-family: STIXGeneral, Symbol, "Times New Roman", sans-serif;
    25 #else
    26     font-family: MathJax_Main, STIXGeneral, STIXSizeOneSym, "DejaVu Sans", "DejaVu Serif", Cambria, "Cambria Math",
    27         "Lucida Sans Unicode", "Arial Unicode MS", "Lucida Grande", OpenSymbol, "Standard Symbols L", sans-serif;
     18    font-family: MathJax_Main, STIXGeneral, STIXSizeOneSym, "DejaVu Sans", "DejaVu Serif", Cambria, "Cambria Math", "Lucida Sans Unicode", "Arial Unicode MS", "Lucida Grande", OpenSymbol, "Standard Symbols L", Times, serif;
    2819#endif
    2920}
  • trunk/Source/WebCore/platform/graphics/SimpleFontData.cpp

    r166633 r169305  
    262262const OpenTypeMathData* SimpleFontData::mathData() const
    263263{
     264    if (m_isLoading)
     265        return nullptr;
    264266    if (!m_mathData) {
    265267        m_mathData = OpenTypeMathData::create(m_platformData);
  • trunk/Source/WebCore/platform/graphics/opentype/OpenTypeMathData.cpp

    r166640 r169305  
    230230#endif // ENABLE(OPENTYPE_MATH)
    231231
     232#if ENABLE(OPENTYPE_MATH)
    232233OpenTypeMathData::OpenTypeMathData(const FontPlatformData& fontData)
    233234{
    234 #if ENABLE(OPENTYPE_MATH)
    235235    m_mathBuffer = fontData.openTypeTable(OpenType::MATHTag);
    236236    const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
     
    250250        m_mathBuffer = nullptr;
    251251#else
     252OpenTypeMathData::OpenTypeMathData(const FontPlatformData&)
     253{
    252254    m_mathBuffer = nullptr;
    253255#endif
    254256}
    255257
     258#if ENABLE(OPENTYPE_MATH)
    256259float OpenTypeMathData::getMathConstant(const SimpleFontData* font, MathConstant constant) const
    257260{
    258 #if ENABLE(OPENTYPE_MATH)
    259261    int32_t value = 0;
    260262
     
    278280    return value * font->sizePerUnit();
    279281#else
     282float OpenTypeMathData::getMathConstant(const SimpleFontData*, MathConstant) const
     283{
    280284    ASSERT_NOT_REACHED();
    281285    return 0;
     
    283287}
    284288
     289#if ENABLE(OPENTYPE_MATH)
    285290float OpenTypeMathData::getItalicCorrection(const SimpleFontData* font, Glyph glyph) const
    286291{
    287 #if ENABLE(OPENTYPE_MATH)
    288292    const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
    289293    ASSERT(math);
     
    298302    return mathItalicsCorrectionInfo->getItalicCorrection(*m_mathBuffer, glyph) * font->sizePerUnit();
    299303#else
     304float OpenTypeMathData::getItalicCorrection(const SimpleFontData*, Glyph) const
     305{
    300306    ASSERT_NOT_REACHED();
    301307    return 0;
     
    303309}
    304310
     311#if ENABLE(OPENTYPE_MATH)
    305312void OpenTypeMathData::getMathVariants(Glyph glyph, bool isVertical, Vector<Glyph>& sizeVariants, Vector<AssemblyPart>& assemblyParts) const
    306313{
    307314    sizeVariants.clear();
    308315    assemblyParts.clear();
    309 #if ENABLE(OPENTYPE_MATH)
    310316    const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
    311317    ASSERT(math);
     
    320326    mathGlyphConstruction->getAssemblyParts(*m_mathBuffer, assemblyParts);
    321327#else
     328void OpenTypeMathData::getMathVariants(Glyph, bool, Vector<Glyph>&, Vector<AssemblyPart>&) const
     329{
    322330    ASSERT_NOT_REACHED();
    323331#endif
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp

    r166170 r169305  
    2626 */
    2727
     28#define _USE_MATH_DEFINES 1
    2829#include "config.h"
    2930
     
    12831284}
    12841285
    1285 FloatRect RenderMathMLOperator::boundsForGlyph(const GlyphData& data)
     1286FloatRect RenderMathMLOperator::boundsForGlyph(const GlyphData& data) const
    12861287{
    12871288    return data.fontData->boundsForGlyph(data.glyph);
    12881289}
    12891290
    1290 float RenderMathMLOperator::heightForGlyph(const GlyphData& data)
     1291float RenderMathMLOperator::heightForGlyph(const GlyphData& data) const
    12911292{
    12921293    return boundsForGlyph(data).height();
    12931294}
    12941295
    1295 float RenderMathMLOperator::advanceForGlyph(const GlyphData& data)
     1296float RenderMathMLOperator::advanceForGlyph(const GlyphData& data) const
    12961297{
    12971298    return data.fontData->widthForGlyph(data.glyph);
     
    13031304
    13041305    SetOperatorProperties();
    1305     UChar stretchedCharacter;
    1306     bool allowStretching = shouldAllowStretching(stretchedCharacter);
    1307     if (!allowStretching) {
     1306    if (!shouldAllowStretching()) {
    13081307        RenderMathMLToken::computePreferredLogicalWidths();
    13091308        if (isInvisibleOperator()) {
     
    13181317    }
    13191318
    1320     GlyphData data = style().font().glyphDataForCharacter(stretchedCharacter, false);
     1319    GlyphData data = style().font().glyphDataForCharacter(m_operator, false);
    13211320    float maximumGlyphWidth = advanceForGlyph(data);
    1322     findStretchyData(stretchedCharacter, &maximumGlyphWidth);
     1321    if (isLargeOperatorInDisplayStyle()) {
     1322        // 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/).
     1323        StretchyData largeOperator = getDisplayStyleLargeOperator(m_operator);
     1324        if (largeOperator.mode() == DrawSizeVariant)
     1325            maximumGlyphWidth = boundsForGlyph(largeOperator.variant()).width();
     1326    } else {
     1327        // 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).
     1328        findStretchyData(m_operator, &maximumGlyphWidth);
     1329    }
    13231330    m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth = m_leadingSpace + maximumGlyphWidth + m_trailingSpace;
    13241331}
     
    13721379}
    13731380
    1374 bool RenderMathMLOperator::shouldAllowStretching(UChar& stretchedCharacter)
    1375 {
    1376     if (!hasOperatorFlag(MathMLOperatorDictionary::Stretchy))
    1377         return false;
    1378 
    1379     stretchedCharacter = m_operator;
    1380     return stretchedCharacter;
    1381 }
    1382 
    1383 // FIXME: We should also look at alternate characters defined in the OpenType MATH table (http://wkbug/122297).
    1384 RenderMathMLOperator::StretchyData RenderMathMLOperator::findStretchyData(UChar character, float* maximumGlyphWidth)
    1385 {
    1386     // FIXME: This function should first try size variants.
    1387     StretchyData data;
    1388 
    1389     const StretchyCharacter* stretchyCharacter = 0;
    1390     const int maxIndex = WTF_ARRAY_LENGTH(stretchyCharacters);
    1391     for (int index = 0; index < maxIndex; ++index) {
    1392         if (stretchyCharacters[index].character == character) {
    1393             stretchyCharacter = &stretchyCharacters[index];
    1394             break;
     1381bool RenderMathMLOperator::shouldAllowStretching() const
     1382{
     1383    return m_operator && (hasOperatorFlag(MathMLOperatorDictionary::Stretchy) || isLargeOperatorInDisplayStyle());
     1384}
     1385
     1386bool RenderMathMLOperator::getGlyphAssemblyFallBack(Vector<OpenTypeMathData::AssemblyPart> assemblyParts, StretchyData& stretchyData) const
     1387{
     1388    GlyphData top;
     1389    GlyphData extension;
     1390    GlyphData bottom;
     1391    GlyphData middle;
     1392
     1393    // 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.
     1394    // FIXME: RenderMathMLOperator should support the most general format (https://bugs.webkit.org/show_bug.cgi?id=130327).
     1395    // We use the approach of the copyComponents function in github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py
     1396
     1397    // We count the number of non extender pieces.
     1398    int nonExtenderCount = 0;
     1399    for (auto& part : assemblyParts) {
     1400        if (!part.isExtender)
     1401            nonExtenderCount++;
     1402    }
     1403    if (nonExtenderCount > 3)
     1404        return false; // This is not supported: there are too many pieces.
     1405
     1406    // We now browse the list of pieces.
     1407    // 1 = look for a left/bottom glyph
     1408    // 2 = look for an extender between left/bottom and mid
     1409    // 4 = look for a middle glyph
     1410    // 5 = look for an extender between middle and right/top
     1411    // 5 = look for a right/top glyph
     1412    // 6 = no more piece expected
     1413    unsigned state = 1;
     1414
     1415    extension.glyph = 0;
     1416    middle.glyph = 0;
     1417    for (auto& part : assemblyParts) {
     1418        if ((state == 2 || state == 3) && nonExtenderCount < 3) {
     1419            // We do not try to find a middle glyph.
     1420            state += 2;
     1421        }
     1422        if (part.isExtender) {
     1423            if (!extension.glyph)
     1424                extension.glyph = part.glyph;
     1425            else if (extension.glyph != part.glyph)
     1426                return false; // This is not supported: the assembly has different extenders.
     1427
     1428            if (state == 1) {
     1429                // We ignore left/bottom piece and multiple successive extenders.
     1430                state = 2;
     1431            } else if (state == 3) {
     1432                // We ignore middle piece and multiple successive extenders.
     1433                state = 4;
     1434            } else if (state >= 5)
     1435                return false; // This is not supported: we got an unexpected extender.
     1436            continue;
     1437        }
     1438
     1439        if (state == 1) {
     1440            // We copy the left/bottom part.
     1441            bottom.glyph = part.glyph;
     1442            state = 2;
     1443            continue;
     1444        }
     1445
     1446        if (state == 2 || state == 3) {
     1447            // We copy the middle part.
     1448            middle.glyph = part.glyph;
     1449            state = 4;
     1450            continue;
     1451        }
     1452
     1453        if (state == 4 || state == 5) {
     1454            // We copy the right/top part.
     1455            top.glyph = part.glyph;
     1456            state = 6;
    13951457        }
    13961458    }
    13971459
    1398     // If we didn't find a stretchy character set for this character, we don't know how to stretch it.
    1399     if (!stretchyCharacter)
     1460    if (!extension.glyph)
     1461        return false; // This is not supported: we always assume that we have an extension glyph.
     1462
     1463    // If we don't have top/bottom glyphs, we use the extension glyph.
     1464    if (!top.glyph)
     1465        top.glyph = extension.glyph;
     1466    if (!bottom.glyph)
     1467        bottom.glyph = extension.glyph;
     1468
     1469    top.fontData = style().font().primaryFont();
     1470    extension.fontData = top.fontData;
     1471    bottom.fontData = top.fontData;
     1472    if (middle.glyph)
     1473        middle.fontData = top.fontData;
     1474
     1475    stretchyData.setGlyphAssemblyMode(top, extension, bottom, middle);
     1476
     1477    return true;
     1478}
     1479
     1480RenderMathMLOperator::StretchyData RenderMathMLOperator::getDisplayStyleLargeOperator(UChar character) const
     1481{
     1482    StretchyData data;
     1483
     1484    ASSERT(isLargeOperatorInDisplayStyle());
     1485
     1486    const auto& primaryFontData = style().font().primaryFont();
     1487    GlyphData baseGlyph = style().font().glyphDataForCharacter(character, false);
     1488    if (!primaryFontData || !primaryFontData->mathData() || baseGlyph.fontData != primaryFontData)
    14001489        return data;
    14011490
    1402     // We convert the list of Unicode characters into a list of glyph data.
    1403     GlyphData top = style().font().glyphDataForCharacter(stretchyCharacter->topChar, false);
    1404     GlyphData extension = style().font().glyphDataForCharacter(stretchyCharacter->extensionChar, false);
    1405     GlyphData bottom = style().font().glyphDataForCharacter(stretchyCharacter->bottomChar, false);
    1406     GlyphData middle;
    1407     if (stretchyCharacter->middleChar)
    1408         middle = style().font().glyphDataForCharacter(stretchyCharacter->middleChar, false);
     1491    Vector<Glyph> sizeVariants;
     1492    Vector<OpenTypeMathData::AssemblyPart> assemblyParts;
     1493
     1494    // 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.
     1495    float displayOperatorMinHeight = std::max(baseGlyph.fontData->boundsForGlyph(baseGlyph.glyph).height() * float(M_SQRT2), primaryFontData->mathData()->getMathConstant(primaryFontData, OpenTypeMathData::DisplayOperatorMinHeight));
     1496
     1497    primaryFontData->mathData()->getMathVariants(baseGlyph.glyph, true, sizeVariants, assemblyParts);
     1498
     1499    // We choose the first size variant that is larger than the expected displayOperatorMinHeight and otherwise fallback to the largest variant.
     1500    for (auto& variant : sizeVariants) {
     1501        GlyphData sizeVariant;
     1502        sizeVariant.glyph = variant;
     1503        sizeVariant.fontData = primaryFontData;
     1504        data.setSizeVariantMode(sizeVariant);
     1505        if (boundsForGlyph(sizeVariant).height() >= displayOperatorMinHeight)
     1506            return data;
     1507    }
     1508    return data;
     1509}
     1510
     1511RenderMathMLOperator::StretchyData RenderMathMLOperator::findStretchyData(UChar character, float* maximumGlyphWidth)
     1512{
     1513    StretchyData data;
     1514    StretchyData assemblyData;
     1515
     1516    const auto& primaryFontData = style().font().primaryFont();
     1517    GlyphData baseGlyph = style().font().glyphDataForCharacter(character, false);
     1518   
     1519    if (primaryFontData && primaryFontData->mathData() && baseGlyph.fontData == primaryFontData) {
     1520        Vector<Glyph> sizeVariants;
     1521        Vector<OpenTypeMathData::AssemblyPart> assemblyParts;
     1522        primaryFontData->mathData()->getMathVariants(baseGlyph.glyph, true, sizeVariants, assemblyParts);
     1523        // We verify the size variants.
     1524        for (auto& variant : sizeVariants) {
     1525            GlyphData sizeVariant;
     1526            sizeVariant.glyph = variant;
     1527            sizeVariant.fontData = primaryFontData;
     1528            if (maximumGlyphWidth)
     1529                *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(sizeVariant));
     1530            else {
     1531                data.setSizeVariantMode(sizeVariant);
     1532                if (heightForGlyph(sizeVariant) >= stretchSize())
     1533                    return data;
     1534            }
     1535        }
     1536
     1537        // We verify if there is a construction.
     1538        if (!getGlyphAssemblyFallBack(assemblyParts, assemblyData))
     1539            return data;
     1540    } else {
     1541        // If the font does not have a MATH table, we fallback to the Unicode-only constructions.
     1542        const StretchyCharacter* stretchyCharacter = nullptr;
     1543        const unsigned maxIndex = WTF_ARRAY_LENGTH(stretchyCharacters);
     1544        for (unsigned index = 0; index < maxIndex; ++index) {
     1545            if (stretchyCharacters[index].character == character) {
     1546                stretchyCharacter = &stretchyCharacters[index];
     1547                break;
     1548            }
     1549        }
     1550
     1551        // If we didn't find a stretchy character set for this character, we don't know how to stretch it.
     1552        if (!stretchyCharacter)
     1553            return data;
     1554
     1555        // We convert the list of Unicode characters into a list of glyph data.
     1556        GlyphData top = style().font().glyphDataForCharacter(stretchyCharacter->topChar, false);
     1557        GlyphData extension = style().font().glyphDataForCharacter(stretchyCharacter->extensionChar, false);
     1558        GlyphData bottom = style().font().glyphDataForCharacter(stretchyCharacter->bottomChar, false);
     1559        GlyphData middle;
     1560        if (stretchyCharacter->middleChar)
     1561            middle = style().font().glyphDataForCharacter(stretchyCharacter->middleChar, false);
     1562        assemblyData.setGlyphAssemblyMode(top, extension, bottom, middle);
     1563    }
     1564
     1565    ASSERT(assemblyData.mode() == DrawGlyphAssembly);
    14091566
    14101567    // If we are measuring the maximum width, verify each component.
    14111568    if (maximumGlyphWidth) {
    1412         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(top));
    1413         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(extension));
    1414         if (middle.glyph)
    1415             *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(middle));
    1416         *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(bottom));
    1417         return data;
     1569        *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(assemblyData.top()));
     1570        *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(assemblyData.extension()));
     1571        if (assemblyData.middle().glyph)
     1572            *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(assemblyData.middle()));
     1573        *maximumGlyphWidth = std::max(*maximumGlyphWidth, advanceForGlyph(assemblyData.bottom()));
     1574        return assemblyData;
    14181575    }
    14191576
    1420     float height = heightForGlyph(top) + heightForGlyph(bottom);
    1421     if (middle.glyph)
    1422         height += heightForGlyph(middle);
     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());
    14231581    if (height > stretchSize())
    14241582        return data;
    14251583
    1426     data.setGlyphAssemblyMode(top, extension, bottom, middle);
    1427     return data;
     1584    return assemblyData;
    14281585}
    14291586
    14301587void RenderMathMLOperator::updateStyle()
    14311588{
     1589    FontCachePurgePreventer fontCachePurgePreventer;
     1590
    14321591    ASSERT(firstChild());
    14331592    if (!firstChild())
    14341593        return;
    14351594
    1436     UChar stretchedCharacter;
    1437     bool allowStretching = shouldAllowStretching(stretchedCharacter);
    1438 
    1439     float stretchedCharacterHeight = style().fontMetrics().floatHeight();
    14401595    m_stretchyData.setNormalMode();
    1441 
    1442     // Sometimes we cannot stretch an operator properly, so in that case, we should just use the original size.
    1443     if (allowStretching && stretchSize() > stretchedCharacterHeight)
    1444         m_stretchyData = findStretchyData(stretchedCharacter, nullptr);
    1445 
    14461596    // We add spacing around the operator.
    14471597    // FIXME: The spacing should be added to the whole embellished operator (https://bugs.webkit.org/show_bug.cgi?id=124831).
     
    14531603    wrapper->setStyle(std::move(newStyle));
    14541604    wrapper->setNeedsLayoutAndPrefWidthsRecalc();
     1605
     1606    if (!shouldAllowStretching())
     1607        return;
     1608
     1609    if (isLargeOperatorInDisplayStyle())
     1610        m_stretchyData = getDisplayStyleLargeOperator(m_operator);
     1611    else {
     1612        // We do not stretch if the base glyph is large enough.
     1613        GlyphData baseGlyph = style().font().glyphDataForCharacter(m_operator, false);
     1614        float baseHeight = heightForGlyph(baseGlyph);
     1615        if (stretchSize() <= baseHeight)
     1616            return;
     1617        m_stretchyData = findStretchyData(m_operator, nullptr);
     1618    }
     1619
     1620    if (m_stretchyData.mode() == DrawSizeVariant) {
     1621        // We resize the operator to match the one of the size variant.
     1622        if (isLargeOperatorInDisplayStyle()) {
     1623            // The stretch size is actually not involved in the selection of the size variant in getDisplayStyleLargeOperator.
     1624            // We simply use the height and depth of the selected size variant glyph.
     1625            FloatRect glyphBounds = boundsForGlyph(m_stretchyData.variant());
     1626            m_stretchHeightAboveBaseline = -glyphBounds.y();
     1627            m_stretchDepthBelowBaseline = glyphBounds.maxY();
     1628        } else {
     1629            // We rescale the height and depth proportionately.
     1630            float variantSize = heightForGlyph(m_stretchyData.variant());
     1631            float size = stretchSize();
     1632            float aspect = size > 0 ? variantSize / size : 1.0;
     1633            m_stretchHeightAboveBaseline *= aspect;
     1634            m_stretchDepthBelowBaseline *= aspect;
     1635        }
     1636    }
    14551637}
    14561638
     
    15581740    info.context->setFillColor(style().visitedDependentColor(CSSPropertyColor), style().colorSpace());
    15591741
     1742    if (m_stretchyData.mode() == DrawSizeVariant) {
     1743        ASSERT(m_stretchyData.variant().glyph);
     1744        GlyphBuffer buffer;
     1745        buffer.add(m_stretchyData.variant().glyph, m_stretchyData.variant().fontData, advanceForGlyph(m_stretchyData.variant()));
     1746        LayoutPoint operatorTopLeft = ceiledIntPoint(paintOffset + location());
     1747        FloatRect glyphBounds = boundsForGlyph(m_stretchyData.variant());
     1748        LayoutPoint operatorOrigin(operatorTopLeft.x(), operatorTopLeft.y() - glyphBounds.y());
     1749        info.context->drawGlyphs(style().font(), *m_stretchyData.variant().fontData, buffer, 0, 1, operatorOrigin);
     1750        return;
     1751    }
     1752
    15601753    ASSERT(m_stretchyData.mode() == DrawGlyphAssembly);
    15611754    ASSERT(m_stretchyData.top().glyph);
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.h

    r165608 r169305  
    3131#include "GlyphPage.h"
    3232#include "MathMLElement.h"
     33#include "OpenTypeMathData.h"
    3334#include "RenderMathMLToken.h"
     35#include "SimpleFontData.h"
    3436
    3537namespace WebCore {
     
    4143    Accent = 0x1, // FIXME: This must be used to implement accentunder/accent on munderover (https://bugs.webkit.org/show_bug.cgi?id=124826).
    4244    Fence = 0x2, // This has no visual effect but allows to expose semantic information via the accessibility tree.
    43     LargeOp = 0x4, // FIXME: This must be used to implement displaystyle (https://bugs.webkit.org/show_bug.cgi?id=118737)
     45    LargeOp = 0x4,
    4446    MovableLimits = 0x8, // FIXME: This must be used to implement displaystyle  (https://bugs.webkit.org/show_bug.cgi?id=118737).
    4547    Separator = 0x10, // This has no visual effect but allows to expose semantic information via the accessibility tree.
     
    6668   
    6769    bool hasOperatorFlag(MathMLOperatorDictionary::Flag flag) const { return m_operatorFlags & flag; }
     70    // FIXME: The displaystyle property is not implemented (https://bugs.webkit.org/show_bug.cgi?id=118737).
     71    bool isLargeOperatorInDisplayStyle() const { return !hasOperatorFlag(MathMLOperatorDictionary::Stretchy) && hasOperatorFlag(MathMLOperatorDictionary::LargeOp); }
    6872
    6973    void updateStyle() override final;
     
    9094    void updateFromElement() override;
    9195
    92     bool shouldAllowStretching(UChar& characterForStretching);
     96    bool shouldAllowStretching() const;
    9397
    94     FloatRect boundsForGlyph(const GlyphData&);
    95     float heightForGlyph(const GlyphData&);
    96     float advanceForGlyph(const GlyphData&);
     98    FloatRect boundsForGlyph(const GlyphData&) const;
     99    float heightForGlyph(const GlyphData&) const;
     100    float advanceForGlyph(const GlyphData&) const;
    97101
    98     // FIXME: DrawSizeVariant is not implemented yet.
    99102    enum DrawMode {
    100103        DrawNormal, DrawSizeVariant, DrawGlyphAssembly
     
    147150        GlyphData m_data[4];
    148151    };
     152    bool getGlyphAssemblyFallBack(Vector<OpenTypeMathData::AssemblyPart>, StretchyData&) const;
     153    StretchyData getDisplayStyleLargeOperator(UChar) const;
    149154    StretchyData findStretchyData(UChar, float* maximumGlyphWidth);
    150155   
Note: See TracChangeset for help on using the changeset viewer.