Crash when getting font bounding rect
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLToken.cpp
1 /*
2  * Copyright (C) 2014 Frédéric Wang (fred.wang@free.fr). All rights reserved.
3  * Copyright (C) 2016 Igalia S.L.
4  * Copyright (C) 2016 Apple Inc.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "RenderMathMLToken.h"
30
31 #if ENABLE(MATHML)
32
33 #include "MathMLElement.h"
34 #include "MathMLNames.h"
35 #include "MathMLTokenElement.h"
36 #include "PaintInfo.h"
37 #include "RenderElement.h"
38 #include "RenderIterator.h"
39
40 namespace WebCore {
41
42 using namespace MathMLNames;
43
44 RenderMathMLToken::RenderMathMLToken(Element& element, RenderStyle&& style)
45     : RenderMathMLBlock(element, WTFMove(style))
46 {
47 }
48
49 RenderMathMLToken::RenderMathMLToken(Document& document, RenderStyle&& style)
50     : RenderMathMLBlock(document, WTFMove(style))
51 {
52 }
53
54 MathMLTokenElement& RenderMathMLToken::element()
55 {
56     return static_cast<MathMLTokenElement&>(nodeForNonAnonymous());
57 }
58
59 void RenderMathMLToken::updateTokenContent()
60 {
61     RenderMathMLBlock::updateFromElement();
62     setMathVariantGlyphDirty();
63 }
64
65 // Entries for the mathvariant lookup tables.
66 // 'key' represents the Unicode character to be transformed and is used for searching the tables.
67 // 'replacement' represents the mapped mathvariant Unicode character.
68 struct MathVariantMapping {
69     uint32_t key;
70     uint32_t replacement;
71 };
72 static inline UChar32 ExtractKey(const MathVariantMapping* entry) { return entry->key; }
73 static UChar32 MathVariantMappingSearch(uint32_t key, const MathVariantMapping* table, size_t tableLength)
74 {
75     if (const auto* entry = tryBinarySearch<const MathVariantMapping, UChar32>(table, tableLength, key, ExtractKey))
76         return entry->replacement;
77
78     return 0;
79 }
80
81 // Lookup tables for use with mathvariant mappings to transform a unicode character point to another unicode character that indicates the proper output.
82 // key represents one of two concepts.
83 // 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.
84 // 2. It represents an Arabic letter.
85 //  As a replacement, 0 is reserved to indicate no mapping was found.
86 static const MathVariantMapping arabicInitialMapTable[] = {
87     { 0x628, 0x1EE21 },
88     { 0x62A, 0x1EE35 },
89     { 0x62B, 0x1EE36 },
90     { 0x62C, 0x1EE22 },
91     { 0x62D, 0x1EE27 },
92     { 0x62E, 0x1EE37 },
93     { 0x633, 0x1EE2E },
94     { 0x634, 0x1EE34 },
95     { 0x635, 0x1EE31 },
96     { 0x636, 0x1EE39 },
97     { 0x639, 0x1EE2F },
98     { 0x63A, 0x1EE3B },
99     { 0x641, 0x1EE30 },
100     { 0x642, 0x1EE32 },
101     { 0x643, 0x1EE2A },
102     { 0x644, 0x1EE2B },
103     { 0x645, 0x1EE2C },
104     { 0x646, 0x1EE2D },
105     { 0x647, 0x1EE24 },
106     { 0x64A, 0x1EE29 }
107 };
108
109 static const MathVariantMapping arabicTailedMapTable[] = {
110     { 0x62C, 0x1EE42 },
111     { 0x62D, 0x1EE47 },
112     { 0x62E, 0x1EE57 },
113     { 0x633, 0x1EE4E },
114     { 0x634, 0x1EE54 },
115     { 0x635, 0x1EE51 },
116     { 0x636, 0x1EE59 },
117     { 0x639, 0x1EE4F },
118     { 0x63A, 0x1EE5B },
119     { 0x642, 0x1EE52 },
120     { 0x644, 0x1EE4B },
121     { 0x646, 0x1EE4D },
122     { 0x64A, 0x1EE49 },
123     { 0x66F, 0x1EE5F },
124     { 0x6BA, 0x1EE5D }
125 };
126
127 static const MathVariantMapping arabicStretchedMapTable[] = {
128     { 0x628, 0x1EE61 },
129     { 0x62A, 0x1EE75 },
130     { 0x62B, 0x1EE76 },
131     { 0x62C, 0x1EE62 },
132     { 0x62D, 0x1EE67 },
133     { 0x62E, 0x1EE77 },
134     { 0x633, 0x1EE6E },
135     { 0x634, 0x1EE74 },
136     { 0x635, 0x1EE71 },
137     { 0x636, 0x1EE79 },
138     { 0x637, 0x1EE68 },
139     { 0x638, 0x1EE7A },
140     { 0x639, 0x1EE6F },
141     { 0x63A, 0x1EE7B },
142     { 0x641, 0x1EE70 },
143     { 0x642, 0x1EE72 },
144     { 0x643, 0x1EE6A },
145     { 0x645, 0x1EE6C },
146     { 0x646, 0x1EE6D },
147     { 0x647, 0x1EE64 },
148     { 0x64A, 0x1EE69 },
149     { 0x66E, 0x1EE7C },
150     { 0x6A1, 0x1EE7E }
151 };
152
153 static const MathVariantMapping arabicLoopedMapTable[] = {
154     { 0x627, 0x1EE80 },
155     { 0x628, 0x1EE81 },
156     { 0x62A, 0x1EE95 },
157     { 0x62B, 0x1EE96 },
158     { 0x62C, 0x1EE82 },
159     { 0x62D, 0x1EE87 },
160     { 0x62E, 0x1EE97 },
161     { 0x62F, 0x1EE83 },
162     { 0x630, 0x1EE98 },
163     { 0x631, 0x1EE93 },
164     { 0x632, 0x1EE86 },
165     { 0x633, 0x1EE8E },
166     { 0x634, 0x1EE94 },
167     { 0x635, 0x1EE91 },
168     { 0x636, 0x1EE99 },
169     { 0x637, 0x1EE88 },
170     { 0x638, 0x1EE9A },
171     { 0x639, 0x1EE8F },
172     { 0x63A, 0x1EE9B },
173     { 0x641, 0x1EE90 },
174     { 0x642, 0x1EE92 },
175     { 0x644, 0x1EE8B },
176     { 0x645, 0x1EE8C },
177     { 0x646, 0x1EE8D },
178     { 0x647, 0x1EE84 },
179     { 0x648, 0x1EE85 },
180     { 0x64A, 0x1EE89 }
181 };
182
183 static const MathVariantMapping arabicDoubleMapTable[] = {
184     { 0x628, 0x1EEA1 },
185     { 0x62A, 0x1EEB5 },
186     { 0x62B, 0x1EEB6 },
187     { 0x62C, 0x1EEA2 },
188     { 0x62D, 0x1EEA7 },
189     { 0x62E, 0x1EEB7 },
190     { 0x62F, 0x1EEA3 },
191     { 0x630, 0x1EEB8 },
192     { 0x631, 0x1EEB3 },
193     { 0x632, 0x1EEA6 },
194     { 0x633, 0x1EEAE },
195     { 0x634, 0x1EEB4 },
196     { 0x635, 0x1EEB1 },
197     { 0x636, 0x1EEB9 },
198     { 0x637, 0x1EEA8 },
199     { 0x638, 0x1EEBA },
200     { 0x639, 0x1EEAF },
201     { 0x63A, 0x1EEBB },
202     { 0x641, 0x1EEB0 },
203     { 0x642, 0x1EEB2 },
204     { 0x644, 0x1EEAB },
205     { 0x645, 0x1EEAC },
206     { 0x646, 0x1EEAD },
207     { 0x648, 0x1EEA5 },
208     { 0x64A, 0x1EEA9 }
209 };
210
211 static const MathVariantMapping latinExceptionMapTable[] = {
212     { 0x1D455, 0x210E },
213     { 0x1D49D, 0x212C },
214     { 0x1D4A0, 0x2130 },
215     { 0x1D4A1, 0x2131 },
216     { 0x1D4A3, 0x210B },
217     { 0x1D4A4, 0x2110 },
218     { 0x1D4A7, 0x2112 },
219     { 0x1D4A8, 0x2133 },
220     { 0x1D4AD, 0x211B },
221     { 0x1D4BA, 0x212F },
222     { 0x1D4BC, 0x210A },
223     { 0x1D4C4, 0x2134 },
224     { 0x1D506, 0x212D },
225     { 0x1D50B, 0x210C },
226     { 0x1D50C, 0x2111 },
227     { 0x1D515, 0x211C },
228     { 0x1D51D, 0x2128 },
229     { 0x1D53A, 0x2102 },
230     { 0x1D53F, 0x210D },
231     { 0x1D545, 0x2115 },
232     { 0x1D547, 0x2119 },
233     { 0x1D548, 0x211A },
234     { 0x1D549, 0x211D },
235     { 0x1D551, 0x2124 }
236 };
237
238 const UChar32 greekUpperTheta = 0x03F4;
239 const UChar32 holeGreekUpperTheta = 0x03A2;
240 const UChar32 nabla = 0x2207;
241 const UChar32 partialDifferential = 0x2202;
242 const UChar32 greekUpperAlpha = 0x0391;
243 const UChar32 greekUpperOmega = 0x03A9;
244 const UChar32 greekLowerAlpha = 0x03B1;
245 const UChar32 greekLowerOmega = 0x03C9;
246 const UChar32 greekLunateEpsilonSymbol = 0x03F5;
247 const UChar32 greekThetaSymbol = 0x03D1;
248 const UChar32 greekKappaSymbol = 0x03F0;
249 const UChar32 greekPhiSymbol = 0x03D5;
250 const UChar32 greekRhoSymbol = 0x03F1;
251 const UChar32 greekPiSymbol = 0x03D6;
252 const UChar32 greekLetterDigamma = 0x03DC;
253 const UChar32 greekSmallLetterDigamma = 0x03DD;
254 const UChar32 mathBoldCapitalDigamma = 0x1D7CA;
255 const UChar32 mathBoldSmallDigamma = 0x1D7CB;
256
257 const UChar32 latinSmallLetterDotlessI = 0x0131;
258 const UChar32 latinSmallLetterDotlessJ = 0x0237;
259
260 const UChar32 mathItalicSmallDotlessI = 0x1D6A4;
261 const UChar32 mathItalicSmallDotlessJ = 0x1D6A5;
262
263 const UChar32 mathBoldUpperA = 0x1D400;
264 const UChar32 mathItalicUpperA = 0x1D434;
265 const UChar32 mathBoldSmallA = 0x1D41A;
266 const UChar32 mathBoldUpperAlpha = 0x1D6A8;
267 const UChar32 mathBoldSmallAlpha = 0x1D6C2;
268 const UChar32 mathItalicUpperAlpha = 0x1D6E2;
269 const UChar32 mathBoldDigitZero = 0x1D7CE;
270 const UChar32 mathDoubleStruckZero = 0x1D7D8;
271
272 const UChar32 mathBoldUpperTheta = 0x1D6B9;
273 const UChar32 mathBoldNabla = 0x1D6C1;
274 const UChar32 mathBoldPartialDifferential = 0x1D6DB;
275 const UChar32 mathBoldEpsilonSymbol = 0x1D6DC;
276 const UChar32 mathBoldThetaSymbol = 0x1D6DD;
277 const UChar32 mathBoldKappaSymbol = 0x1D6DE;
278 const UChar32 mathBoldPhiSymbol = 0x1D6DF;
279 const UChar32 mathBoldRhoSymbol = 0x1D6E0;
280 const UChar32 mathBoldPiSymbol = 0x1D6E1;
281
282 // Performs the character mapping needed to implement MathML's mathvariant attribute.
283 // It takes a unicode character and maps it to its appropriate mathvariant counterpart specified by mathvariant.
284 // The mapped character is typically located within Unicode's mathematical blocks (0x1D***, 0x1EE**) but there are exceptions which this function accounts for.
285 // Characters without a valid mapping or valid aMathvar value are returned
286 // unaltered.
287 // Characters already in the mathematical blocks (or are one of the exceptions) are never transformed.
288 // Acceptable values for mathvariant are specified in MathMLElement.h
289 // The transformable characters can be found at:
290 // http://lists.w3.org/Archives/Public/www-math/2013Sep/0012.html and
291 // https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols
292 static UChar32 mathVariant(UChar32 codePoint, MathMLElement::MathVariant mathvariant)
293 {
294     ASSERT(mathvariant >= MathMLElement::MathVariant::Normal && mathvariant <= MathMLElement::MathVariant::Stretched);
295
296     if (mathvariant == MathMLElement::MathVariant::Normal)
297         return codePoint; // Nothing to do here.
298
299     // Exceptional characters with at most one possible transformation.
300     if (codePoint == holeGreekUpperTheta)
301         return codePoint; // Nothing at this code point is transformed
302     if (codePoint == greekLetterDigamma) {
303         if (mathvariant == MathMLElement::MathVariant::Bold)
304             return mathBoldCapitalDigamma;
305         return codePoint;
306     }
307     if (codePoint == greekSmallLetterDigamma) {
308         if (mathvariant == MathMLElement::MathVariant::Bold)
309             return mathBoldSmallDigamma;
310         return codePoint;
311     }
312     if (codePoint == latinSmallLetterDotlessI) {
313         if (mathvariant == MathMLElement::MathVariant::Italic)
314             return mathItalicSmallDotlessI;
315         return codePoint;
316     }
317     if (codePoint == latinSmallLetterDotlessJ) {
318         if (mathvariant == MathMLElement::MathVariant::Italic)
319             return mathItalicSmallDotlessJ;
320         return codePoint;
321     }
322
323     // The Unicode mathematical blocks are divided into four segments: Latin, Greek, numbers and Arabic.
324     // 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.
325     UChar32 baseChar = 0;
326     enum CharacterType {
327         Latin,
328         Greekish,
329         Number,
330         Arabic
331     };
332     CharacterType varType;
333     if ('A' <= codePoint && codePoint <= 'Z') {
334         baseChar = codePoint - 'A';
335         varType = Latin;
336     } else if ('a' <= codePoint && codePoint <= 'z') {
337         // Lowercase characters are placed immediately after the uppercase characters in the Unicode mathematical block.
338         // The constant subtraction represents the number of characters between the start of the sequence (capital A) and the first lowercase letter.
339         baseChar = mathBoldSmallA - mathBoldUpperA + codePoint - 'a';
340         varType = Latin;
341     } else if ('0' <= codePoint && codePoint <= '9') {
342         baseChar = codePoint - '0';
343         varType = Number;
344     } else if (greekUpperAlpha <= codePoint && codePoint <= greekUpperOmega) {
345         baseChar = codePoint - greekUpperAlpha;
346         varType = Greekish;
347     } else if (greekLowerAlpha <= codePoint && codePoint <= greekLowerOmega) {
348         // Lowercase Greek comes after uppercase Greek.
349         // Note in this instance the presence of an additional character (Nabla) between the end of the uppercase Greek characters and the lowercase ones.
350         baseChar = mathBoldSmallAlpha - mathBoldUpperAlpha + codePoint - greekLowerAlpha;
351         varType = Greekish;
352     } else if (0x0600 <= codePoint && codePoint <= 0x06FF) {
353         // Arabic characters are defined within this range
354         varType = Arabic;
355     } else {
356         switch (codePoint) {
357         case greekUpperTheta:
358             baseChar = mathBoldUpperTheta - mathBoldUpperAlpha;
359             break;
360         case nabla:
361             baseChar = mathBoldNabla - mathBoldUpperAlpha;
362             break;
363         case partialDifferential:
364             baseChar = mathBoldPartialDifferential - mathBoldUpperAlpha;
365             break;
366         case greekLunateEpsilonSymbol:
367             baseChar = mathBoldEpsilonSymbol - mathBoldUpperAlpha;
368             break;
369         case greekThetaSymbol:
370             baseChar = mathBoldThetaSymbol - mathBoldUpperAlpha;
371             break;
372         case greekKappaSymbol:
373             baseChar = mathBoldKappaSymbol - mathBoldUpperAlpha;
374             break;
375         case greekPhiSymbol:
376             baseChar = mathBoldPhiSymbol - mathBoldUpperAlpha;
377             break;
378         case greekRhoSymbol:
379             baseChar = mathBoldRhoSymbol - mathBoldUpperAlpha;
380             break;
381         case greekPiSymbol:
382             baseChar = mathBoldPiSymbol - mathBoldUpperAlpha;
383             break;
384         default:
385             return codePoint;
386         }
387         varType = Greekish;
388     }
389
390     int8_t multiplier;
391     if (varType == Number) {
392         // Each possible number mathvariant is encoded in a single, contiguous block.
393         // For example the beginning of the double struck number range follows immediately after the end of the bold number range.
394         // multiplier represents the order of the sequences relative to the first one.
395         switch (mathvariant) {
396         case MathMLElement::MathVariant::Bold:
397             multiplier = 0;
398             break;
399         case MathMLElement::MathVariant::DoubleStruck:
400             multiplier = 1;
401             break;
402         case MathMLElement::MathVariant::SansSerif:
403             multiplier = 2;
404             break;
405         case MathMLElement::MathVariant::BoldSansSerif:
406             multiplier = 3;
407             break;
408         case MathMLElement::MathVariant::Monospace:
409             multiplier = 4;
410             break;
411         default:
412             // This mathvariant isn't defined for numbers or is otherwise normal.
413             return codePoint;
414         }
415         // As the ranges are contiguous, to find the desired mathvariant range it is sufficient to
416         // multiply the position within the sequence order (multiplier) with the period of the sequence (which is constant for all number sequences)
417         // and to add the character point of the first character within the number mathvariant range.
418         // To this the baseChar calculated earlier is added to obtain the final code point.
419         return baseChar + multiplier * (mathDoubleStruckZero - mathBoldDigitZero) + mathBoldDigitZero;
420     }
421     if (varType == Greekish) {
422         switch (mathvariant) {
423         case MathMLElement::MathVariant::Bold:
424             multiplier = 0;
425             break;
426         case MathMLElement::MathVariant::Italic:
427             multiplier = 1;
428             break;
429         case MathMLElement::MathVariant::BoldItalic:
430             multiplier = 2;
431             break;
432         case MathMLElement::MathVariant::BoldSansSerif:
433             multiplier = 3;
434             break;
435         case MathMLElement::MathVariant::SansSerifBoldItalic:
436             multiplier = 4;
437             break;
438         default:
439             // This mathvariant isn't defined for Greek or is otherwise normal.
440             return codePoint;
441         }
442         // See the Number case for an explanation of the following calculation.
443         return baseChar + mathBoldUpperAlpha + multiplier * (mathItalicUpperAlpha - mathBoldUpperAlpha);
444     }
445
446     UChar32 tempChar = 0;
447     UChar32 newChar;
448     if (varType == Arabic) {
449         // 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.
450         const MathVariantMapping* mapTable;
451         size_t tableLength;
452         switch (mathvariant) {
453         case MathMLElement::MathVariant::Initial:
454             mapTable = arabicInitialMapTable;
455             tableLength = WTF_ARRAY_LENGTH(arabicInitialMapTable);
456             break;
457         case MathMLElement::MathVariant::Tailed:
458             mapTable = arabicTailedMapTable;
459             tableLength = WTF_ARRAY_LENGTH(arabicTailedMapTable);
460             break;
461         case MathMLElement::MathVariant::Stretched:
462             mapTable = arabicStretchedMapTable;
463             tableLength = WTF_ARRAY_LENGTH(arabicStretchedMapTable);
464             break;
465         case MathMLElement::MathVariant::Looped:
466             mapTable = arabicLoopedMapTable;
467             tableLength = WTF_ARRAY_LENGTH(arabicLoopedMapTable);
468             break;
469         case MathMLElement::MathVariant::DoubleStruck:
470             mapTable = arabicDoubleMapTable;
471             tableLength = WTF_ARRAY_LENGTH(arabicDoubleMapTable);
472             break;
473         default:
474             return codePoint; // No valid transformations exist.
475         }
476         newChar = MathVariantMappingSearch(codePoint, mapTable, tableLength);
477     } else {
478         // Must be Latin
479         if (mathvariant > MathMLElement::MathVariant::Monospace)
480             return codePoint; // Latin doesn't support the Arabic mathvariants
481         multiplier = static_cast<int>(mathvariant) - 2;
482         // 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)
483         // See the Number case for an explanation of the following calculation
484         tempChar = baseChar + mathBoldUpperA + multiplier * (mathItalicUpperA - mathBoldUpperA);
485         // 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.
486         newChar = MathVariantMappingSearch(tempChar, latinExceptionMapTable, WTF_ARRAY_LENGTH(latinExceptionMapTable));
487     }
488
489     if (newChar)
490         return newChar;
491     if (varType == Latin)
492         return tempChar;
493     return codePoint; // This is an Arabic character without a corresponding mapping.
494 }
495
496 void RenderMathMLToken::computePreferredLogicalWidths()
497 {
498     ASSERT(preferredLogicalWidthsDirty());
499
500     if (m_mathVariantGlyphDirty)
501         updateMathVariantGlyph();
502
503     if (m_mathVariantCodePoint) {
504         auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
505         if (mathVariantGlyph.font) {
506             m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth = mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph);
507             setPreferredLogicalWidthsDirty(false);
508             return;
509         }
510     }
511
512     RenderMathMLBlock::computePreferredLogicalWidths();
513 }
514
515 void RenderMathMLToken::updateMathVariantGlyph()
516 {
517     ASSERT(m_mathVariantGlyphDirty);
518
519     m_mathVariantCodePoint = Nullopt;
520     m_mathVariantGlyphDirty = false;
521
522     // Early return if the token element contains RenderElements.
523     // Note that the renderers corresponding to the children of the token element are wrapped inside an anonymous RenderBlock.
524     if (const auto& block = downcast<RenderElement>(firstChild())) {
525         if (childrenOfType<RenderElement>(*block).first())
526             return;
527     }
528
529     const auto& tokenElement = element();
530     if (auto codePoint = MathMLTokenElement::convertToSingleCodePoint(element().textContent())) {
531         MathMLElement::MathVariant mathvariant = mathMLStyle()->mathVariant();
532         if (mathvariant == MathMLElement::MathVariant::None)
533             mathvariant = tokenElement.hasTagName(MathMLNames::miTag) ? MathMLElement::MathVariant::Italic : MathMLElement::MathVariant::Normal;
534         UChar32 transformedCodePoint = mathVariant(codePoint.value(), mathvariant);
535         if (transformedCodePoint != codePoint.value()) {
536             m_mathVariantCodePoint = mathVariant(codePoint.value(), mathvariant);
537             m_mathVariantIsMirrored = !style().isLeftToRightDirection();
538         }
539     }
540 }
541
542 void RenderMathMLToken::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
543 {
544     RenderMathMLBlock::styleDidChange(diff, oldStyle);
545     setMathVariantGlyphDirty();
546 }
547
548 void RenderMathMLToken::updateFromElement()
549 {
550     RenderMathMLBlock::updateFromElement();
551     setMathVariantGlyphDirty();
552 }
553
554 Optional<int> RenderMathMLToken::firstLineBaseline() const
555 {
556     if (m_mathVariantCodePoint) {
557         auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
558         if (mathVariantGlyph.font)
559             return Optional<int>(static_cast<int>(lroundf(-mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).y())));
560     }
561     return RenderMathMLBlock::firstLineBaseline();
562 }
563
564 void RenderMathMLToken::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
565 {
566     ASSERT(needsLayout());
567
568     if (!relayoutChildren && simplifiedLayout())
569         return;
570
571     GlyphData mathVariantGlyph;
572     if (m_mathVariantCodePoint)
573         mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
574
575     if (!mathVariantGlyph.font) {
576         RenderMathMLBlock::layoutBlock(relayoutChildren, pageLogicalHeight);
577         return;
578     }
579
580     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox())
581         child->layoutIfNeeded();
582
583     setLogicalWidth(mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph));
584     setLogicalHeight(mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).height());
585
586     clearNeedsLayout();
587 }
588
589 void RenderMathMLToken::paint(PaintInfo& info, const LayoutPoint& paintOffset)
590 {
591     RenderMathMLBlock::paint(info, paintOffset);
592
593     // FIXME: Instead of using DrawGlyph, we may consider using the more general TextPainter so that we can apply mathvariant to strings with an arbitrary number of characters and preserve advanced CSS effects (text-shadow, etc).
594     if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !m_mathVariantCodePoint)
595         return;
596
597     auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
598     if (!mathVariantGlyph.font)
599         return;
600
601     GraphicsContextStateSaver stateSaver(info.context());
602     info.context().setFillColor(style().visitedDependentColor(CSSPropertyColor));
603
604     GlyphBuffer buffer;
605     buffer.add(mathVariantGlyph.glyph, mathVariantGlyph.font, mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph));
606     LayoutUnit glyphAscent = static_cast<int>(lroundf(-mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).y()));
607     info.context().drawGlyphs(style().fontCascade(), *mathVariantGlyph.font, buffer, 0, 1, paintOffset + location() + LayoutPoint(0, glyphAscent));
608 }
609
610 void RenderMathMLToken::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
611 {
612     if (m_mathVariantCodePoint) {
613         auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
614         if (mathVariantGlyph.font)
615             return;
616     }
617
618     RenderMathMLBlock::paintChildren(paintInfo, paintOffset, paintInfoForChild, usePrintRect);
619 }
620
621 }
622
623 #endif // ENABLE(MATHML)