e25f2a70070c8ab9dbd572a646d4daecf59f1c98
[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 #include <wtf/IsoMallocInlines.h>
40
41 namespace WebCore {
42
43 using namespace MathMLNames;
44
45 WTF_MAKE_ISO_ALLOCATED_IMPL(RenderMathMLToken);
46
47 RenderMathMLToken::RenderMathMLToken(MathMLTokenElement& element, RenderStyle&& style)
48     : RenderMathMLBlock(element, WTFMove(style))
49 {
50 }
51
52 RenderMathMLToken::RenderMathMLToken(Document& document, RenderStyle&& style)
53     : RenderMathMLBlock(document, WTFMove(style))
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 (isASCIIUpper(codePoint)) {
337         baseChar = codePoint - 'A';
338         varType = Latin;
339     } else if (isASCIILower(codePoint)) {
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 (isASCIIDigit(codePoint)) {
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_mathVariantCodePoint) {
507         auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
508         if (mathVariantGlyph.font) {
509             m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth = mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph);
510             setPreferredLogicalWidthsDirty(false);
511             return;
512         }
513     }
514
515     RenderMathMLBlock::computePreferredLogicalWidths();
516 }
517
518 void RenderMathMLToken::updateMathVariantGlyph()
519 {
520     ASSERT(m_mathVariantGlyphDirty);
521
522     m_mathVariantCodePoint = std::nullopt;
523     m_mathVariantGlyphDirty = false;
524
525     // Early return if the token element contains RenderElements.
526     // Note that the renderers corresponding to the children of the token element are wrapped inside an anonymous RenderBlock.
527     if (const auto& block = downcast<RenderElement>(firstChild())) {
528         if (childrenOfType<RenderElement>(*block).first())
529             return;
530     }
531
532     const auto& tokenElement = element();
533     if (auto codePoint = MathMLTokenElement::convertToSingleCodePoint(element().textContent())) {
534         MathMLElement::MathVariant mathvariant = mathMLStyle().mathVariant();
535         if (mathvariant == MathMLElement::MathVariant::None)
536             mathvariant = tokenElement.hasTagName(MathMLNames::miTag) ? MathMLElement::MathVariant::Italic : MathMLElement::MathVariant::Normal;
537         UChar32 transformedCodePoint = mathVariant(codePoint.value(), mathvariant);
538         if (transformedCodePoint != codePoint.value()) {
539             m_mathVariantCodePoint = mathVariant(codePoint.value(), mathvariant);
540             m_mathVariantIsMirrored = !style().isLeftToRightDirection();
541         }
542     }
543 }
544
545 void RenderMathMLToken::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
546 {
547     RenderMathMLBlock::styleDidChange(diff, oldStyle);
548     setMathVariantGlyphDirty();
549 }
550
551 void RenderMathMLToken::updateFromElement()
552 {
553     RenderMathMLBlock::updateFromElement();
554     setMathVariantGlyphDirty();
555 }
556
557 std::optional<int> RenderMathMLToken::firstLineBaseline() const
558 {
559     if (m_mathVariantCodePoint) {
560         auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
561         if (mathVariantGlyph.font)
562             return std::optional<int>(static_cast<int>(lroundf(-mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).y())));
563     }
564     return RenderMathMLBlock::firstLineBaseline();
565 }
566
567 void RenderMathMLToken::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
568 {
569     ASSERT(needsLayout());
570
571     if (!relayoutChildren && simplifiedLayout())
572         return;
573
574     GlyphData mathVariantGlyph;
575     if (m_mathVariantCodePoint)
576         mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
577
578     if (!mathVariantGlyph.font) {
579         RenderMathMLBlock::layoutBlock(relayoutChildren, pageLogicalHeight);
580         return;
581     }
582
583     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox())
584         child->layoutIfNeeded();
585
586     setLogicalWidth(mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph));
587     setLogicalHeight(mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).height());
588
589     clearNeedsLayout();
590 }
591
592 void RenderMathMLToken::paint(PaintInfo& info, const LayoutPoint& paintOffset)
593 {
594     RenderMathMLBlock::paint(info, paintOffset);
595
596     // 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).
597     if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !m_mathVariantCodePoint)
598         return;
599
600     auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
601     if (!mathVariantGlyph.font)
602         return;
603
604     GraphicsContextStateSaver stateSaver(info.context());
605     info.context().setFillColor(style().visitedDependentColor(CSSPropertyColor));
606
607     GlyphBuffer buffer;
608     buffer.add(mathVariantGlyph.glyph, mathVariantGlyph.font, mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph));
609     LayoutUnit glyphAscent = static_cast<int>(lroundf(-mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).y()));
610     info.context().drawGlyphs(style().fontCascade(), *mathVariantGlyph.font, buffer, 0, 1, paintOffset + location() + LayoutPoint(0, glyphAscent));
611 }
612
613 void RenderMathMLToken::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
614 {
615     if (m_mathVariantCodePoint) {
616         auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored);
617         if (mathVariantGlyph.font)
618             return;
619     }
620
621     RenderMathMLBlock::paintChildren(paintInfo, paintOffset, paintInfoForChild, usePrintRect);
622 }
623
624 }
625
626 #endif // ENABLE(MATHML)