400 already_AddRefed<gfxFont>
401 gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript)
402 {
404 FontEntry *fe = static_cast<FontEntry*>
405 (gfxPlatformFontList::PlatformFontList()->
406 SystemFindFontForChar(aCh, aRunScript, &mStyle));
407 if (fe) {
408 nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
409 nsRefPtr<gfxFont> font = f.get();
410 return font.forget();
411 }
420 return nsnull;
421 }
3982 already_AddRefed<gfxFont>
3983 gfxFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript)
3984 {
3985 gfxFontEntry *fe =
3986 gfxPlatformFontList::PlatformFontList()->
3987 SystemFindFontForChar(aCh, aRunScript, &mStyle);
3988 if (fe) {
3989
3990 nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, false);
3991 return font.forget();
3992 }
3993
3994 return nsnull;
3995 }
441 gfxFontEntry*
442 gfxPlatformFontList::SystemFindFontForChar(const PRUint32 aCh,
443 PRInt32 aRunScript,
444 const gfxFontStyle* aStyle)
445 {
446 gfxFontEntry* fontEntry = nsnull;
447
448
449 if (mCodepointsWithNoFonts.test(aCh)) {
450 return nsnull;
451 }
452
453
454
455
456
457
458 if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
459 bool needsBold;
460
461 fontEntry = FindFontForFamily(mReplacementCharFallbackFamily,
462 aStyle, needsBold);
463
464 if (fontEntry && fontEntry->TestCharacterMap(aCh))
465 return fontEntry;
466 }
467
468 TimeStamp start = TimeStamp::Now();
469
470
471 bool common = true;
472 fontEntry = CommonFontFallback(aCh, aRunScript, aStyle); <==============================
473
474
475 PRUint32 cmapCount = 0;
476 if (!fontEntry) {
477 common = false;
478 fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount);
479 }
480 TimeDuration elapsed = TimeStamp::Now() - start;
481
482 #ifdef PR_LOGGING
483 PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
484
485 if (NS_UNLIKELY(log)) {
486 PRUint32 charRange = gfxFontUtils::CharRangeBit(aCh);
487 PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
488 PRInt32 script = mozilla::unicode::GetScriptCode(aCh);
489 PR_LOG(log, PR_LOG_WARNING,\
490 ("(textrun-systemfallback-%s) char: u+%6.6x "
491 "char-range: %d unicode-range: %d script: %d match: [%s]"
492 " time: %dus cmaps: %d\n",
493 (common ? "common" : "global"), aCh,
494 charRange, unicodeRange, script,
495 (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
496 "<none>"),
497 PRInt32(elapsed.ToMicroseconds()),
498 cmapCount));
499 }
500 #endif
501
502
503 if (!fontEntry) {
504 mCodepointsWithNoFonts.set(aCh);
505 } else if (aCh == 0xFFFD && fontEntry) {
506 mReplacementCharFallbackFamily = fontEntry->FamilyName();
507 }
508
509
510 static bool first = true;
511 PRInt32 intElapsed = PRInt32(first ? elapsed.ToMilliseconds() :
512 elapsed.ToMicroseconds());
513 Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
514 Telemetry::SYSTEM_FONT_FALLBACK),
515 intElapsed);
516 first = false;
517
518
519
520 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
521
522 return fontEntry;
523 }
539 gfxFontEntry*
540 gfxPlatformFontList::CommonFontFallback(const PRUint32 aCh,
541 PRInt32 aRunScript,
542 const gfxFontStyle* aMatchStyle)
543 {
544 nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
545 PRUint32 i, numFallbacks;
546
547 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript, <=============
548 defaultFallbacks);
549 numFallbacks = defaultFallbacks.Length();
550 for (i = 0; i < numFallbacks; i++) {
551 nsAutoString familyName;
552 const char *fallbackFamily = defaultFallbacks[i];
553
554 familyName.AppendASCII(fallbackFamily);
555 gfxFontFamily *fallback =
556 gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
557 if (!fallback)
558 continue;
559
560 gfxFontEntry *fontEntry;
561 bool needsBold;
562
563
564 fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
565 if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
566 return fontEntry;
567 }
568 }
569
570 return nsnull;
571 }
173 void
174 gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh,
175 int32_t aRunScript,
176 nsTArray<const char*>& aFontList)
177 {
178 static const char kDroidSansJapanese[] = "Droid Sans Japanese";
179 static const char kMotoyaLMaru[] = "MotoyaLMaru";
180
181 if (IS_IN_BMP(aCh)) { <=========
182
183
184 uint8_t block = (aCh >> 8) & 0xff;
185 switch (block) {
186 case 0x05:
187 aFontList.AppendElement("Droid Sans Hebrew");
188 aFontList.AppendElement("Droid Sans Armenian");
189 break;
190 case 0x06:
191 aFontList.AppendElement("Droid Sans Arabic");
192 break;
193 case 0x09:
194 aFontList.AppendElement("Droid Sans Devanagari");
195 break;
196 case 0x0b:
197 aFontList.AppendElement("Droid Sans Tamil");
198 break;
199 case 0x0e:
200 aFontList.AppendElement("Droid Sans Thai");
201 break;
202 case 0x10: case 0x2d:
203 aFontList.AppendElement("Droid Sans Georgian");
204 break;
205 case 0x12: case 0x13:
206 aFontList.AppendElement("Droid Sans Ethiopic");
207 break;
208 case 0xf9: case 0xfa:
209 if (IsJapaneseLocale()) {
210 aFontList.AppendElement(kMotoyaLMaru);
211 aFontList.AppendElement(kDroidSansJapanese);
212 }
213 break;
214 default:
215 if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) {
216 aFontList.AppendElement(kMotoyaLMaru);
217 aFontList.AppendElement(kDroidSansJapanese);
218 }
219 break;
220 }
221 }
222
223 aFontList.AppendElement("Droid Sans Fallback");
224 }
81 * Some macros for converting PRUnichar (UTF-16) to and from Unicode scalar
82 * values.
83 *
84 * Note that UTF-16 represents all Unicode scalar values up to U+10FFFF by
85 * using "surrogate pairs". These consist of a high surrogate, i.e. a code
86 * point in the range U+D800 - U+DBFF, and a low surrogate, i.e. a code point
87 * in the range U+DC00 - U+DFFF, like this:
88 *
89 * U+D800 U+DC00 = U+10000
90 * U+D800 U+DC01 = U+10001
91 * ...
92 * U+DBFF U+DFFE = U+10FFFE
93 * U+DBFF U+DFFF = U+10FFFF
94 *
95 * These surrogate code points U+D800 - U+DFFF are not themselves valid Unicode
96 * scalar values and are not well-formed UTF-16 except as high-surrogate /
97 * low-surrogate pairs.
98 */
99
100 #define PLANE1_BASE PRUint32(0x00010000) <=====================
101
102 #define NS_IS_HIGH_SURROGATE(u) ((PRUint32(u) & 0xFFFFFC00) == 0xD800)
103
104 #define NS_IS_LOW_SURROGATE(u) ((PRUint32(u) & 0xFFFFFC00) == 0xDC00)
105
106 #define IS_SURROGATE(u) ((PRUint32(u) & 0xFFFFF800) == 0xD800)
107
108
109
110
111
112
113 #define SURROGATE_TO_UCS4(h, l) (((PRUint32(h) & 0x03FF) << 10) + \
114 (PRUint32(l) & 0x03FF) + PLANE1_BASE)
115
116
117
118
119
120
121 #define H_SURROGATE(c) PRUnichar(PRUnichar(PRUint32(c) >> 10) + \
122 PRUnichar(0xD7C0))
123
124
125
126
127
128
129 #define L_SURROGATE(c) PRUnichar(PRUnichar(PRUint32(c) & PRUint32(0x03FF)) | \
130 PRUnichar(0xDC00))
131
132 #define IS_IN_BMP(ucs) (PRUint32(ucs) < PLANE1_BASE) <========================
133 #define UCS2_REPLACEMENT_CHAR PRUnichar(0xFFFD)
134
135 #define UCS_END PRUint32(0x00110000)
136 #define IS_VALID_CHAR(c) ((PRUint32(c) < UCS_END) && !IS_SURROGATE(c))
137 #define ENSURE_VALID_CHAR(c) (IS_VALID_CHAR(c) ? (c) : UCS2_REPLACEMENT_CHAR)