Changeset 203072 in webkit
- Timestamp:
- Jul 11, 2016 11:38:36 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 11 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r203071 r203072 1 2016-07-11 Frederic Wang <fwang@igalia.com> 2 3 Add support for mathvariants that cannot be emulated via CSS. 4 https://bugs.webkit.org/show_bug.cgi?id=108778 5 6 Reviewed by Brent Fulgham. 7 8 Import a test from the MathML in HTML5 test suite to perform an exhaustive 9 verification of all the mathvariant transforms allowed. 10 We also add some tests to verify inheritance of the mathvariant style, the 11 effect on each token element and dynamic modification of mathvariant. 12 Finally, we modify one test now that mathvariant is no longer emulated via CSS. 13 14 * mathml/mathml-in-html5/fonts/mathvariant-transforms.woff: Added. 15 * mathml/mathml-in-html5/mathvariant-transforms-1-expected.html: Added. 16 * mathml/mathml-in-html5/mathvariant-transforms-1.html: Added. 17 * mathml/mathml-in-html5/mathvariant-transforms-2-expected.html: Added. 18 * mathml/mathml-in-html5/mathvariant-transforms-2.html: Added. 19 * mathml/presentation/attributes-mathvariant-expected.html: Update this test now that 20 mathvariant is correctly implemented using character transforms. 21 * mathml/presentation/mathvariant-inheritance-expected.html: Added. 22 * mathml/presentation/mathvariant-inheritance.html: Added. 23 * mathml/presentation/mathvariant-tokens-expected.html: Added. 24 * mathml/presentation/mathvariant-tokens.html: Added. 25 * mathml/presentation/mathvariant-dynamic.html: Added. 26 * mathml/presentation/mathvariant-dynamic-expected.html: Added. 27 1 28 2016-07-11 Ryan Haddad <ryanhaddad@apple.com> 2 29 -
trunk/LayoutTests/mathml/presentation/attributes-mathvariant-expected.html
r202420 r203072 12 12 Unicode block ("U+1D400 MATHEMATICAL BOLD CAPITAL", 13 13 "U+1D434 MATHEMATICAL ITALIC CAPITAL A" and 14 "U+1D468 MATHEMATICAL BOLD ITALIC CAPITAL A") but the WebKit 15 implementation relies on CSS style instead, except for implicit 16 mathvariant italic on single-char mi. See also bug 108778. 14 "U+1D468 MATHEMATICAL BOLD ITALIC CAPITAL A"). 17 15 --> 18 16 <div> 19 17 <!-- FIXME: we add new lines to workaround a width/spacing bug. --> 20 18 <math> 21 <mtext style="font-style: normal;">A</mtext>19 <mtext>A</mtext> 22 20 </math><br/> 23 21 <math> 24 <mtext style="font-style: normal;">𝐴</mtext>22 <mtext>𝐴</mtext> 25 23 </math><br/> 26 24 <math> 27 <mtext style="font-style: italic;">A</mtext>25 <mtext>𝐴</mtext> 28 26 </math><br/> 29 27 <math> 30 <mtext style="font-weight: bold;">A</mtext>28 <mtext>𝐀</mtext> 31 29 </math><br/> 32 30 <math> 33 <mtext style="font-weight: bold; font-style: italic;">A</mtext>31 <mtext>𝑨</mtext> 34 32 </math> 35 33 </div> -
trunk/LayoutTests/platform/ios-simulator/TestExpectations
r202907 r203072 675 675 mathml/presentation/attributes-mathvariant.html [ Skip ] 676 676 mathml/presentation/tokenElements-mathvariant.html [ Skip ] 677 mathml/presentation/mathvariant-inheritance.html [ Skip ] 678 mathml/presentation/mathvariant-tokens.html [ Skip ] 679 680 # The web font loading & relayout seems to be performed too late. 681 imported/mathml-in-html5/mathml/relations/css-styling/mathvariant-transforms-1.html [ Pass ImageOnlyFailure ] 677 682 678 683 # <rdar://problem/19215305> ASSERT(m_cgFont.get()) fails in FontPlatformData::ctFont() -
trunk/Source/WebCore/ChangeLog
r203066 r203072 1 2016-07-11 Frederic Wang <fwang@igalia.com> 2 3 Add support for mathvariants that cannot be emulated via CSS. 4 https://bugs.webkit.org/show_bug.cgi?id=108778 5 6 Reviewed by Brent Fulgham. 7 8 Tests: mathml/mathml-in-html5/mathvariant-transforms-1.html 9 mathml/mathml-in-html5/mathvariant-transforms-2.html 10 mathml/presentation/mathvariant-inheritance.html 11 mathml/presentation/mathvariant-tokens.html 12 13 We remove the old code to emulate partial mathvariant support via CSS and add support 14 for all mathvariant values using the technique used for implicit italic on <mi> element. 15 We also rely on the MathMLStyle class introduced earlier to support custome MathML style 16 and manage inheritance of mathvariant values. 17 The function that tries and converts one base character into a transformed mathvariant 18 character is based on similar code from Gecko: 19 http://hg.mozilla.org/mozilla-central/file/tip/layout/generic/MathMLTextRunFactory.cpp 20 Note that we only support transform on token elements with a single character, which 21 should cover the most important use cases. 22 23 * css/mathml.css: Remove the CSS rules to emulate some mathvariant values. 24 (math[mathvariant="normal"], mstyle[mathvariant="normal"], mo[mathvariant="normal"], mn[mathvariant="normal"], mi[mathvariant="normal"], mtext[mathvariant="normal"], mspace[mathvariant="normal"], ms[mathvariant="normal"]): Deleted. 25 (math[mathvariant="bold"], mstyle[mathvariant="bold"], mo[mathvariant="bold"], mn[mathvariant="bold"], mi[mathvariant="bold"], mtext[mathvariant="bold"], mspace[mathvariant="bold"], ms[mathvariant="bold"]): Deleted. 26 (math[mathvariant="italic"], mstyle[mathvariant="italic"], mo[mathvariant="italic"], mn[mathvariant="italic"], mi[mathvariant="italic"], mtext[mathvariant="italic"], mspace[mathvariant="italic"], ms[mathvariant="italic"]): Deleted. 27 (math[mathvariant="bold-italic"], mstyle[mathvariant="bold-italic"], mo[mathvariant="bold-italic"], mn[mathvariant="bold-italic"], mi[mathvariant="bold-italic"], mtext[mathvariant="bold-italic"], mspace[mathvariant="bold-italic"], ms[mathvariant="bold-italic"]): Deleted. 28 * mathml/MathMLInlineContainerElement.cpp: We resolve mathml style when mathvariant changes. 29 (WebCore::MathMLInlineContainerElement::parseAttribute): 30 * mathml/MathMLMathElement.cpp: ditto. 31 (WebCore::MathMLMathElement::parseAttribute): 32 * mathml/MathMLTextElement.cpp: ditto. 33 (WebCore::MathMLTextElement::parseAttribute): 34 * rendering/mathml/MathMLStyle.cpp: Add mathvariant property to the MathML style. 35 (WebCore::MathMLStyle::MathMLStyle): Init mathvariant to none. 36 (WebCore::MathMLStyle::getMathMLStyle): Helper function to retrieve the MathML style on a renderer. 37 (WebCore::MathMLStyle::updateStyleIfNeeded): Take into account change of mathvariant. 38 (WebCore::MathMLStyle::parseMathVariant): Helper function to parse a mathvariant attribute. 39 (WebCore::MathMLStyle::resolveMathMLStyle): Take into account mathvariant value: it is None 40 by default, inherited and can be modified via an attribute on <math>, <mstyle> or token 41 elements. We also refactor a bit to share logic between displaystyle and mathvariant. 42 (WebCore::MathMLStyle::setDisplayStyle): Deleted. 43 * rendering/mathml/MathMLStyle.h: Add mathvariant members and update declarations. 44 * rendering/mathml/RenderMathMLOperator.cpp: 45 (WebCore::RenderMathMLOperator::updateTokenContent): Call the function from the parent class 46 to consider mathvariant on <mo>. 47 * rendering/mathml/RenderMathMLToken.cpp: 48 We implement a mathVariant function to transform a base character into its transformed mathvariant: 49 - There are some regularity that allows to perform this via simple linear transforms. 50 - However, there are also many exceptions and we rely on some sorted MathVariantMapping 51 tables to handle these cases. 52 (WebCore::ExtractKey): Helper function to perform binary searches on MathVariant tables. 53 (WebCore::MathVariantMappingSearch): ditto. 54 (WebCore::mathVariant): New function to perform mathvariant transforms. 55 (WebCore::RenderMathMLToken::updateMathVariantGlyph): Use the mathVariant function to 56 perform all transformations, not just the italic one. 57 (WebCore::transformToItalic): Deleted. Replaced with the more general mathVariant function. 58 1 59 2016-07-11 Jeremy Jones <jeremyj@apple.com> 2 60 -
trunk/Source/WebCore/css/mathml.css
r202934 r203072 133 133 } 134 134 135 math[mathvariant="normal"], mstyle[mathvariant="normal"], mo[mathvariant="normal"], mn[mathvariant="normal"], mi[mathvariant="normal"], mtext[mathvariant="normal"], mspace[mathvariant="normal"], ms[mathvariant="normal"] {136 font-style: normal;137 font-weight: normal;138 }139 140 math[mathvariant="bold"], mstyle[mathvariant="bold"], mo[mathvariant="bold"], mn[mathvariant="bold"], mi[mathvariant="bold"], mtext[mathvariant="bold"], mspace[mathvariant="bold"], ms[mathvariant="bold"] {141 font-style: normal;142 font-weight: bold;143 }144 145 math[mathvariant="italic"], mstyle[mathvariant="italic"], mo[mathvariant="italic"], mn[mathvariant="italic"], mi[mathvariant="italic"], mtext[mathvariant="italic"], mspace[mathvariant="italic"], ms[mathvariant="italic"] {146 font-style: italic;147 font-weight: normal;148 }149 150 math[mathvariant="bold-italic"], mstyle[mathvariant="bold-italic"], mo[mathvariant="bold-italic"], mn[mathvariant="bold-italic"], mi[mathvariant="bold-italic"], mtext[mathvariant="bold-italic"], mspace[mathvariant="bold-italic"], ms[mathvariant="bold-italic"] {151 font-weight: bold;152 font-style: italic;153 }154 155 135 math[mathsize="small"], mstyle[mathsize="small"], mo[mathsize="small"], mn[mathsize="small"], mi[mathsize="small"], mtext[mathsize="small"], mspace[mathsize="small"], ms[mathsize="small"] { 156 136 font-size: 0.75em; -
trunk/Source/WebCore/mathml/MathMLInlineContainerElement.cpp
r202962 r203072 89 89 void MathMLInlineContainerElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 90 90 { 91 if (name == displaystyleAttr && (hasTagName(mstyleTag) || hasTagName(mtableTag)) && renderer()) 91 bool displayStyleAttribute = (name == displaystyleAttr && (hasTagName(mstyleTag) || hasTagName(mtableTag))); 92 bool mathVariantAttribute = (name == mathvariantAttr && (hasTagName(mathTag) || hasTagName(mstyleTag))); 93 if ((displayStyleAttribute || mathVariantAttribute) && renderer()) 92 94 MathMLStyle::resolveMathMLStyleTree(renderer()); 93 95 -
trunk/Source/WebCore/mathml/MathMLMathElement.cpp
r202960 r203072 56 56 void MathMLMathElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 57 57 { 58 if ((name == displaystyleAttr || name == displayAttr ) && hasTagName(mathTag) && renderer())58 if ((name == displaystyleAttr || name == displayAttr || name == mathvariantAttr) && renderer()) 59 59 MathMLStyle::resolveMathMLStyleTree(renderer()); 60 60 -
trunk/Source/WebCore/mathml/MathMLTextElement.cpp
r202970 r203072 73 73 } 74 74 75 if (name == mathvariantAttr && renderer()) 76 MathMLStyle::resolveMathMLStyleTree(renderer()); 77 75 78 MathMLElement::parseAttribute(name, value); 76 79 } -
trunk/Source/WebCore/rendering/mathml/MathMLStyle.cpp
r202979 r203072 48 48 } 49 49 50 void MathMLStyle::setDisplayStyle(RenderObject* renderer) 51 { 52 if (!renderer) 53 return; 54 55 // FIXME: Should we make RenderMathMLTable derive from RenderMathMLBlock in order to simplify this? 56 if (is<RenderMathMLTable>(renderer)) 57 m_displayStyle = downcast<RenderMathMLTable>(renderer)->mathMLStyle()->displayStyle(); 58 else if (is<RenderMathMLBlock>(renderer)) 59 m_displayStyle = downcast<RenderMathMLBlock>(renderer)->mathMLStyle()->displayStyle(); 50 const MathMLStyle* MathMLStyle::getMathMLStyle(RenderObject* renderer) 51 { 52 if (renderer) { 53 // FIXME: Should we make RenderMathMLTable derive from RenderMathMLBlock in order to simplify this? 54 if (is<RenderMathMLTable>(renderer)) 55 return downcast<RenderMathMLTable>(renderer)->mathMLStyle(); 56 if (is<RenderMathMLBlock>(renderer)) 57 return downcast<RenderMathMLBlock>(renderer)->mathMLStyle(); 58 } 59 60 return nullptr; 60 61 } 61 62 … … 81 82 } 82 83 83 void MathMLStyle::updateStyleIfNeeded(RenderObject* renderer, bool oldDisplayStyle )84 void MathMLStyle::updateStyleIfNeeded(RenderObject* renderer, bool oldDisplayStyle, MathVariant oldMathVariant) 84 85 { 85 86 if (oldDisplayStyle != m_displayStyle) { … … 92 93 downcast<RenderMathMLFraction>(renderer)->updateFromElement(); 93 94 } 95 if (oldMathVariant != m_mathVariant) { 96 if (is<RenderMathMLToken>(renderer)) 97 downcast<RenderMathMLToken>(renderer)->updateTokenContent(); 98 } 99 } 100 101 MathMLStyle::MathVariant MathMLStyle::parseMathVariant(const AtomicString& attributeValue) 102 { 103 if (attributeValue == "normal") 104 return Normal; 105 if (attributeValue == "bold") 106 return Bold; 107 if (attributeValue == "italic") 108 return Italic; 109 if (attributeValue == "bold-italic") 110 return BoldItalic; 111 if (attributeValue == "double-struck") 112 return DoubleStruck; 113 if (attributeValue == "bold-fraktur") 114 return BoldFraktur; 115 if (attributeValue == "script") 116 return Script; 117 if (attributeValue == "bold-script") 118 return BoldScript; 119 if (attributeValue == "fraktur") 120 return Fraktur; 121 if (attributeValue == "sans-serif") 122 return SansSerif; 123 if (attributeValue == "bold-sans-serif") 124 return BoldSansSerif; 125 if (attributeValue == "sans-serif-italic") 126 return SansSerifItalic; 127 if (attributeValue == "sans-serif-bold-italic") 128 return SansSerifBoldItalic; 129 if (attributeValue == "monospace") 130 return Monospace; 131 if (attributeValue == "initial") 132 return Initial; 133 if (attributeValue == "tailed") 134 return Tailed; 135 if (attributeValue == "looped") 136 return Looped; 137 if (attributeValue == "stretched") 138 return Stretched; 139 return None; 94 140 } 95 141 … … 99 145 100 146 bool oldDisplayStyle = m_displayStyle; 101 102 // For anonymous renderers, we just inherit the style from our parent. 147 MathVariant oldMathVariant = m_mathVariant; 148 auto* parentRenderer = getMathMLParentNode(renderer); 149 const MathMLStyle* parentStyle = getMathMLStyle(parentRenderer); 150 151 // By default, we just inherit the style from our parent. 152 m_displayStyle = false; 153 m_mathVariant = None; 154 if (parentStyle) { 155 setDisplayStyle(parentStyle->displayStyle()); 156 setMathVariant(parentStyle->mathVariant()); 157 } 158 159 // Early return for anonymous renderers. 103 160 if (renderer->isAnonymous()) { 104 setDisplayStyle(getMathMLParentNode(renderer)); 105 updateStyleIfNeeded(renderer, oldDisplayStyle); 161 updateStyleIfNeeded(renderer, oldDisplayStyle, oldMathVariant); 106 162 return; 107 163 } … … 111 167 else if (is<RenderMathMLTable>(renderer)) 112 168 m_displayStyle = false; // The default displaystyle of <mtable> is false. 113 else if (auto* parentRenderer = getMathMLParentNode(renderer)) { 114 setDisplayStyle(parentRenderer); // The default displaystyle is inherited from our parent. 169 else if (parentRenderer) { 115 170 if (is<RenderMathMLFraction>(parentRenderer)) 116 171 m_displayStyle = false; // <mfrac> sets displaystyle to false within its numerator and denominator. … … 135 190 } 136 191 137 updateStyleIfNeeded(renderer, oldDisplayStyle); 192 // The mathvariant attribute on the <math>, <mstyle> or token elements overrides the default behavior. 193 if (is<RenderMathMLMath>(renderer) || is<RenderMathMLToken>(renderer) || tagName == mstyleTag) { 194 MathVariant mathvariant = parseMathVariant(element->fastGetAttribute(mathvariantAttr)); 195 if (mathvariant != None) 196 m_mathVariant = mathvariant; 197 } 198 199 updateStyleIfNeeded(renderer, oldDisplayStyle, oldMathVariant); 138 200 } 139 201 -
trunk/Source/WebCore/rendering/mathml/MathMLStyle.h
r202960 r203072 43 43 void setDisplayStyle(bool displayStyle) { m_displayStyle = displayStyle; } 44 44 45 // These are the mathvariant values from the MathML recommendation. 46 // The special value none means that no explicit mathvariant value has been specified. 47 // Note that the numeral values are important for the computation performed in the mathVariant function of RenderMathMLToken, do not change them! 48 enum MathVariant { 49 None = 0, 50 Normal = 1, 51 Bold = 2, 52 Italic = 3, 53 BoldItalic = 4, 54 Script = 5, 55 BoldScript = 6, 56 Fraktur = 7, 57 DoubleStruck = 8, 58 BoldFraktur = 9, 59 SansSerif = 10, 60 BoldSansSerif = 11, 61 SansSerifItalic = 12, 62 SansSerifBoldItalic = 13, 63 Monospace = 14, 64 Initial = 15, 65 Tailed = 16, 66 Looped = 17, 67 Stretched = 18 68 }; 69 MathVariant mathVariant() const { return m_mathVariant; } 70 void setMathVariant(MathVariant mathvariant) { m_mathVariant = mathvariant; } 71 45 72 void resolveMathMLStyle(RenderObject*); 46 73 static void resolveMathMLStyleTree(RenderObject*); … … 48 75 private: 49 76 bool isDisplayStyleAlwaysFalse(RenderObject*); 50 void setDisplayStyle(RenderObject*);77 const MathMLStyle* getMathMLStyle(RenderObject* renderer); 51 78 RenderObject* getMathMLParentNode(RenderObject*); 52 void updateStyleIfNeeded(RenderObject*, bool); 79 void updateStyleIfNeeded(RenderObject*, bool, MathVariant); 80 MathVariant parseMathVariant(const AtomicString& attributeValue); 53 81 54 bool m_displayStyle = false; 82 bool m_displayStyle { false }; 83 MathVariant m_mathVariant { None }; 55 84 }; 56 85 -
trunk/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp
r202973 r203072 326 326 { 327 327 ASSERT(!isAnonymous()); 328 RenderMathMLToken::updateTokenContent(); 328 329 rebuildTokenContent(element().textContent()); 329 330 } -
trunk/Source/WebCore/rendering/mathml/RenderMathMLToken.cpp
r202420 r203072 59 59 } 60 60 61 static bool transformToItalic(UChar32& codePoint) 62 { 63 const UChar32 lowerAlpha = 0x3B1; 64 const UChar32 lowerOmega = 0x3C9; 65 const UChar32 mathItalicLowerA = 0x1D44E; 66 const UChar32 mathItalicLowerAlpha = 0x1D6FC; 67 const UChar32 mathItalicLowerH = 0x210E; 68 const UChar32 mathItalicUpperA = 0x1D434; 69 70 // FIXME: We should also transform dotless i, dotless j and more greek letters. 71 if ('a' <= codePoint && codePoint <= 'z') { 72 if (codePoint == 'h') 73 codePoint = mathItalicLowerH; 74 else 75 codePoint += mathItalicLowerA - 'a'; 76 return true; 77 } 61 // Entries for the mathvariant lookup tables. 62 // 'key' represents the Unicode character to be transformed and is used for searching the tables. 63 // 'replacement' represents the mapped mathvariant Unicode character. 64 struct MathVariantMapping { 65 uint32_t key; 66 uint32_t replacement; 67 }; 68 static inline UChar32 ExtractKey(const MathVariantMapping* entry) { return entry->key; } 69 static UChar32 MathVariantMappingSearch(uint32_t key, const MathVariantMapping* table, size_t tableLength) 70 { 71 if (const auto* entry = tryBinarySearch<const MathVariantMapping, UChar32>(table, tableLength, key, ExtractKey)) 72 return entry->replacement; 73 74 return 0; 75 } 76 77 // Lookup tables for use with mathvariant mappings to transform a unicode character point to another unicode character that indicates the proper output. 78 // key represents one of two concepts. 79 // 1. In the Latin table it represents a hole in the mathematical alphanumeric block, where the character that should occupy that position is located elsewhere. 80 // 2. It represents an Arabic letter. 81 // As a replacement, 0 is reserved to indicate no mapping was found. 82 static const MathVariantMapping arabicInitialMapTable[] = { 83 { 0x628, 0x1EE21 }, 84 { 0x62A, 0x1EE35 }, 85 { 0x62B, 0x1EE36 }, 86 { 0x62C, 0x1EE22 }, 87 { 0x62D, 0x1EE27 }, 88 { 0x62E, 0x1EE37 }, 89 { 0x633, 0x1EE2E }, 90 { 0x634, 0x1EE34 }, 91 { 0x635, 0x1EE31 }, 92 { 0x636, 0x1EE39 }, 93 { 0x639, 0x1EE2F }, 94 { 0x63A, 0x1EE3B }, 95 { 0x641, 0x1EE30 }, 96 { 0x642, 0x1EE32 }, 97 { 0x643, 0x1EE2A }, 98 { 0x644, 0x1EE2B }, 99 { 0x645, 0x1EE2C }, 100 { 0x646, 0x1EE2D }, 101 { 0x647, 0x1EE24 }, 102 { 0x64A, 0x1EE29 } 103 }; 104 105 static const MathVariantMapping arabicTailedMapTable[] = { 106 { 0x62C, 0x1EE42 }, 107 { 0x62D, 0x1EE47 }, 108 { 0x62E, 0x1EE57 }, 109 { 0x633, 0x1EE4E }, 110 { 0x634, 0x1EE54 }, 111 { 0x635, 0x1EE51 }, 112 { 0x636, 0x1EE59 }, 113 { 0x639, 0x1EE4F }, 114 { 0x63A, 0x1EE5B }, 115 { 0x642, 0x1EE52 }, 116 { 0x644, 0x1EE4B }, 117 { 0x646, 0x1EE4D }, 118 { 0x64A, 0x1EE49 }, 119 { 0x66F, 0x1EE5F }, 120 { 0x6BA, 0x1EE5D } 121 }; 122 123 static const MathVariantMapping arabicStretchedMapTable[] = { 124 { 0x628, 0x1EE61 }, 125 { 0x62A, 0x1EE75 }, 126 { 0x62B, 0x1EE76 }, 127 { 0x62C, 0x1EE62 }, 128 { 0x62D, 0x1EE67 }, 129 { 0x62E, 0x1EE77 }, 130 { 0x633, 0x1EE6E }, 131 { 0x634, 0x1EE74 }, 132 { 0x635, 0x1EE71 }, 133 { 0x636, 0x1EE79 }, 134 { 0x637, 0x1EE68 }, 135 { 0x638, 0x1EE7A }, 136 { 0x639, 0x1EE6F }, 137 { 0x63A, 0x1EE7B }, 138 { 0x641, 0x1EE70 }, 139 { 0x642, 0x1EE72 }, 140 { 0x643, 0x1EE6A }, 141 { 0x645, 0x1EE6C }, 142 { 0x646, 0x1EE6D }, 143 { 0x647, 0x1EE64 }, 144 { 0x64A, 0x1EE69 }, 145 { 0x66E, 0x1EE7C }, 146 { 0x6A1, 0x1EE7E } 147 }; 148 149 static const MathVariantMapping arabicLoopedMapTable[] = { 150 { 0x627, 0x1EE80 }, 151 { 0x628, 0x1EE81 }, 152 { 0x62A, 0x1EE95 }, 153 { 0x62B, 0x1EE96 }, 154 { 0x62C, 0x1EE82 }, 155 { 0x62D, 0x1EE87 }, 156 { 0x62E, 0x1EE97 }, 157 { 0x62F, 0x1EE83 }, 158 { 0x630, 0x1EE98 }, 159 { 0x631, 0x1EE93 }, 160 { 0x632, 0x1EE86 }, 161 { 0x633, 0x1EE8E }, 162 { 0x634, 0x1EE94 }, 163 { 0x635, 0x1EE91 }, 164 { 0x636, 0x1EE99 }, 165 { 0x637, 0x1EE88 }, 166 { 0x638, 0x1EE9A }, 167 { 0x639, 0x1EE8F }, 168 { 0x63A, 0x1EE9B }, 169 { 0x641, 0x1EE90 }, 170 { 0x642, 0x1EE92 }, 171 { 0x644, 0x1EE8B }, 172 { 0x645, 0x1EE8C }, 173 { 0x646, 0x1EE8D }, 174 { 0x647, 0x1EE84 }, 175 { 0x648, 0x1EE85 }, 176 { 0x64A, 0x1EE89 } 177 }; 178 179 static const MathVariantMapping arabicDoubleMapTable[] = { 180 { 0x628, 0x1EEA1 }, 181 { 0x62A, 0x1EEB5 }, 182 { 0x62B, 0x1EEB6 }, 183 { 0x62C, 0x1EEA2 }, 184 { 0x62D, 0x1EEA7 }, 185 { 0x62E, 0x1EEB7 }, 186 { 0x62F, 0x1EEA3 }, 187 { 0x630, 0x1EEB8 }, 188 { 0x631, 0x1EEB3 }, 189 { 0x632, 0x1EEA6 }, 190 { 0x633, 0x1EEAE }, 191 { 0x634, 0x1EEB4 }, 192 { 0x635, 0x1EEB1 }, 193 { 0x636, 0x1EEB9 }, 194 { 0x637, 0x1EEA8 }, 195 { 0x638, 0x1EEBA }, 196 { 0x639, 0x1EEAF }, 197 { 0x63A, 0x1EEBB }, 198 { 0x641, 0x1EEB0 }, 199 { 0x642, 0x1EEB2 }, 200 { 0x644, 0x1EEAB }, 201 { 0x645, 0x1EEAC }, 202 { 0x646, 0x1EEAD }, 203 { 0x648, 0x1EEA5 }, 204 { 0x64A, 0x1EEA9 } 205 }; 206 207 static const MathVariantMapping latinExceptionMapTable[] = { 208 { 0x1D455, 0x210E }, 209 { 0x1D49D, 0x212C }, 210 { 0x1D4A0, 0x2130 }, 211 { 0x1D4A1, 0x2131 }, 212 { 0x1D4A3, 0x210B }, 213 { 0x1D4A4, 0x2110 }, 214 { 0x1D4A7, 0x2112 }, 215 { 0x1D4A8, 0x2133 }, 216 { 0x1D4AD, 0x211B }, 217 { 0x1D4BA, 0x212F }, 218 { 0x1D4BC, 0x210A }, 219 { 0x1D4C4, 0x2134 }, 220 { 0x1D506, 0x212D }, 221 { 0x1D50B, 0x210C }, 222 { 0x1D50C, 0x2111 }, 223 { 0x1D515, 0x211C }, 224 { 0x1D51D, 0x2128 }, 225 { 0x1D53A, 0x2102 }, 226 { 0x1D53F, 0x210D }, 227 { 0x1D545, 0x2115 }, 228 { 0x1D547, 0x2119 }, 229 { 0x1D548, 0x211A }, 230 { 0x1D549, 0x211D }, 231 { 0x1D551, 0x2124 } 232 }; 233 234 const UChar32 greekUpperTheta = 0x03F4; 235 const UChar32 holeGreekUpperTheta = 0x03A2; 236 const UChar32 nabla = 0x2207; 237 const UChar32 partialDifferential = 0x2202; 238 const UChar32 greekUpperAlpha = 0x0391; 239 const UChar32 greekUpperOmega = 0x03A9; 240 const UChar32 greekLowerAlpha = 0x03B1; 241 const UChar32 greekLowerOmega = 0x03C9; 242 const UChar32 greekLunateEpsilonSymbol = 0x03F5; 243 const UChar32 greekThetaSymbol = 0x03D1; 244 const UChar32 greekKappaSymbol = 0x03F0; 245 const UChar32 greekPhiSymbol = 0x03D5; 246 const UChar32 greekRhoSymbol = 0x03F1; 247 const UChar32 greekPiSymbol = 0x03D6; 248 const UChar32 greekLetterDigamma = 0x03DC; 249 const UChar32 greekSmallLetterDigamma = 0x03DD; 250 const UChar32 mathBoldCapitalDigamma = 0x1D7CA; 251 const UChar32 mathBoldSmallDigamma = 0x1D7CB; 252 253 const UChar32 latinSmallLetterDotlessI = 0x0131; 254 const UChar32 latinSmallLetterDotlessJ = 0x0237; 255 256 const UChar32 mathItalicSmallDotlessI = 0x1D6A4; 257 const UChar32 mathItalicSmallDotlessJ = 0x1D6A5; 258 259 const UChar32 mathBoldUpperA = 0x1D400; 260 const UChar32 mathItalicUpperA = 0x1D434; 261 const UChar32 mathBoldSmallA = 0x1D41A; 262 const UChar32 mathBoldUpperAlpha = 0x1D6A8; 263 const UChar32 mathBoldSmallAlpha = 0x1D6C2; 264 const UChar32 mathItalicUpperAlpha = 0x1D6E2; 265 const UChar32 mathBoldDigitZero = 0x1D7CE; 266 const UChar32 mathDoubleStruckZero = 0x1D7D8; 267 268 const UChar32 mathBoldUpperTheta = 0x1D6B9; 269 const UChar32 mathBoldNabla = 0x1D6C1; 270 const UChar32 mathBoldPartialDifferential = 0x1D6DB; 271 const UChar32 mathBoldEpsilonSymbol = 0x1D6DC; 272 const UChar32 mathBoldThetaSymbol = 0x1D6DD; 273 const UChar32 mathBoldKappaSymbol = 0x1D6DE; 274 const UChar32 mathBoldPhiSymbol = 0x1D6DF; 275 const UChar32 mathBoldRhoSymbol = 0x1D6E0; 276 const UChar32 mathBoldPiSymbol = 0x1D6E1; 277 278 // Performs the character mapping needed to implement MathML's mathvariant attribute. 279 // It takes a unicode character and maps it to its appropriate mathvariant counterpart specified by mathvariant. 280 // The mapped character is typically located within Unicode's mathematical blocks (0x1D***, 0x1EE**) but there are exceptions which this function accounts for. 281 // Characters without a valid mapping or valid aMathvar value are returned 282 // unaltered. 283 // Characters already in the mathematical blocks (or are one of the exceptions) are never transformed. 284 // Acceptable values for mathvariant are specified in MathMLStyle.h 285 // The transformable characters can be found at: 286 // http://lists.w3.org/Archives/Public/www-math/2013Sep/0012.html and 287 // https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols 288 static UChar32 mathVariant(UChar32 codePoint, MathMLStyle::MathVariant mathvariant) 289 { 290 ASSERT(mathvariant >= MathMLStyle::Normal && mathvariant <= MathMLStyle::Stretched); 291 292 if (mathvariant == MathMLStyle::Normal) 293 return codePoint; // Nothing to do here. 294 295 // Exceptional characters with at most one possible transformation. 296 if (codePoint == holeGreekUpperTheta) 297 return codePoint; // Nothing at this code point is transformed 298 if (codePoint == greekLetterDigamma) { 299 if (mathvariant == MathMLStyle::Bold) 300 return mathBoldCapitalDigamma; 301 return codePoint; 302 } 303 if (codePoint == greekSmallLetterDigamma) { 304 if (mathvariant == MathMLStyle::Bold) 305 return mathBoldSmallDigamma; 306 return codePoint; 307 } 308 if (codePoint == latinSmallLetterDotlessI) { 309 if (mathvariant == MathMLStyle::Italic) 310 return mathItalicSmallDotlessI; 311 return codePoint; 312 } 313 if (codePoint == latinSmallLetterDotlessJ) { 314 if (mathvariant == MathMLStyle::Italic) 315 return mathItalicSmallDotlessJ; 316 return codePoint; 317 } 318 319 // The Unicode mathematical blocks are divided into four segments: Latin, Greek, numbers and Arabic. 320 // In the case of the first three baseChar represents the relative order in which the characters are encoded in the Unicode mathematical block, normalised to the first character of that sequence. 321 UChar32 baseChar; 322 enum CharacterType { 323 Latin, 324 Greekish, 325 Number, 326 Arabic 327 }; 328 CharacterType varType; 78 329 if ('A' <= codePoint && codePoint <= 'Z') { 79 codePoint += mathItalicUpperA - 'A'; 80 return true; 81 } 82 if (lowerAlpha <= codePoint && codePoint <= lowerOmega) { 83 codePoint += mathItalicLowerAlpha - lowerAlpha; 84 return true; 85 } 86 87 return false; 330 baseChar = codePoint - 'A'; 331 varType = Latin; 332 } else if ('a' <= codePoint && codePoint <= 'z') { 333 // Lowercase characters are placed immediately after the uppercase characters in the Unicode mathematical block. 334 // The constant subtraction represents the number of characters between the start of the sequence (capital A) and the first lowercase letter. 335 baseChar = mathBoldSmallA - mathBoldUpperA + codePoint - 'a'; 336 varType = Latin; 337 } else if ('0' <= codePoint && codePoint <= '9') { 338 baseChar = codePoint - '0'; 339 varType = Number; 340 } else if (greekUpperAlpha <= codePoint && codePoint <= greekUpperOmega) { 341 baseChar = codePoint - greekUpperAlpha; 342 varType = Greekish; 343 } else if (greekLowerAlpha <= codePoint && codePoint <= greekLowerOmega) { 344 // Lowercase Greek comes after uppercase Greek. 345 // Note in this instance the presence of an additional character (Nabla) between the end of the uppercase Greek characters and the lowercase ones. 346 baseChar = mathBoldSmallAlpha - mathBoldUpperAlpha + codePoint - greekLowerAlpha; 347 varType = Greekish; 348 } else if (0x0600 <= codePoint && codePoint <= 0x06FF) { 349 // Arabic characters are defined within this range 350 varType = Arabic; 351 } else { 352 switch (codePoint) { 353 case greekUpperTheta: 354 baseChar = mathBoldUpperTheta - mathBoldUpperAlpha; 355 break; 356 case nabla: 357 baseChar = mathBoldNabla - mathBoldUpperAlpha; 358 break; 359 case partialDifferential: 360 baseChar = mathBoldPartialDifferential - mathBoldUpperAlpha; 361 break; 362 case greekLunateEpsilonSymbol: 363 baseChar = mathBoldEpsilonSymbol - mathBoldUpperAlpha; 364 break; 365 case greekThetaSymbol: 366 baseChar = mathBoldThetaSymbol - mathBoldUpperAlpha; 367 break; 368 case greekKappaSymbol: 369 baseChar = mathBoldKappaSymbol - mathBoldUpperAlpha; 370 break; 371 case greekPhiSymbol: 372 baseChar = mathBoldPhiSymbol - mathBoldUpperAlpha; 373 break; 374 case greekRhoSymbol: 375 baseChar = mathBoldRhoSymbol - mathBoldUpperAlpha; 376 break; 377 case greekPiSymbol: 378 baseChar = mathBoldPiSymbol - mathBoldUpperAlpha; 379 break; 380 default: 381 return codePoint; 382 } 383 varType = Greekish; 384 } 385 386 int8_t multiplier; 387 if (varType == Number) { 388 // Each possible number mathvariant is encoded in a single, contiguous block. 389 // For example the beginning of the double struck number range follows immediately after the end of the bold number range. 390 // multiplier represents the order of the sequences relative to the first one. 391 switch (mathvariant) { 392 case MathMLStyle::Bold: 393 multiplier = 0; 394 break; 395 case MathMLStyle::DoubleStruck: 396 multiplier = 1; 397 break; 398 case MathMLStyle::SansSerif: 399 multiplier = 2; 400 break; 401 case MathMLStyle::BoldSansSerif: 402 multiplier = 3; 403 break; 404 case MathMLStyle::Monospace: 405 multiplier = 4; 406 break; 407 default: 408 // This mathvariant isn't defined for numbers or is otherwise normal. 409 return codePoint; 410 } 411 // As the ranges are contiguous, to find the desired mathvariant range it is sufficient to 412 // multiply the position within the sequence order (multiplier) with the period of the sequence (which is constant for all number sequences) 413 // and to add the character point of the first character within the number mathvariant range. 414 // To this the baseChar calculated earlier is added to obtain the final code point. 415 return baseChar + multiplier * (mathDoubleStruckZero - mathBoldDigitZero) + mathBoldDigitZero; 416 } 417 if (varType == Greekish) { 418 switch (mathvariant) { 419 case MathMLStyle::Bold: 420 multiplier = 0; 421 break; 422 case MathMLStyle::Italic: 423 multiplier = 1; 424 break; 425 case MathMLStyle::BoldItalic: 426 multiplier = 2; 427 break; 428 case MathMLStyle::BoldSansSerif: 429 multiplier = 3; 430 break; 431 case MathMLStyle::SansSerifBoldItalic: 432 multiplier = 4; 433 break; 434 default: 435 // This mathvariant isn't defined for Greek or is otherwise normal. 436 return codePoint; 437 } 438 // See the Number case for an explanation of the following calculation. 439 return baseChar + mathBoldUpperAlpha + multiplier * (mathItalicUpperAlpha - mathBoldUpperAlpha); 440 } 441 442 UChar32 tempChar; 443 UChar32 newChar; 444 if (varType == Arabic) { 445 // The Arabic mathematical block is not continuous, nor does it have a monotonic mapping to the unencoded characters, requiring the use of a lookup table. 446 const MathVariantMapping* mapTable; 447 size_t tableLength; 448 switch (mathvariant) { 449 case MathMLStyle::Initial: 450 mapTable = arabicInitialMapTable; 451 tableLength = WTF_ARRAY_LENGTH(arabicInitialMapTable); 452 break; 453 case MathMLStyle::Tailed: 454 mapTable = arabicTailedMapTable; 455 tableLength = WTF_ARRAY_LENGTH(arabicTailedMapTable); 456 break; 457 case MathMLStyle::Stretched: 458 mapTable = arabicStretchedMapTable; 459 tableLength = WTF_ARRAY_LENGTH(arabicStretchedMapTable); 460 break; 461 case MathMLStyle::Looped: 462 mapTable = arabicLoopedMapTable; 463 tableLength = WTF_ARRAY_LENGTH(arabicLoopedMapTable); 464 break; 465 case MathMLStyle::DoubleStruck: 466 mapTable = arabicDoubleMapTable; 467 tableLength = WTF_ARRAY_LENGTH(arabicDoubleMapTable); 468 break; 469 default: 470 return codePoint; // No valid transformations exist. 471 } 472 newChar = MathVariantMappingSearch(codePoint, mapTable, tableLength); 473 } else { 474 // Must be Latin 475 if (mathvariant > MathMLStyle::Monospace) 476 return codePoint; // Latin doesn't support the Arabic mathvariants 477 multiplier = mathvariant - 2; 478 // This is possible because the values for NS_MATHML_MATHVARIANT_* are chosen to coincide with the order in which the encoded mathvariant characters are located within their unicode block (less an offset to avoid None and Normal variants) 479 // See the Number case for an explanation of the following calculation 480 tempChar = baseChar + mathBoldUpperA + multiplier * (mathItalicUpperA - mathBoldUpperA); 481 // There are roughly twenty characters that are located outside of the mathematical block, so the spaces where they ought to be are used as keys for a lookup table containing the correct character mappings. 482 newChar = MathVariantMappingSearch(tempChar, latinExceptionMapTable, WTF_ARRAY_LENGTH(latinExceptionMapTable)); 483 } 484 485 if (newChar) 486 return newChar; 487 if (varType == Latin) 488 return tempChar; 489 return codePoint; // This is an Arabic character without a corresponding mapping. 88 490 } 89 491 … … 108 510 ASSERT(m_mathVariantGlyphDirty); 109 511 110 // This implements implicit italic mathvariant for single-char <mi>.111 // FIXME: Add full support for the mathvariant attribute (https://webkit.org/b/85735)112 512 m_mathVariantGlyph = GlyphData(); 113 513 m_mathVariantGlyphDirty = false; … … 121 521 122 522 const auto& tokenElement = element(); 123 if (tokenElement.hasTagName(MathMLNames::miTag) && !tokenElement.hasAttribute(mathvariantAttr)) { 124 AtomicString textContent = element().textContent().stripWhiteSpace().simplifyWhiteSpace(); 125 if (textContent.length() == 1) { 126 UChar32 codePoint = textContent[0]; 127 if (transformToItalic(codePoint)) 128 m_mathVariantGlyph = style().fontCascade().glyphDataForCharacter(codePoint, !style().isLeftToRightDirection()); 129 } 523 AtomicString textContent = element().textContent().stripWhiteSpace().simplifyWhiteSpace(); 524 if (textContent.length() == 1) { 525 UChar32 codePoint = textContent[0]; 526 MathMLStyle::MathVariant mathvariant = mathMLStyle()->mathVariant(); 527 if (mathvariant == MathMLStyle::None) 528 mathvariant = tokenElement.hasTagName(MathMLNames::miTag) ? MathMLStyle::Italic : MathMLStyle::Normal; 529 UChar32 transformedCodePoint = mathVariant(codePoint, mathvariant); 530 if (transformedCodePoint != codePoint) 531 m_mathVariantGlyph = style().fontCascade().glyphDataForCharacter(transformedCodePoint, !style().isLeftToRightDirection()); 130 532 } 131 533 }
Note: See TracChangeset
for help on using the changeset viewer.