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