Changeset 204022 in webkit


Ignore:
Timestamp:
Aug 2, 2016 4:27:19 AM (8 years ago)
Author:
fred.wang@free.fr
Message:

Move parsing of the form attribute to MathMLOperatorElement
https://bugs.webkit.org/show_bug.cgi?id=160239

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

We move the parsing of the mo@form attribute to the MathMLOperatorElement class. Note that
when the attribute is not explicit, the form may also be guessed by searching into the
operator dictionary. Hence we also start moving the determination of the default dictionary
properties. Moving the actual parsing of the corresponding attributes will be done in
follow-up commits.

No new tests, already covered by existing tests.

  • mathml/MathMLInlineContainerElement.cpp:

(WebCore::MathMLInlineContainerElement::childrenChanged): Make the form of operators dirty
if its siblings have changed.

  • mathml/MathMLOperatorDictionary.cpp:

(WebCore::MathMLOperatorDictionary::search): Merge old getEntry functions into one helper
function that returns an Optional<Entry>.
(WebCore::MathMLOperatorDictionary::getEntry): Deleted

  • mathml/MathMLOperatorDictionary.h: Declare MathMLOperatorDictionary::find.
  • mathml/MathMLOperatorElement.cpp:

(WebCore::MathMLOperatorElement::dictionaryProperty): We determine the operator form by
parsing the corresponding attribute or by using heuristics if that attribute is not
specified. We also read dictionary the corresponding dictionary properties.
(WebCore::MathMLOperatorElement::flags): Return the flags read from the dictionary.
(WebCore::MathMLOperatorElement::defaultLeadingSpace): Return the space read from the dictionary.
(WebCore::MathMLOperatorElement::defaultTrailingSpace): Return the space read from the dictionary.
(WebCore::MathMLOperatorElement::childrenChanged): Make the dictionary properties dirty.
(WebCore::MathMLOperatorElement::parseAttribute): Make the dictionary properties dirty when
the form changes.

  • mathml/MathMLOperatorElement.h: New member to store dictionary properties and expose them.
  • rendering/mathml/RenderMathMLFencedOperator.cpp:

(WebCore::RenderMathMLFencedOperator::setOperatorProperties): We implement the case specific
to anonymous mfenced operators here.

  • rendering/mathml/RenderMathMLFencedOperator.h: Move the m_operatorForm member here and

declare the overriden function setOperatorProperties.

  • rendering/mathml/RenderMathMLOperator.cpp:

(WebCore::RenderMathMLOperator::setOperatorProperties): Simplify this code since the logic
has been moved to the element classes.
(WebCore::RenderMathMLOperator::setOperatorPropertiesFromOpDictEntry): Deleted.

  • rendering/mathml/RenderMathMLOperator.h: Remove setOperatorPropertiesFromOpDictEntry, make

members accessible to RenderMathMLFencedOperator and remove m_operatorForm.

Location:
trunk/Source/WebCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r204021 r204022  
     12016-07-28  Frederic Wang  <fwang@igalia.com>
     2
     3        Move parsing of the form attribute to MathMLOperatorElement
     4        https://bugs.webkit.org/show_bug.cgi?id=160239
     5
     6        Reviewed by Darin Adler.
     7
     8        We move the parsing of the mo@form attribute to the MathMLOperatorElement class. Note that
     9        when the attribute is not explicit, the form may also be guessed by searching into the
     10        operator dictionary. Hence we also start moving the determination of the default dictionary
     11        properties. Moving the actual parsing of the corresponding attributes will be done in
     12        follow-up commits.
     13
     14        No new tests, already covered by existing tests.
     15
     16        * mathml/MathMLInlineContainerElement.cpp:
     17        (WebCore::MathMLInlineContainerElement::childrenChanged): Make the form of operators dirty
     18        if its siblings have changed.
     19        * mathml/MathMLOperatorDictionary.cpp:
     20        (WebCore::MathMLOperatorDictionary::search): Merge old getEntry functions into one helper
     21        function that returns an Optional<Entry>.
     22        (WebCore::MathMLOperatorDictionary::getEntry): Deleted
     23        * mathml/MathMLOperatorDictionary.h: Declare MathMLOperatorDictionary::find.
     24        * mathml/MathMLOperatorElement.cpp:
     25        (WebCore::MathMLOperatorElement::dictionaryProperty): We determine the operator form by
     26        parsing the corresponding attribute or by using heuristics if that attribute is not
     27        specified. We also read dictionary the corresponding dictionary properties.
     28        (WebCore::MathMLOperatorElement::flags): Return the flags read from the dictionary.
     29        (WebCore::MathMLOperatorElement::defaultLeadingSpace): Return the space read from the dictionary.
     30        (WebCore::MathMLOperatorElement::defaultTrailingSpace): Return the space read from the dictionary.
     31        (WebCore::MathMLOperatorElement::childrenChanged): Make the dictionary properties dirty.
     32        (WebCore::MathMLOperatorElement::parseAttribute): Make the dictionary properties dirty when
     33        the form changes.
     34        * mathml/MathMLOperatorElement.h: New member to store dictionary properties and expose them.
     35        * rendering/mathml/RenderMathMLFencedOperator.cpp:
     36        (WebCore::RenderMathMLFencedOperator::setOperatorProperties): We implement the case specific
     37        to anonymous mfenced operators here.
     38        * rendering/mathml/RenderMathMLFencedOperator.h: Move the m_operatorForm member here and
     39        declare the overriden function setOperatorProperties.
     40        * rendering/mathml/RenderMathMLOperator.cpp:
     41        (WebCore::RenderMathMLOperator::setOperatorProperties): Simplify this code since the logic
     42        has been moved to the element classes.
     43        (WebCore::RenderMathMLOperator::setOperatorPropertiesFromOpDictEntry): Deleted.
     44        * rendering/mathml/RenderMathMLOperator.h: Remove setOperatorPropertiesFromOpDictEntry, make
     45        members accessible to RenderMathMLFencedOperator and remove m_operatorForm.
     46
    1472016-08-02  Frederic Wang  <fwang.igalia.com>
    248
  • trunk/Source/WebCore/mathml/MathMLInlineContainerElement.cpp

    r204021 r204022  
    3333
    3434#include "MathMLNames.h"
     35#include "MathMLOperatorElement.h"
    3536#include "RenderMathMLBlock.h"
    3637#include "RenderMathMLFenced.h"
     
    5556void MathMLInlineContainerElement::childrenChanged(const ChildChange& change)
    5657{
     58    for (auto child = firstChild(); child; child = child->nextSibling()) {
     59        if (child->hasTagName(MathMLNames::moTag))
     60            static_cast<MathMLOperatorElement*>(child)->setOperatorFormDirty();
     61    }
     62
    5763    // FIXME: Parsing of operator properties should be done in the element classes rather than in the renderer classes.
    5864    // See https://webkit.org/b/156537
  • trunk/Source/WebCore/mathml/MathMLOperatorDictionary.cpp

    r203116 r204022  
    10901090};
    10911091
    1092 const Entry* MathMLOperatorDictionary::getEntry(UChar textContent, Form form)
     1092Optional<Entry> MathMLOperatorDictionary::search(UChar character, Form form, bool explicitForm)
    10931093{
    1094     return tryBinarySearch<const Entry, Key>(dictionary, dictionarySize, Key(textContent, form), ExtractKey);
    1095 }
    1096 
    1097 const Entry* MathMLOperatorDictionary::getEntry(UChar textContent)
    1098 {
    1099     // For each operator, the dictionary has at most three form in the following order: Infix, Prefix, Postfix.
    1100     if (const Entry* entry = tryBinarySearch<const Entry, UChar>(dictionary, dictionarySize, textContent, ExtractChar)) {
     1094    if (!character)
     1095        return Nullopt;
     1096
     1097    // We try and find the default values from the operator dictionary.
     1098    if (auto* entry = tryBinarySearch<const Entry, Key>(dictionary, dictionarySize, Key(character, form), ExtractKey))
     1099        return *entry;
     1100
     1101    if (explicitForm)
     1102        return Nullopt;
     1103
     1104    // If we did not find the desired operator form and if it was not set explicitely, we use the first one in the following order: Infix, Prefix, Postfix.
     1105    // This is to handle bad MathML markup without explicit <mrow> delimiters like "<mo>(</mo><mi>a</mi><mo>)</mo><mo>(</mo><mi>b</mi><mo>)</mo>" where innerfences should not be considered infix.
     1106    if (auto* entry = tryBinarySearch<const Entry, UChar>(dictionary, dictionarySize, character, ExtractChar)) {
    11011107        // There are at most two other entries before the one found.
    1102         if (entry != dictionary && (entry - 1)->character == textContent)
     1108        if (entry != dictionary && (entry - 1)->character == character)
    11031109            entry--;
    1104         if (entry != dictionary && (entry - 1)->character == textContent)
     1110        if (entry != dictionary && (entry - 1)->character == character)
    11051111            entry--;
    1106         return entry;
     1112        return *entry;
    11071113    }
    1108     return nullptr;
     1114
     1115    return Nullopt;
    11091116}
    11101117
  • trunk/Source/WebCore/mathml/MathMLOperatorDictionary.h

    r203228 r204022  
    2929
    3030#include <unicode/utypes.h>
     31#include <wtf/Optional.h>
    3132
    3233namespace WebCore {
     
    5051    unsigned flags : 8;
    5152};
    52 const Entry* getEntry(UChar, Form);
    53 const Entry* getEntry(UChar);
     53Optional<Entry> search(UChar, Form, bool explicitForm);
    5454bool isVertical(UChar);
    5555}
  • trunk/Source/WebCore/mathml/MathMLOperatorElement.cpp

    r204021 r204022  
    3636
    3737using namespace MathMLNames;
     38using namespace MathMLOperatorDictionary;
    3839
    3940MathMLOperatorElement::MathMLOperatorElement(const QualifiedName& tagName, Document& document)
     
    6162UChar MathMLOperatorElement::operatorText()
    6263{
    63     if (m_operatorText)
    64         return m_operatorText.value();
     64    if (!m_operatorText)
     65        m_operatorText = parseOperatorText(textContent());
     66    return m_operatorText.value();
     67}
    6568
    66     m_operatorText = parseOperatorText(textContent());
    67     return m_operatorText.value();
     69MathMLOperatorElement::DictionaryProperty MathMLOperatorElement::computeDictionaryProperty()
     70{
     71    DictionaryProperty dictionaryProperty;
     72
     73    // We first determine the form attribute and use the default spacing and properties.
     74    const auto& value = attributeWithoutSynchronization(formAttr);
     75    bool explicitForm = true;
     76    if (value == "prefix")
     77        dictionaryProperty.form = Prefix;
     78    else if (value == "infix")
     79        dictionaryProperty.form = Infix;
     80    else if (value == "postfix")
     81        dictionaryProperty.form = Postfix;
     82    else {
     83        // FIXME: We should use more advanced heuristics indicated in the specification to determine the operator form (https://bugs.webkit.org/show_bug.cgi?id=124829).
     84        explicitForm = false;
     85        if (!previousSibling() && nextSibling())
     86            dictionaryProperty.form = Prefix;
     87        else if (previousSibling() && !nextSibling())
     88            dictionaryProperty.form = Postfix;
     89        else
     90            dictionaryProperty.form = Infix;
     91    }
     92
     93    // We then try and find an entry in the operator dictionary to override the default values.
     94    if (auto entry = search(operatorText(), dictionaryProperty.form, explicitForm)) {
     95        dictionaryProperty.form = static_cast<MathMLOperatorDictionary::Form>(entry.value().form);
     96        dictionaryProperty.leadingSpaceInMathUnit = entry.value().lspace;
     97        dictionaryProperty.trailingSpaceInMathUnit = entry.value().rspace;
     98        dictionaryProperty.flags = entry.value().flags;
     99    }
     100
     101    return dictionaryProperty;
     102}
     103
     104const MathMLOperatorElement::DictionaryProperty& MathMLOperatorElement::dictionaryProperty()
     105{
     106    if (!m_dictionaryProperty)
     107        m_dictionaryProperty = computeDictionaryProperty();
     108    return m_dictionaryProperty.value();
     109}
     110
     111unsigned short MathMLOperatorElement::flags()
     112{
     113    // FIXME: We should also handle boolean attributes here (https://webkit.org/b/160190).
     114    return dictionaryProperty().flags;
     115}
     116
     117MathMLElement::Length MathMLOperatorElement::defaultLeadingSpace()
     118{
     119    Length space;
     120    space.type = LengthType::MathUnit;
     121    space.value = static_cast<float>(dictionaryProperty().leadingSpaceInMathUnit);
     122    return space;
     123}
     124
     125MathMLElement::Length MathMLOperatorElement::defaultTrailingSpace()
     126{
     127    Length space;
     128    space.type = LengthType::MathUnit;
     129    space.value = static_cast<float>(dictionaryProperty().trailingSpaceInMathUnit);
     130    return space;
    68131}
    69132
     
    71134{
    72135    m_operatorText = Nullopt;
     136    m_dictionaryProperty = Nullopt;
    73137    MathMLTextElement::childrenChanged(change);
    74138}
     
    76140void MathMLOperatorElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    77141{
     142    if (name == formAttr)
     143        m_dictionaryProperty = Nullopt;
     144
    78145    if ((name == stretchyAttr || name == lspaceAttr || name == rspaceAttr || name == movablelimitsAttr) && renderer()) {
    79146        downcast<RenderMathMLOperator>(*renderer()).updateFromElement();
  • trunk/Source/WebCore/mathml/MathMLOperatorElement.h

    r203896 r204022  
    2727
    2828#if ENABLE(MATHML)
     29#include "MathMLOperatorDictionary.h"
    2930#include "MathMLTextElement.h"
    3031
     
    3637    static UChar parseOperatorText(const String&);
    3738    UChar operatorText();
     39    void setOperatorFormDirty() { m_dictionaryProperty = Nullopt; }
     40    MathMLOperatorDictionary::Form form() { return dictionaryProperty().form; }
     41    unsigned short flags();
     42    Length defaultLeadingSpace();
     43    Length defaultTrailingSpace();
    3844
    3945private:
     
    4450
    4551    Optional<UChar> m_operatorText;
     52
     53    struct DictionaryProperty {
     54        MathMLOperatorDictionary::Form form;
     55        // Default leading and trailing spaces are "thickmathspace".
     56        unsigned short leadingSpaceInMathUnit { 5 };
     57        unsigned short trailingSpaceInMathUnit { 5 };
     58        // Default operator properties are all set to "false".
     59        unsigned short flags { 0 };
     60    };
     61    Optional<DictionaryProperty> m_dictionaryProperty;
     62    DictionaryProperty computeDictionaryProperty();
     63    const DictionaryProperty& dictionaryProperty();
    4664};
    4765
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLFencedOperator.cpp

    r203973 r204022  
    2727
    2828#if ENABLE(MATHML)
     29
    2930#include "RenderMathMLFencedOperator.h"
    3031
     32#include "MathMLOperatorDictionary.h"
    3133#include "MathMLOperatorElement.h"
    3234
    3335namespace WebCore {
    3436
     37using namespace MathMLOperatorDictionary;
     38
    3539RenderMathMLFencedOperator::RenderMathMLFencedOperator(Document& document, RenderStyle&& style, const String& operatorString, MathMLOperatorDictionary::Form form, unsigned short flags)
    36     : RenderMathMLOperator(document, WTFMove(style), form, flags)
     40    : RenderMathMLOperator(document, WTFMove(style), flags)
     41    , m_operatorForm(form)
    3742{
    3843    updateOperatorContent(operatorString);
     44
     45    // maxsize always has the default value "infinity" value for mfenced operators.
     46    m_maxSize = intMaxForLayoutUnit;
    3947}
    4048
     
    4553}
    4654
     55void RenderMathMLFencedOperator::setOperatorProperties()
     56{
     57    // We determine the stretch direction (default is vertical).
     58    m_isVertical = MathMLOperatorDictionary::isVertical(m_textContent);
     59
     60    // Resets all but the Fence and Separator properties.
     61    m_operatorFlags &= MathMLOperatorDictionary::Fence | MathMLOperatorDictionary::Separator;
     62
     63    // minsize always has the default value "1em" value for mfenced operators.
     64    m_minSize = style().fontCascade().size();
     65
     66    // Default spacing is thickmathspace.
     67    MathMLElement::Length leadingSpace;
     68    leadingSpace.type = MathMLElement::LengthType::MathUnit;
     69    leadingSpace.value = 5;
     70    MathMLElement::Length trailingSpace = leadingSpace;
     71
     72    if (auto entry = search(m_textContent, m_operatorForm, true)) {
     73        // We use the space specified in the operator dictionary.
     74        leadingSpace.value = static_cast<float>(entry.value().lspace);
     75        trailingSpace.value = static_cast<float>(entry.value().rspace);
     76
     77        // We use the dictionary but preserve the Fence and Separator properties.
     78        m_operatorFlags = (m_operatorFlags & (MathMLOperatorDictionary::Fence | MathMLOperatorDictionary::Separator)) | entry.value().flags;
     79    }
     80
     81    // Resolve the leading and trailing spaces.
     82    m_leadingSpace = toUserUnits(leadingSpace, style(), 0);
     83    m_trailingSpace = toUserUnits(trailingSpace, style(), 0);
     84}
     85
    4786}
    4887
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLFencedOperator.h

    r203973 r204022  
    4040private:
    4141    bool isRenderMathMLFencedOperator() const final { return true; }
     42    void setOperatorProperties() final;
    4243    UChar textContent() const final { return m_textContent; }
    4344
    4445    UChar m_textContent { 0 };
     46    MathMLOperatorDictionary::Form m_operatorForm;
    4547};
    4648
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp

    r203973 r204022  
    5454}
    5555
    56 RenderMathMLOperator::RenderMathMLOperator(Document& document, RenderStyle&& style, MathMLOperatorDictionary::Form form, unsigned short flags)
     56RenderMathMLOperator::RenderMathMLOperator(Document& document, RenderStyle&& style, unsigned short flags)
    5757    : RenderMathMLToken(document, WTFMove(style))
    58     , m_operatorForm(form)
    5958    , m_operatorFlags(flags)
    6059{
     
    8887}
    8988
    90 void RenderMathMLOperator::setOperatorPropertiesFromOpDictEntry(const MathMLOperatorDictionary::Entry* entry)
    91 {
    92     // If this operator is anonymous, we preserve the Fence and Separator properties. This is to handle the case of RenderMathMLFenced.
    93     if (isAnonymous())
    94         m_operatorFlags = (m_operatorFlags & (MathMLOperatorDictionary::Fence | MathMLOperatorDictionary::Separator)) | entry->flags;
    95     else
    96         m_operatorFlags = entry->flags;
    97 
    98     // Leading and trailing space is specified as multiple of 1/18em.
    99     m_leadingSpace = entry->lspace * style().fontCascade().size() / 18;
    100     m_trailingSpace = entry->rspace * style().fontCascade().size() / 18;
    101 }
    102 
    10389void RenderMathMLOperator::setOperatorProperties()
    10490{
     
    10692    m_isVertical = MathMLOperatorDictionary::isVertical(textContent());
    10793
    108     // We determine the form of the operator.
    109     bool explicitForm = true;
    110     if (!isAnonymous()) {
    111         const AtomicString& form = element().attributeWithoutSynchronization(MathMLNames::formAttr);
    112         if (form == "prefix")
    113             m_operatorForm = MathMLOperatorDictionary::Prefix;
    114         else if (form == "infix")
    115             m_operatorForm = MathMLOperatorDictionary::Infix;
    116         else if (form == "postfix")
    117             m_operatorForm = MathMLOperatorDictionary::Postfix;
    118         else {
    119             // FIXME: We should use more advanced heuristics indicated in the specification to determine the operator form (https://bugs.webkit.org/show_bug.cgi?id=124829).
    120             explicitForm = false;
    121             if (!element().previousSibling() && element().nextSibling())
    122                 m_operatorForm = MathMLOperatorDictionary::Prefix;
    123             else if (element().previousSibling() && !element().nextSibling())
    124                 m_operatorForm = MathMLOperatorDictionary::Postfix;
    125             else
    126                 m_operatorForm = MathMLOperatorDictionary::Infix;
    127         }
    128     }
    129 
    130     // We determine the default values of the operator properties.
    131 
    132     // First we initialize with the default values for unknown operators.
    133     if (isAnonymous())
    134         m_operatorFlags &= MathMLOperatorDictionary::Fence | MathMLOperatorDictionary::Separator; // This resets all but the Fence and Separator properties.
    135     else
    136         m_operatorFlags = 0; // This resets all the operator properties.
    137     m_leadingSpace = 5 * style().fontCascade().size() / 18; // This sets leading space to "thickmathspace".
    138     m_trailingSpace = 5 * style().fontCascade().size() / 18; // This sets trailing space to "thickmathspace".
     94    // Initialize with the default values.
     95    m_operatorFlags = element().flags();
     96    m_leadingSpace = toUserUnits(element().defaultLeadingSpace(), style(), 0);
     97    m_trailingSpace = toUserUnits(element().defaultTrailingSpace(), style(), 0);
    13998    m_minSize = style().fontCascade().size(); // This sets minsize to "1em".
    14099    m_maxSize = intMaxForLayoutUnit; // This sets maxsize to "infinity".
    141 
    142     if (textContent()) {
    143         // Then we try to find the default values from the operator dictionary.
    144         if (const MathMLOperatorDictionary::Entry* entry = MathMLOperatorDictionary::getEntry(textContent(), m_operatorForm))
    145             setOperatorPropertiesFromOpDictEntry(entry);
    146         else if (!explicitForm) {
    147             // If we did not find the desired operator form and if it was not set explicitely, we use the first one in the following order: Infix, Prefix, Postfix.
    148             // This is to handle bad MathML markup without explicit <mrow> delimiters like "<mo>(</mo><mi>a</mi><mo>)</mo><mo>(</mo><mi>b</mi><mo>)</mo>" where the inner parenthesis should not be considered infix.
    149             if (const MathMLOperatorDictionary::Entry* entry = MathMLOperatorDictionary::getEntry(textContent())) {
    150                 m_operatorForm = static_cast<MathMLOperatorDictionary::Form>(entry->form); // We override the form previously determined.
    151                 setOperatorPropertiesFromOpDictEntry(entry);
    152             }
    153         }
    154     }
    155100
    156101    if (!isAnonymous()) {
  • trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.h

    r203973 r204022  
    4040public:
    4141    RenderMathMLOperator(MathMLOperatorElement&, RenderStyle&&);
    42     RenderMathMLOperator(Document&, RenderStyle&&, MathMLOperatorDictionary::Form, unsigned short flags = 0);
     42    RenderMathMLOperator(Document&, RenderStyle&&, unsigned short flags = 0);
    4343    MathMLOperatorElement& element() const;
    4444
     
    6161protected:
    6262    void rebuildTokenContent();
     63    virtual void setOperatorProperties();
    6364
    64     MathMLOperatorDictionary::Form m_operatorForm;
     65    bool m_isVertical { true };
     66    LayoutUnit m_leadingSpace;
     67    LayoutUnit m_trailingSpace;
     68    LayoutUnit m_minSize;
     69    LayoutUnit m_maxSize;
    6570    unsigned short m_operatorFlags;
    6671
    6772private:
    68     virtual void setOperatorProperties();
    6973    void styleDidChange(StyleDifference, const RenderStyle* oldStyle) final;
    7074    void computePreferredLogicalWidths() final;
     
    8993    void setOperatorFlagFromAttribute(MathMLOperatorDictionary::Flag, const QualifiedName&);
    9094    void setOperatorFlagFromAttributeValue(MathMLOperatorDictionary::Flag, const AtomicString& attributeValue);
    91     void setOperatorPropertiesFromOpDictEntry(const MathMLOperatorDictionary::Entry*);
    9295
    9396    LayoutUnit verticalStretchedOperatorShift() const;
     
    97100    LayoutUnit m_stretchWidth;
    98101
    99     bool m_isVertical { true };
    100     LayoutUnit m_leadingSpace;
    101     LayoutUnit m_trailingSpace;
    102     LayoutUnit m_minSize;
    103     LayoutUnit m_maxSize;
    104102    MathOperator m_mathOperator;
    105103};
Note: See TracChangeset for help on using the changeset viewer.