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"
10 #include "nsStyleConsts.h"
11 #include "nsStyleContext.h"
12 #include "nsTextFrameUtils.h"
13 #include "nsFontMetrics.h"
14 #include "nsDeviceContext.h"
16 using namespace mozilla
;
19 Entries for the mathvariant lookup tables. mKey represents the Unicode
20 character to be transformed and is used for searching the tables.
21 mReplacement represents the mapped mathvariant Unicode character.
26 uint32_t mReplacement
;
30 Lookup tables for use with mathvariant mappings to transform a unicode
31 character point to another unicode character that indicates the proper output.
32 mKey represents one of two concepts.
33 1. In the Latin table it represents a hole in the mathematical alphanumeric
34 block, where the character that should occupy that position is located
36 2. It represents an Arabic letter.
38 As a replacement, 0 is reserved to indicate no mapping was found.
40 static const MathVarMapping gArabicInitialMapTable
[] = {
63 static const MathVarMapping gArabicTailedMapTable
[] = {
81 static const MathVarMapping gArabicStretchedMapTable
[] = {
107 static const MathVarMapping gArabicLoopedMapTable
[] = {
137 static const MathVarMapping gArabicDoubleMapTable
[] = {
165 static const MathVarMapping gLatinExceptionMapTable
[] = {
192 // Finds a MathVarMapping struct with the specified key (aKey) within aTable.
193 // aTable must be an array, whose length is specified by aNumElements
195 MathvarMappingSearch(uint32_t aKey
, const MathVarMapping
* aTable
, uint32_t aNumElements
)
198 uint32_t high
= aNumElements
;
200 uint32_t midPoint
= (low
+high
) >> 1;
201 if (aKey
== aTable
[midPoint
].mKey
) {
202 return aTable
[midPoint
].mReplacement
;
204 if (aKey
> aTable
[midPoint
].mKey
) {
213 #define GREEK_UPPER_THETA 0x03F4
214 #define HOLE_GREEK_UPPER_THETA 0x03A2
216 #define PARTIAL_DIFFERENTIAL 0x2202
217 #define GREEK_UPPER_ALPHA 0x0391
218 #define GREEK_UPPER_OMEGA 0x03A9
219 #define GREEK_LOWER_ALPHA 0x03B1
220 #define GREEK_LOWER_OMEGA 0x03C9
221 #define GREEK_LUNATE_EPSILON_SYMBOL 0x03F5
222 #define GREEK_THETA_SYMBOL 0x03D1
223 #define GREEK_KAPPA_SYMBOL 0x03F0
224 #define GREEK_PHI_SYMBOL 0x03D5
225 #define GREEK_RHO_SYMBOL 0x03F1
226 #define GREEK_PI_SYMBOL 0x03D6
227 #define GREEK_LETTER_DIGAMMA 0x03DC
228 #define GREEK_SMALL_LETTER_DIGAMMA 0x03DD
229 #define MATH_BOLD_CAPITAL_DIGAMMA 0x1D7CA
230 #define MATH_BOLD_SMALL_DIGAMMA 0x1D7CB
232 #define LATIN_SMALL_LETTER_DOTLESS_I 0x0131
233 #define LATIN_SMALL_LETTER_DOTLESS_J 0x0237
235 #define MATH_ITALIC_SMALL_DOTLESS_I 0x1D6A4
236 #define MATH_ITALIC_SMALL_DOTLESS_J 0x1D6A5
238 #define MATH_BOLD_UPPER_A 0x1D400
239 #define MATH_ITALIC_UPPER_A 0x1D434
240 #define MATH_BOLD_SMALL_A 0x1D41A
241 #define MATH_BOLD_UPPER_ALPHA 0x1D6A8
242 #define MATH_BOLD_SMALL_ALPHA 0x1D6C2
243 #define MATH_ITALIC_UPPER_ALPHA 0x1D6E2
244 #define MATH_BOLD_DIGIT_ZERO 0x1D7CE
245 #define MATH_DOUBLE_STRUCK_ZERO 0x1D7D8
247 #define MATH_BOLD_UPPER_THETA 0x1D6B9
248 #define MATH_BOLD_NABLA 0x1D6C1
249 #define MATH_BOLD_PARTIAL_DIFFERENTIAL 0x1D6DB
250 #define MATH_BOLD_EPSILON_SYMBOL 0x1D6DC
251 #define MATH_BOLD_THETA_SYMBOL 0x1D6DD
252 #define MATH_BOLD_KAPPA_SYMBOL 0x1D6DE
253 #define MATH_BOLD_PHI_SYMBOL 0x1D6DF
254 #define MATH_BOLD_RHO_SYMBOL 0x1D6E0
255 #define MATH_BOLD_PI_SYMBOL 0x1D6E1
258 Performs the character mapping needed to implement MathML's mathvariant
259 attribute. It takes a unicode character and maps it to its appropriate
260 mathvariant counterpart specified by aMathVar. The mapped character is
261 typically located within Unicode's mathematical blocks (0x1D***, 0x1EE**) but
262 there are exceptions which this function accounts for.
263 Characters without a valid mapping or valid aMathvar value are returned
264 unaltered. Characters already in the mathematical blocks (or are one of the
265 exceptions) are never transformed.
266 Acceptable values for aMathVar are specified in layout/style/nsStyleConsts.h.
267 The transformable characters can be found at:
268 http://lists.w3.org/Archives/Public/www-math/2013Sep/0012.html and
269 https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols
272 MathVariant(uint32_t aCh
, uint8_t aMathVar
)
281 CharacterType varType
;
285 if (aMathVar
<= NS_MATHML_MATHVARIANT_NORMAL
) {
286 // nothing to do here
289 if (aMathVar
> NS_MATHML_MATHVARIANT_STRETCHED
) {
290 NS_ASSERTION(false, "Illegal mathvariant value");
294 // Exceptional characters with at most one possible transformation
295 if (aCh
== HOLE_GREEK_UPPER_THETA
) {
296 // Nothing at this code point is transformed
299 if (aCh
== GREEK_LETTER_DIGAMMA
) {
300 if (aMathVar
== NS_MATHML_MATHVARIANT_BOLD
) {
301 return MATH_BOLD_CAPITAL_DIGAMMA
;
305 if (aCh
== GREEK_SMALL_LETTER_DIGAMMA
) {
306 if (aMathVar
== NS_MATHML_MATHVARIANT_BOLD
) {
307 return MATH_BOLD_SMALL_DIGAMMA
;
311 if (aCh
== LATIN_SMALL_LETTER_DOTLESS_I
) {
312 if (aMathVar
== NS_MATHML_MATHVARIANT_ITALIC
) {
313 return MATH_ITALIC_SMALL_DOTLESS_I
;
317 if (aCh
== LATIN_SMALL_LETTER_DOTLESS_J
) {
318 if (aMathVar
== NS_MATHML_MATHVARIANT_ITALIC
) {
319 return MATH_ITALIC_SMALL_DOTLESS_J
;
324 // The Unicode mathematical blocks are divided into four segments: Latin,
325 // Greek, numbers and Arabic. In the case of the first three
326 // baseChar represents the relative order in which the characters are
327 // encoded in the Unicode mathematical block, normalised to the first
328 // character of that sequence.
330 if ('A' <= aCh
&& aCh
<= 'Z') {
331 baseChar
= aCh
- 'A';
333 } else if ('a' <= aCh
&& aCh
<= 'z') {
334 // Lowercase characters are placed immediately after the uppercase
335 // characters in the Unicode mathematical block. The constant subtraction
336 // represents the number of characters between the start of the sequence
337 // (capital A) and the first lowercase letter.
338 baseChar
= MATH_BOLD_SMALL_A
-MATH_BOLD_UPPER_A
+ aCh
- 'a';
340 } else if ('0' <= aCh
&& aCh
<= '9') {
341 baseChar
= aCh
- '0';
343 } else if (GREEK_UPPER_ALPHA
<= aCh
&& aCh
<= GREEK_UPPER_OMEGA
) {
344 baseChar
= aCh
-GREEK_UPPER_ALPHA
;
345 varType
= kIsGreekish
;
346 } else if (GREEK_LOWER_ALPHA
<= aCh
&& aCh
<= GREEK_LOWER_OMEGA
) {
347 // Lowercase Greek comes after uppercase Greek.
348 // Note in this instance the presence of an additional character (Nabla)
349 // between the end of the uppercase Greek characters and the lowercase
351 baseChar
= MATH_BOLD_SMALL_ALPHA
- MATH_BOLD_UPPER_ALPHA
352 + aCh
-GREEK_LOWER_ALPHA
;
353 varType
= kIsGreekish
;
354 } else if (0x0600 <= aCh
&& aCh
<= 0x06FF) {
355 // Arabic characters are defined within this range
359 case GREEK_UPPER_THETA
:
360 baseChar
= MATH_BOLD_UPPER_THETA
-MATH_BOLD_UPPER_ALPHA
;
363 baseChar
= MATH_BOLD_NABLA
-MATH_BOLD_UPPER_ALPHA
;
365 case PARTIAL_DIFFERENTIAL
:
366 baseChar
= MATH_BOLD_PARTIAL_DIFFERENTIAL
- MATH_BOLD_UPPER_ALPHA
;
368 case GREEK_LUNATE_EPSILON_SYMBOL
:
369 baseChar
= MATH_BOLD_EPSILON_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
371 case GREEK_THETA_SYMBOL
:
372 baseChar
= MATH_BOLD_THETA_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
374 case GREEK_KAPPA_SYMBOL
:
375 baseChar
= MATH_BOLD_KAPPA_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
377 case GREEK_PHI_SYMBOL
:
378 baseChar
= MATH_BOLD_PHI_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
380 case GREEK_RHO_SYMBOL
:
381 baseChar
= MATH_BOLD_RHO_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
383 case GREEK_PI_SYMBOL
:
384 baseChar
= MATH_BOLD_PI_SYMBOL
- MATH_BOLD_UPPER_ALPHA
;
390 varType
= kIsGreekish
;
393 if (varType
== kIsNumber
) {
395 // Each possible number mathvariant is encoded in a single, contiguous
396 // block. For example the beginning of the double struck number range
397 // follows immediately after the end of the bold number range.
398 // multiplier represents the order of the sequences relative to the first
400 case NS_MATHML_MATHVARIANT_BOLD
:
403 case NS_MATHML_MATHVARIANT_DOUBLE_STRUCK
:
406 case NS_MATHML_MATHVARIANT_SANS_SERIF
:
409 case NS_MATHML_MATHVARIANT_BOLD_SANS_SERIF
:
412 case NS_MATHML_MATHVARIANT_MONOSPACE
:
416 // This mathvariant isn't defined for numbers or is otherwise normal
419 // As the ranges are contiguous, to find the desired mathvariant range it
420 // is sufficient to multiply the position within the sequence order
421 // (multiplier) with the period of the sequence (which is constant for all
422 // number sequences) and to add the character point of the first character
423 // within the number mathvariant range.
424 // To this the baseChar calculated earlier is added to obtain the final
426 return baseChar
+multiplier
*(MATH_DOUBLE_STRUCK_ZERO
-MATH_BOLD_DIGIT_ZERO
)
427 +MATH_BOLD_DIGIT_ZERO
;
428 } else if (varType
== kIsGreekish
) {
430 case NS_MATHML_MATHVARIANT_BOLD
:
433 case NS_MATHML_MATHVARIANT_ITALIC
:
436 case NS_MATHML_MATHVARIANT_BOLD_ITALIC
:
439 case NS_MATHML_MATHVARIANT_BOLD_SANS_SERIF
:
442 case NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC
:
446 // This mathvariant isn't defined for Greek or is otherwise normal
449 // See the kIsNumber case for an explanation of the following calculation
450 return baseChar
+ MATH_BOLD_UPPER_ALPHA
+
451 multiplier
*(MATH_ITALIC_UPPER_ALPHA
- MATH_BOLD_UPPER_ALPHA
);
456 if (varType
== kIsArabic
) {
457 const MathVarMapping
* mapTable
;
458 uint32_t tableLength
;
460 /* The Arabic mathematical block is not continuous, nor does it have a
461 * monotonic mapping to the unencoded characters, requiring the use of a
464 case NS_MATHML_MATHVARIANT_INITIAL
:
465 mapTable
= gArabicInitialMapTable
;
466 tableLength
= ArrayLength(gArabicInitialMapTable
);
468 case NS_MATHML_MATHVARIANT_TAILED
:
469 mapTable
= gArabicTailedMapTable
;
470 tableLength
= ArrayLength(gArabicTailedMapTable
);
472 case NS_MATHML_MATHVARIANT_STRETCHED
:
473 mapTable
= gArabicStretchedMapTable
;
474 tableLength
= ArrayLength(gArabicStretchedMapTable
);
476 case NS_MATHML_MATHVARIANT_LOOPED
:
477 mapTable
= gArabicLoopedMapTable
;
478 tableLength
= ArrayLength(gArabicLoopedMapTable
);
480 case NS_MATHML_MATHVARIANT_DOUBLE_STRUCK
:
481 mapTable
= gArabicDoubleMapTable
;
482 tableLength
= ArrayLength(gArabicDoubleMapTable
);
485 // No valid transformations exist
488 newChar
= MathvarMappingSearch(aCh
, mapTable
, tableLength
);
491 if (aMathVar
> NS_MATHML_MATHVARIANT_MONOSPACE
) {
492 // Latin doesn't support the Arabic mathvariants
495 multiplier
= aMathVar
- 2;
496 // This is possible because the values for NS_MATHML_MATHVARIANT_* are
497 // chosen to coincide with the order in which the encoded mathvariant
498 // characters are located within their unicode block (less an offset to
499 // avoid _NONE and _NORMAL variants)
500 // See the kIsNumber case for an explanation of the following calculation
501 tempChar
= baseChar
+ MATH_BOLD_UPPER_A
+
502 multiplier
*(MATH_ITALIC_UPPER_A
- MATH_BOLD_UPPER_A
);
503 // There are roughly twenty characters that are located outside of the
504 // mathematical block, so the spaces where they ought to be are used
505 // as keys for a lookup table containing the correct character mappings.
506 newChar
= MathvarMappingSearch(tempChar
, gLatinExceptionMapTable
,
507 ArrayLength(gLatinExceptionMapTable
));
512 } else if (varType
== kIsLatin
) {
515 // An Arabic character without a corresponding mapping
522 MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun
* aTextRun
,
523 gfxContext
* aRefContext
)
525 gfxFontGroup
* fontGroup
= aTextRun
->GetFontGroup();
527 nsAutoString convertedString
;
528 nsAutoTArray
<bool,50> charsToMergeArray
;
529 nsAutoTArray
<bool,50> deletedCharsArray
;
530 nsAutoTArray
<nsStyleContext
*,50> styleArray
;
531 nsAutoTArray
<uint8_t,50> canBreakBeforeArray
;
532 bool mergeNeeded
= false;
535 aTextRun
->GetFlags() & nsTextFrameUtils::TEXT_IS_SINGLE_CHAR_MI
;
537 uint32_t length
= aTextRun
->GetLength();
538 const char16_t
* str
= aTextRun
->mString
.BeginReading();
539 nsRefPtr
<nsStyleContext
>* styles
= aTextRun
->mStyles
.Elements();
542 font
= styles
[0]->StyleFont()->mFont
;
544 if (mSSTYScriptLevel
) {
546 // We respect ssty settings explicitly set by the user
547 for (uint32_t i
= 0; i
< font
.fontFeatureSettings
.Length(); i
++) {
548 if (font
.fontFeatureSettings
[i
].mTag
== TRUETYPE_TAG('s', 's', 't', 'y')) {
554 uint8_t sstyLevel
= 0;
555 float scriptScaling
= pow(styles
[0]->StyleFont()->mScriptSizeMultiplier
,
557 static_assert(NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
< 1,
558 "Shouldn't it make things smaller?");
560 An SSTY level of 2 is set if the scaling factor is less than or equal
561 to halfway between that for a scriptlevel of 1 (0.71) and that of a
562 scriptlevel of 2 (0.71^2), assuming the default script size multiplier.
563 An SSTY level of 1 is set if the script scaling factor is less than
564 or equal that for a scriptlevel of 1 assuming the default script size
567 User specified values of script size multiplier will change the scaling
568 factor which mSSTYScriptLevel values correspond to.
570 In the event that the script size multiplier actually makes things
571 larger, no change is made.
573 To opt out of this change, add the following to the stylesheet:
574 "font-feature-settings: 'ssty' 0"
576 if (scriptScaling
<= (NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
+
577 (NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
*
578 NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
))/2) {
579 // Currently only the first two ssty settings are used, so two is large
582 } else if (scriptScaling
<= NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER
) {
586 gfxFontFeature settingSSTY
;
587 settingSSTY
.mTag
= TRUETYPE_TAG('s','s','t','y');
588 settingSSTY
.mValue
= sstyLevel
;
589 font
.fontFeatureSettings
.AppendElement(settingSSTY
);
595 uint8_t mathVar
= NS_MATHML_MATHVARIANT_NONE
;
596 bool doMathvariantStyling
= true;
598 for (uint32_t i
= 0; i
< length
; ++i
) {
600 nsStyleContext
* styleContext
= styles
[i
];
601 mathVar
= styleContext
->StyleFont()->mMathVariant
;
603 if (singleCharMI
&& mathVar
== NS_MATHML_MATHVARIANT_NONE
) {
604 // If the user has explicitly set a non-default value for fontstyle or
605 // fontweight, the italic mathvariant behaviour of <mi> is disabled
606 // This overrides the initial values specified in fontStyle, to avoid
607 // inconsistencies in which attributes allow CSS changes and which do not.
608 if (mFlags
& MATH_FONT_WEIGHT_BOLD
) {
609 font
.weight
= NS_FONT_WEIGHT_BOLD
;
610 if (mFlags
& MATH_FONT_STYLING_NORMAL
) {
611 font
.style
= NS_FONT_STYLE_NORMAL
;
613 font
.style
= NS_FONT_STYLE_ITALIC
;
615 } else if (mFlags
& MATH_FONT_STYLING_NORMAL
) {
616 font
.style
= NS_FONT_STYLE_NORMAL
;
617 font
.weight
= NS_FONT_WEIGHT_NORMAL
;
619 mathVar
= NS_MATHML_MATHVARIANT_ITALIC
;
623 uint32_t ch
= str
[i
];
624 if (NS_IS_HIGH_SURROGATE(ch
) && i
< length
- 1 &&
625 NS_IS_LOW_SURROGATE(str
[i
+ 1])) {
626 ch
= SURROGATE_TO_UCS4(ch
, str
[i
+ 1]);
628 uint32_t ch2
= MathVariant(ch
, mathVar
);
630 if (mathVar
== NS_MATHML_MATHVARIANT_BOLD
||
631 mathVar
== NS_MATHML_MATHVARIANT_BOLD_ITALIC
||
632 mathVar
== NS_MATHML_MATHVARIANT_ITALIC
) {
633 if (ch
== ch2
&& ch
!= 0x20 && ch
!= 0xA0) {
634 // Don't apply the CSS style if a character cannot be
635 // transformed. There is an exception for whitespace as it is both
636 // common and innocuous.
637 doMathvariantStyling
= false;
640 // Bug 930504. Some platforms do not have fonts for Mathematical
641 // Alphanumeric Symbols. Hence we check whether the transformed
642 // character is actually available.
644 nsRefPtr
<gfxFont
> mathFont
= fontGroup
->
645 FindFontForChar(ch2
, 0, HB_SCRIPT_COMMON
, nullptr, &matchType
);
647 // Don't apply the CSS style if there is a math font for at least one
648 // of the transformed character in this text run.
649 doMathvariantStyling
= false;
651 // We fallback to the original character.
657 deletedCharsArray
.AppendElement(false);
658 charsToMergeArray
.AppendElement(false);
659 styleArray
.AppendElement(styleContext
);
660 canBreakBeforeArray
.AppendElement(aTextRun
->CanBreakLineBefore(i
));
662 if (IS_IN_BMP(ch2
)) {
663 convertedString
.Append(ch2
);
665 convertedString
.Append(H_SURROGATE(ch2
));
666 convertedString
.Append(L_SURROGATE(ch2
));
668 if (!IS_IN_BMP(ch
)) {
669 deletedCharsArray
.AppendElement(true); // not exactly deleted, but
670 // the trailing surrogate is skipped
675 while (extraChars
-- > 0) {
677 charsToMergeArray
.AppendElement(true);
678 styleArray
.AppendElement(styleContext
);
679 canBreakBeforeArray
.AppendElement(false);
684 gfxTextRunFactory::Parameters innerParams
=
685 GetParametersForInner(aTextRun
, &flags
, aRefContext
);
687 nsAutoPtr
<nsTransformedTextRun
> transformedChild
;
688 nsAutoPtr
<gfxTextRun
> cachedChild
;
691 if (mathVar
== NS_MATHML_MATHVARIANT_BOLD
&& doMathvariantStyling
) {
692 font
.style
= NS_FONT_STYLE_NORMAL
;
693 font
.weight
= NS_FONT_WEIGHT_BOLD
;
694 } else if (mathVar
== NS_MATHML_MATHVARIANT_ITALIC
&& doMathvariantStyling
) {
695 font
.style
= NS_FONT_STYLE_ITALIC
;
696 font
.weight
= NS_FONT_WEIGHT_NORMAL
;
697 } else if (mathVar
== NS_MATHML_MATHVARIANT_BOLD_ITALIC
&&
698 doMathvariantStyling
) {
699 font
.style
= NS_FONT_STYLE_ITALIC
;
700 font
.weight
= NS_FONT_WEIGHT_BOLD
;
701 } else if (mathVar
!= NS_MATHML_MATHVARIANT_NONE
) {
702 // Mathvariant overrides fontstyle and fontweight
703 // Need to check to see if mathvariant is actually applied as this function
704 // is used for other purposes.
705 font
.style
= NS_FONT_STYLE_NORMAL
;
706 font
.weight
= NS_FONT_WEIGHT_NORMAL
;
708 gfxFontGroup
* newFontGroup
= nullptr;
710 // Get the correct gfxFontGroup that corresponds to the earlier font changes.
712 nsPresContext
* pc
= styles
[0]->PresContext();
713 nsRefPtr
<nsFontMetrics
> metrics
;
714 pc
->DeviceContext()->GetMetricsFor(font
,
715 styles
[0]->StyleFont()->mLanguage
,
716 pc
->GetUserFontSet(),
717 pc
->GetTextPerfMetrics(),
718 *getter_AddRefs(metrics
));
720 newFontGroup
= metrics
->GetThebesFontGroup();
725 // If we can't get a new font group, fall back to the old one. Rendering
726 // will be incorrect, but not significantly so.
727 newFontGroup
= fontGroup
;
730 if (mInnerTransformingTextRunFactory
) {
731 transformedChild
= mInnerTransformingTextRunFactory
->MakeTextRun(
732 convertedString
.BeginReading(), convertedString
.Length(),
733 &innerParams
, newFontGroup
, flags
, styleArray
.Elements(), false);
734 child
= transformedChild
.get();
736 cachedChild
= newFontGroup
->MakeTextRun(
737 convertedString
.BeginReading(), convertedString
.Length(),
738 &innerParams
, flags
);
739 child
= cachedChild
.get();
743 // Copy potential linebreaks into child so they're preserved
744 // (and also child will be shaped appropriately)
745 NS_ASSERTION(convertedString
.Length() == canBreakBeforeArray
.Length(),
746 "Dropped characters or break-before values somewhere!");
747 child
->SetPotentialLineBreaks(0, canBreakBeforeArray
.Length(),
748 canBreakBeforeArray
.Elements(), aRefContext
);
749 if (transformedChild
) {
750 transformedChild
->FinishSettingProperties(aRefContext
);
754 // Now merge multiple characters into one multi-glyph character as required
755 NS_ASSERTION(charsToMergeArray
.Length() == child
->GetLength(),
756 "source length mismatch");
757 NS_ASSERTION(deletedCharsArray
.Length() == aTextRun
->GetLength(),
758 "destination length mismatch");
759 MergeCharactersInTextRun(aTextRun
, child
, charsToMergeArray
.Elements(),
760 deletedCharsArray
.Elements());
762 // No merging to do, so just copy; this produces a more optimized textrun.
763 // We can't steal the data because the child may be cached and stealing
764 // the data would break the cache.
765 aTextRun
->ResetGlyphRuns();
766 aTextRun
->CopyGlyphDataFrom(child
, 0, child
->GetLength(), 0);