1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "MathMLTextRunFactory.h"
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/BinarySearch.h"
11 #include "nsStyleConsts.h"
12 #include "nsStyleContext.h"
13 #include "nsTextFrameUtils.h"
14 #include "nsFontMetrics.h"
15 #include "nsDeviceContext.h"
16 #include "nsUnicodeScriptCodes.h"
18 using namespace mozilla
;
21 Entries for the mathvariant lookup tables. mKey represents the Unicode
22 character to be transformed and is used for searching the tables.
23 mReplacement represents the mapped mathvariant Unicode character.
28 uint32_t mReplacement
;
32 Lookup tables for use with mathvariant mappings to transform a unicode
33 character point to another unicode character that indicates the proper output.
34 mKey represents one of two concepts.
35 1. In the Latin table it represents a hole in the mathematical alphanumeric
36 block, where the character that should occupy that position is located
38 2. It represents an Arabic letter.
40 As a replacement, 0 is reserved to indicate no mapping was found.
42 static const MathVarMapping gArabicInitialMapTable
[] = {
65 static const MathVarMapping gArabicTailedMapTable
[] = {
83 static const MathVarMapping gArabicStretchedMapTable
[] = {
109 static const MathVarMapping gArabicLoopedMapTable
[] = {
139 static const MathVarMapping gArabicDoubleMapTable
[] = {
167 static const MathVarMapping gLatinExceptionMapTable
[] = {
196 struct MathVarMappingWrapper
198 const MathVarMapping
* const mTable
;
199 explicit MathVarMappingWrapper(const MathVarMapping
* aTable
) : mTable(aTable
) {}
200 uint32_t operator[](size_t index
) const {
201 return mTable
[index
].mKey
;
207 // Finds a MathVarMapping struct with the specified key (aKey) within aTable.
208 // aTable must be an array, whose length is specified by aNumElements
210 MathvarMappingSearch(uint32_t aKey
, const MathVarMapping
* aTable
, uint32_t aNumElements
)
213 if (BinarySearch(MathVarMappingWrapper(aTable
), 0, aNumElements
, aKey
, &index
)) {
214 return aTable
[index
].mReplacement
;
220 #define GREEK_UPPER_THETA 0x03F4
221 #define HOLE_GREEK_UPPER_THETA 0x03A2
223 #define PARTIAL_DIFFERENTIAL 0x2202
224 #define GREEK_UPPER_ALPHA 0x0391
225 #define GREEK_UPPER_OMEGA 0x03A9
226 #define GREEK_LOWER_ALPHA 0x03B1
227 #define GREEK_LOWER_OMEGA 0x03C9
228 #define GREEK_LUNATE_EPSILON_SYMBOL 0x03F5
229 #define GREEK_THETA_SYMBOL 0x03D1
230 #define GREEK_KAPPA_SYMBOL 0x03F0
231 #define GREEK_PHI_SYMBOL 0x03D5
232 #define GREEK_RHO_SYMBOL 0x03F1
233 #define GREEK_PI_SYMBOL 0x03D6
234 #define GREEK_LETTER_DIGAMMA 0x03DC
235 #define GREEK_SMALL_LETTER_DIGAMMA 0x03DD
236 #define MATH_BOLD_CAPITAL_DIGAMMA 0x1D7CA
237 #define MATH_BOLD_SMALL_DIGAMMA 0x1D7CB
239 #define LATIN_SMALL_LETTER_DOTLESS_I 0x0131
240 #define LATIN_SMALL_LETTER_DOTLESS_J 0x0237
242 #define MATH_ITALIC_SMALL_DOTLESS_I 0x1D6A4
243 #define MATH_ITALIC_SMALL_DOTLESS_J 0x1D6A5
245 #define MATH_BOLD_UPPER_A 0x1D400
246 #define MATH_ITALIC_UPPER_A 0x1D434
247 #define MATH_BOLD_SMALL_A 0x1D41A
248 #define MATH_BOLD_UPPER_ALPHA 0x1D6A8
249 #define MATH_BOLD_SMALL_ALPHA 0x1D6C2
250 #define MATH_ITALIC_UPPER_ALPHA 0x1D6E2
251 #define MATH_BOLD_DIGIT_ZERO 0x1D7CE
252 #define MATH_DOUBLE_STRUCK_ZERO 0x1D7D8
254 #define MATH_BOLD_UPPER_THETA 0x1D6B9
255 #define MATH_BOLD_NABLA 0x1D6C1
256 #define MATH_BOLD_PARTIAL_DIFFERENTIAL 0x1D6DB
257 #define MATH_BOLD_EPSILON_SYMBOL 0x1D6DC
258 #define MATH_BOLD_THETA_SYMBOL 0x1D6DD
259 #define MATH_BOLD_KAPPA_SYMBOL 0x1D6DE
260 #define MATH_BOLD_PHI_SYMBOL 0x1D6DF
261 #define MATH_BOLD_RHO_SYMBOL 0x1D6E0
262 #define MATH_BOLD_PI_SYMBOL 0x1D6E1
265 Performs the character mapping needed to implement MathML's mathvariant
266 attribute. It takes a unicode character and maps it to its appropriate
267 mathvariant counterpart specified by aMathVar. The mapped character is
268 typically located within Unicode's mathematical blocks (0x1D***, 0x1EE**) but
269 there are exceptions which this function accounts for.
270 Characters without a valid mapping or valid aMathvar value are returned
271 unaltered. Characters already in the mathematical blocks (or are one of the
272 exceptions) are never transformed.
273 Acceptable values for aMathVar are specified in layout/style/nsStyleConsts.h.
274 The transformable characters can be found at:
275 http://lists.w3.org/Archives/Public/www-math/2013Sep/0012.html and
276 https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols
279 MathVariant(uint32_t aCh
, uint8_t aMathVar
)
288 CharacterType varType
;
292 if (aMathVar
<= NS_MATHML_MATHVARIANT_NORMAL
) {
293 // nothing to do here
296 if (aMathVar
> NS_MATHML_MATHVARIANT_STRETCHED
) {
297 NS_ASSERTION(false, "Illegal mathvariant value");
301 // Exceptional characters with at most one possible transformation
302 if (aCh
== HOLE_GREEK_UPPER_THETA
) {
303 // Nothing at this code point is transformed
306 if (aCh
== GREEK_LETTER_DIGAMMA
) {
307 if (aMathVar
== NS_MATHML_MATHVARIANT_BOLD
) {
308 return MATH_BOLD_CAPITAL_DIGAMMA
;
312 if (aCh
== GREEK_SMALL_LETTER_DIGAMMA
) {
313 if (aMathVar
== NS_MATHML_MATHVARIANT_BOLD
) {
314 return MATH_BOLD_SMALL_DIGAMMA
;
318 if (aCh
== LATIN_SMALL_LETTER_DOTLESS_I
) {
319 if (aMathVar
== NS_MATHML_MATHVARIANT_ITALIC
) {
320 return MATH_ITALIC_SMALL_DOTLESS_I
;
324 if (aCh
== LATIN_SMALL_LETTER_DOTLESS_J
) {
325 if (aMathVar
== NS_MATHML_MATHVARIANT_ITALIC
) {
326 return MATH_ITALIC_SMALL_DOTLESS_J
;
331 // The Unicode mathematical blocks are divided into four segments: Latin,
332 // Greek, numbers and Arabic. In the case of the first three
333 // baseChar represents the relative order in which the characters are
334 // encoded in the Unicode mathematical block, normalised to the first
335 // character of that sequence.
337 if ('A' <= aCh
&& aCh
<= 'Z') {
338 baseChar
= aCh
- 'A';
340 } else if ('a' <= aCh
&& aCh
<= 'z') {
341 // Lowercase characters are placed immediately after the uppercase
342 // characters in the Unicode mathematical block. The constant subtraction
343 // represents the number of characters between the start of the sequence
344 // (capital A) and the first lowercase letter.
345 baseChar
= MATH_BOLD_SMALL_A
-MATH_BOLD_UPPER_A
+ aCh
- 'a';
347 } else if ('0' <= aCh
&& aCh
<= '9') {
348 baseChar
= aCh
- '0';
350 } else if (GREEK_UPPER_ALPHA
<= aCh
&& aCh
<= GREEK_UPPER_OMEGA
) {
351 baseChar
= aCh
-GREEK_UPPER_ALPHA
;
352 varType
= kIsGreekish
;
353 } else if (GREEK_LOWER_ALPHA
<= aCh
&& aCh
<= GREEK_LOWER_OMEGA
) {
354 // Lowercase Greek comes after uppercase Greek.
355 // Note in this instance the presence of an additional character (Nabla)
356 // between the end of the uppercase Greek characters and the lowercase
358 baseChar
= MATH_BOLD_SMALL_ALPHA
- MATH_BOLD_UPPER_ALPHA
359 + aCh
-GREEK_LOWER_ALPHA
;
360 varType
= kIsGreekish
;
361 } else if (0x0600 <= aCh
&& aCh
<= 0x06FF) {
362 // Arabic characters are defined within this range
366 case GREEK_UPPER_THETA
:
367 baseChar
= MATH_BOLD_UPPER_THETA
-MATH_BOLD_UPPER_ALPHA
;
370 baseChar
= MATH_BOLD_NABLA
-MATH_BOLD_UPPER_ALPHA
;
372 case PARTIAL_DIFFERENTIAL
:
373 baseChar
= MATH_BOLD_PARTIAL_DIFFERENTIAL
- MATH_BOLD_UPPER_ALPHA
;
375 case GREEK_LUNATE_EPSILON_SYMBOL
:
376 baseChar
= MATH_BOLD_EPSILON_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
378 case GREEK_THETA_SYMBOL
:
379 baseChar
= MATH_BOLD_THETA_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
381 case GREEK_KAPPA_SYMBOL
:
382 baseChar
= MATH_BOLD_KAPPA_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
384 case GREEK_PHI_SYMBOL
:
385 baseChar
= MATH_BOLD_PHI_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
387 case GREEK_RHO_SYMBOL
:
388 baseChar
= MATH_BOLD_RHO_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
390 case GREEK_PI_SYMBOL
:
391 baseChar
= MATH_BOLD_PI_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
397 varType
= kIsGreekish
;
400 if (varType
== kIsNumber
) {
402 // Each possible number mathvariant is encoded in a single, contiguous
403 // block. For example the beginning of the double struck number range
404 // follows immediately after the end of the bold number range.
405 // multiplier represents the order of the sequences relative to the first
407 case NS_MATHML_MATHVARIANT_BOLD
:
410 case NS_MATHML_MATHVARIANT_DOUBLE_STRUCK
:
413 case NS_MATHML_MATHVARIANT_SANS_SERIF
:
416 case NS_MATHML_MATHVARIANT_BOLD_SANS_SERIF
:
419 case NS_MATHML_MATHVARIANT_MONOSPACE
:
423 // This mathvariant isn't defined for numbers or is otherwise normal
426 // As the ranges are contiguous, to find the desired mathvariant range it
427 // is sufficient to multiply the position within the sequence order
428 // (multiplier) with the period of the sequence (which is constant for all
429 // number sequences) and to add the character point of the first character
430 // within the number mathvariant range.
431 // To this the baseChar calculated earlier is added to obtain the final
433 return baseChar
+multiplier
*(MATH_DOUBLE_STRUCK_ZERO
-MATH_BOLD_DIGIT_ZERO
)
434 +MATH_BOLD_DIGIT_ZERO
;
435 } else if (varType
== kIsGreekish
) {
437 case NS_MATHML_MATHVARIANT_BOLD
:
440 case NS_MATHML_MATHVARIANT_ITALIC
:
443 case NS_MATHML_MATHVARIANT_BOLD_ITALIC
:
446 case NS_MATHML_MATHVARIANT_BOLD_SANS_SERIF
:
449 case NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC
:
453 // This mathvariant isn't defined for Greek or is otherwise normal
456 // See the kIsNumber case for an explanation of the following calculation
457 return baseChar
+ MATH_BOLD_UPPER_ALPHA
+
458 multiplier
*(MATH_ITALIC_UPPER_ALPHA
- MATH_BOLD_UPPER_ALPHA
);
463 if (varType
== kIsArabic
) {
464 const MathVarMapping
* mapTable
;
465 uint32_t tableLength
;
467 /* The Arabic mathematical block is not continuous, nor does it have a
468 * monotonic mapping to the unencoded characters, requiring the use of a
471 case NS_MATHML_MATHVARIANT_INITIAL
:
472 mapTable
= gArabicInitialMapTable
;
473 tableLength
= ArrayLength(gArabicInitialMapTable
);
475 case NS_MATHML_MATHVARIANT_TAILED
:
476 mapTable
= gArabicTailedMapTable
;
477 tableLength
= ArrayLength(gArabicTailedMapTable
);
479 case NS_MATHML_MATHVARIANT_STRETCHED
:
480 mapTable
= gArabicStretchedMapTable
;
481 tableLength
= ArrayLength(gArabicStretchedMapTable
);
483 case NS_MATHML_MATHVARIANT_LOOPED
:
484 mapTable
= gArabicLoopedMapTable
;
485 tableLength
= ArrayLength(gArabicLoopedMapTable
);
487 case NS_MATHML_MATHVARIANT_DOUBLE_STRUCK
:
488 mapTable
= gArabicDoubleMapTable
;
489 tableLength
= ArrayLength(gArabicDoubleMapTable
);
492 // No valid transformations exist
495 newChar
= MathvarMappingSearch(aCh
, mapTable
, tableLength
);
498 if (aMathVar
> NS_MATHML_MATHVARIANT_MONOSPACE
) {
499 // Latin doesn't support the Arabic mathvariants
502 multiplier
= aMathVar
- 2;
503 // This is possible because the values for NS_MATHML_MATHVARIANT_* are
504 // chosen to coincide with the order in which the encoded mathvariant
505 // characters are located within their unicode block (less an offset to
506 // avoid _NONE and _NORMAL variants)
507 // See the kIsNumber case for an explanation of the following calculation
508 tempChar
= baseChar
+ MATH_BOLD_UPPER_A
+
509 multiplier
*(MATH_ITALIC_UPPER_A
- MATH_BOLD_UPPER_A
);
510 // There are roughly twenty characters that are located outside of the
511 // mathematical block, so the spaces where they ought to be are used
512 // as keys for a lookup table containing the correct character mappings.
513 newChar
= MathvarMappingSearch(tempChar
, gLatinExceptionMapTable
,
514 ArrayLength(gLatinExceptionMapTable
));
519 } else if (varType
== kIsLatin
) {
522 // An Arabic character without a corresponding mapping
528 #define TT_SSTY TRUETYPE_TAG('s', 's', 't', 'y')
529 #define TT_DTLS TRUETYPE_TAG('d', 't', 'l', 's')
532 MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun
* aTextRun
,
533 gfxContext
* aRefContext
,
534 gfxMissingFontRecorder
* aMFR
)
536 gfxFontGroup
* fontGroup
= aTextRun
->GetFontGroup();
538 nsAutoString convertedString
;
539 nsAutoTArray
<bool,50> charsToMergeArray
;
540 nsAutoTArray
<bool,50> deletedCharsArray
;
541 nsAutoTArray
<nsStyleContext
*,50> styleArray
;
542 nsAutoTArray
<uint8_t,50> canBreakBeforeArray
;
543 bool mergeNeeded
= false;
546 aTextRun
->GetFlags() & nsTextFrameUtils::TEXT_IS_SINGLE_CHAR_MI
;
548 uint32_t length
= aTextRun
->GetLength();
549 const char16_t
* str
= aTextRun
->mString
.BeginReading();
550 nsRefPtr
<nsStyleContext
>* styles
= aTextRun
->mStyles
.Elements();
553 font
= styles
[0]->StyleFont()->mFont
;
555 if (mSSTYScriptLevel
|| (mFlags
& MATH_FONT_FEATURE_DTLS
)) {
556 bool foundSSTY
= false;
557 bool foundDTLS
= false;
558 // We respect ssty settings explicitly set by the user
559 for (uint32_t i
= 0; i
< font
.fontFeatureSettings
.Length(); i
++) {
560 if (font
.fontFeatureSettings
[i
].mTag
== TT_SSTY
) {
562 } else if (font
.fontFeatureSettings
[i
].mTag
== TT_DTLS
) {
566 if (mSSTYScriptLevel
&& !foundSSTY
) {
567 uint8_t sstyLevel
= 0;
568 float scriptScaling
= pow(styles
[0]->StyleFont()->mScriptSizeMultiplier
,
570 static_assert(NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
< 1,
571 "Shouldn't it make things smaller?");
573 An SSTY level of 2 is set if the scaling factor is less than or equal
574 to halfway between that for a scriptlevel of 1 (0.71) and that of a
575 scriptlevel of 2 (0.71^2), assuming the default script size multiplier.
576 An SSTY level of 1 is set if the script scaling factor is less than
577 or equal that for a scriptlevel of 1 assuming the default script size
580 User specified values of script size multiplier will change the scaling
581 factor which mSSTYScriptLevel values correspond to.
583 In the event that the script size multiplier actually makes things
584 larger, no change is made.
586 To opt out of this change, add the following to the stylesheet:
587 "font-feature-settings: 'ssty' 0"
589 if (scriptScaling
<= (NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
+
590 (NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
*
591 NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
))/2) {
592 // Currently only the first two ssty settings are used, so two is large
595 } else if (scriptScaling
<= NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
) {
599 gfxFontFeature settingSSTY
;
600 settingSSTY
.mTag
= TT_SSTY
;
601 settingSSTY
.mValue
= sstyLevel
;
602 font
.fontFeatureSettings
.AppendElement(settingSSTY
);
606 Apply the dtls font feature setting (dotless).
607 This gets applied to the base frame and all descendants of the base
608 frame of certain <mover> and <munderover> frames.
610 See nsMathMLmunderoverFrame.cpp for a full description.
612 To opt out of this change, add the following to the stylesheet:
613 "font-feature-settings: 'dtls' 0"
615 if ((mFlags
& MATH_FONT_FEATURE_DTLS
) && !foundDTLS
) {
616 gfxFontFeature settingDTLS
;
617 settingDTLS
.mTag
= TT_DTLS
;
618 settingDTLS
.mValue
= 1;
619 font
.fontFeatureSettings
.AppendElement(settingDTLS
);
624 uint8_t mathVar
= NS_MATHML_MATHVARIANT_NONE
;
625 bool doMathvariantStyling
= true;
627 for (uint32_t i
= 0; i
< length
; ++i
) {
629 nsStyleContext
* styleContext
= styles
[i
];
630 mathVar
= styleContext
->StyleFont()->mMathVariant
;
632 if (singleCharMI
&& mathVar
== NS_MATHML_MATHVARIANT_NONE
) {
633 // If the user has explicitly set a non-default value for fontstyle or
634 // fontweight, the italic mathvariant behaviour of <mi> is disabled
635 // This overrides the initial values specified in fontStyle, to avoid
636 // inconsistencies in which attributes allow CSS changes and which do not.
637 if (mFlags
& MATH_FONT_WEIGHT_BOLD
) {
638 font
.weight
= NS_FONT_WEIGHT_BOLD
;
639 if (mFlags
& MATH_FONT_STYLING_NORMAL
) {
640 font
.style
= NS_FONT_STYLE_NORMAL
;
642 font
.style
= NS_FONT_STYLE_ITALIC
;
644 } else if (mFlags
& MATH_FONT_STYLING_NORMAL
) {
645 font
.style
= NS_FONT_STYLE_NORMAL
;
646 font
.weight
= NS_FONT_WEIGHT_NORMAL
;
648 mathVar
= NS_MATHML_MATHVARIANT_ITALIC
;
652 uint32_t ch
= str
[i
];
653 if (NS_IS_HIGH_SURROGATE(ch
) && i
< length
- 1 &&
654 NS_IS_LOW_SURROGATE(str
[i
+ 1])) {
655 ch
= SURROGATE_TO_UCS4(ch
, str
[i
+ 1]);
657 uint32_t ch2
= MathVariant(ch
, mathVar
);
659 if (mathVar
== NS_MATHML_MATHVARIANT_BOLD
||
660 mathVar
== NS_MATHML_MATHVARIANT_BOLD_ITALIC
||
661 mathVar
== NS_MATHML_MATHVARIANT_ITALIC
) {
662 if (ch
== ch2
&& ch
!= 0x20 && ch
!= 0xA0) {
663 // Don't apply the CSS style if a character cannot be
664 // transformed. There is an exception for whitespace as it is both
665 // common and innocuous.
666 doMathvariantStyling
= false;
669 // Bug 930504. Some platforms do not have fonts for Mathematical
670 // Alphanumeric Symbols. Hence we check whether the transformed
671 // character is actually available.
673 nsRefPtr
<gfxFont
> mathFont
= fontGroup
->
674 FindFontForChar(ch2
, 0, 0, HB_SCRIPT_COMMON
, nullptr, &matchType
);
676 // Don't apply the CSS style if there is a math font for at least one
677 // of the transformed character in this text run.
678 doMathvariantStyling
= false;
680 // We fallback to the original character.
683 aMFR
->RecordScript(MOZ_SCRIPT_MATHEMATICAL_NOTATION
);
689 deletedCharsArray
.AppendElement(false);
690 charsToMergeArray
.AppendElement(false);
691 styleArray
.AppendElement(styleContext
);
692 canBreakBeforeArray
.AppendElement(aTextRun
->CanBreakLineBefore(i
));
694 if (IS_IN_BMP(ch2
)) {
695 convertedString
.Append(ch2
);
697 convertedString
.Append(H_SURROGATE(ch2
));
698 convertedString
.Append(L_SURROGATE(ch2
));
700 if (!IS_IN_BMP(ch
)) {
701 deletedCharsArray
.AppendElement(true); // not exactly deleted, but
702 // the trailing surrogate is skipped
707 while (extraChars
-- > 0) {
709 charsToMergeArray
.AppendElement(true);
710 styleArray
.AppendElement(styleContext
);
711 canBreakBeforeArray
.AppendElement(false);
716 gfxTextRunFactory::Parameters innerParams
=
717 GetParametersForInner(aTextRun
, &flags
, aRefContext
);
719 nsAutoPtr
<nsTransformedTextRun
> transformedChild
;
720 nsAutoPtr
<gfxTextRun
> cachedChild
;
723 if (mathVar
== NS_MATHML_MATHVARIANT_BOLD
&& doMathvariantStyling
) {
724 font
.style
= NS_FONT_STYLE_NORMAL
;
725 font
.weight
= NS_FONT_WEIGHT_BOLD
;
726 } else if (mathVar
== NS_MATHML_MATHVARIANT_ITALIC
&& doMathvariantStyling
) {
727 font
.style
= NS_FONT_STYLE_ITALIC
;
728 font
.weight
= NS_FONT_WEIGHT_NORMAL
;
729 } else if (mathVar
== NS_MATHML_MATHVARIANT_BOLD_ITALIC
&&
730 doMathvariantStyling
) {
731 font
.style
= NS_FONT_STYLE_ITALIC
;
732 font
.weight
= NS_FONT_WEIGHT_BOLD
;
733 } else if (mathVar
!= NS_MATHML_MATHVARIANT_NONE
) {
734 // Mathvariant overrides fontstyle and fontweight
735 // Need to check to see if mathvariant is actually applied as this function
736 // is used for other purposes.
737 font
.style
= NS_FONT_STYLE_NORMAL
;
738 font
.weight
= NS_FONT_WEIGHT_NORMAL
;
740 gfxFontGroup
* newFontGroup
= nullptr;
742 // Get the correct gfxFontGroup that corresponds to the earlier font changes.
744 font
.size
= NSToCoordRound(font
.size
* mFontInflation
);
745 nsPresContext
* pc
= styles
[0]->PresContext();
746 nsRefPtr
<nsFontMetrics
> metrics
;
747 const nsStyleFont
* styleFont
= styles
[0]->StyleFont();
748 pc
->DeviceContext()->GetMetricsFor(font
,
749 styleFont
->mLanguage
,
750 styleFont
->mExplicitLanguage
,
751 gfxFont::eHorizontal
,
752 pc
->GetUserFontSet(),
753 pc
->GetTextPerfMetrics(),
754 *getter_AddRefs(metrics
));
756 newFontGroup
= metrics
->GetThebesFontGroup();
761 // If we can't get a new font group, fall back to the old one. Rendering
762 // will be incorrect, but not significantly so.
763 newFontGroup
= fontGroup
;
766 if (mInnerTransformingTextRunFactory
) {
767 transformedChild
= mInnerTransformingTextRunFactory
->MakeTextRun(
768 convertedString
.BeginReading(), convertedString
.Length(),
769 &innerParams
, newFontGroup
, flags
, styleArray
.Elements(), false);
770 child
= transformedChild
.get();
772 cachedChild
= newFontGroup
->MakeTextRun(
773 convertedString
.BeginReading(), convertedString
.Length(),
774 &innerParams
, flags
, aMFR
);
775 child
= cachedChild
.get();
779 // Copy potential linebreaks into child so they're preserved
780 // (and also child will be shaped appropriately)
781 NS_ASSERTION(convertedString
.Length() == canBreakBeforeArray
.Length(),
782 "Dropped characters or break-before values somewhere!");
783 child
->SetPotentialLineBreaks(0, canBreakBeforeArray
.Length(),
784 canBreakBeforeArray
.Elements(), aRefContext
);
785 if (transformedChild
) {
786 transformedChild
->FinishSettingProperties(aRefContext
, aMFR
);
790 // Now merge multiple characters into one multi-glyph character as required
791 NS_ASSERTION(charsToMergeArray
.Length() == child
->GetLength(),
792 "source length mismatch");
793 NS_ASSERTION(deletedCharsArray
.Length() == aTextRun
->GetLength(),
794 "destination length mismatch");
795 MergeCharactersInTextRun(aTextRun
, child
, charsToMergeArray
.Elements(),
796 deletedCharsArray
.Elements());
798 // No merging to do, so just copy; this produces a more optimized textrun.
799 // We can't steal the data because the child may be cached and stealing
800 // the data would break the cache.
801 aTextRun
->ResetGlyphRuns();
802 aTextRun
->CopyGlyphDataFrom(child
, 0, child
->GetLength(), 0);