Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 #if defined(MOZ_WIDGET_GTK)
7 #include "gfxPlatformGtk.h"
8 #define gfxToolkitPlatform gfxPlatformGtk
9 #elif defined(MOZ_WIDGET_QT)
10 #include <qfontinfo.h>
11 #include "gfxQtPlatform.h"
12 #define gfxToolkitPlatform gfxQtPlatform
13 #elif defined(XP_WIN)
14 #include "gfxWindowsPlatform.h"
15 #define gfxToolkitPlatform gfxWindowsPlatform
16 #elif defined(ANDROID)
17 #include "gfxAndroidPlatform.h"
18 #define gfxToolkitPlatform gfxAndroidPlatform
19 #endif
21 #include "gfxTypes.h"
22 #include "gfxFT2Fonts.h"
23 #include "gfxFT2FontBase.h"
24 #include "gfxFT2Utils.h"
25 #include "gfxFT2FontList.h"
26 #include <locale.h>
27 #include "gfxHarfBuzzShaper.h"
28 #include "gfxGraphiteShaper.h"
29 #include "nsGkAtoms.h"
30 #include "nsTArray.h"
31 #include "nsUnicodeRange.h"
32 #include "nsCRT.h"
33 #include "nsXULAppAPI.h"
35 #include "prlog.h"
36 #include "prinit.h"
38 #include "mozilla/MemoryReporting.h"
39 #include "mozilla/Preferences.h"
40 #include "mozilla/gfx/2D.h"
42 // rounding and truncation functions for a Freetype floating point number
43 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
44 // part and low 6 bits for the fractional part.
45 #define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
46 #define MOZ_FT_TRUNC(x) ((x) >> 6)
47 #define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
48 MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
50 #ifndef ANDROID // not needed on Android, we use the generic gfxFontGroup
51 /**
52 * gfxFT2FontGroup
53 */
55 static PRLogModuleInfo *
56 GetFontLog()
57 {
58 static PRLogModuleInfo *sLog;
59 if (!sLog)
60 sLog = PR_NewLogModule("ft2fonts");
61 return sLog;
62 }
64 bool
65 gfxFT2FontGroup::FontCallback(const nsAString& fontName,
66 const nsACString& genericName,
67 bool aUseFontSet,
68 void *closure)
69 {
70 nsTArray<nsString> *sa = static_cast<nsTArray<nsString>*>(closure);
72 if (!fontName.IsEmpty() && !sa->Contains(fontName)) {
73 sa->AppendElement(fontName);
74 #ifdef DEBUG_pavlov
75 printf(" - %s\n", NS_ConvertUTF16toUTF8(fontName).get());
76 #endif
77 }
79 return true;
80 }
82 gfxFT2FontGroup::gfxFT2FontGroup(const nsAString& families,
83 const gfxFontStyle *aStyle,
84 gfxUserFontSet *aUserFontSet)
85 : gfxFontGroup(families, aStyle, aUserFontSet)
86 {
87 #ifdef DEBUG_pavlov
88 printf("Looking for %s\n", NS_ConvertUTF16toUTF8(families).get());
89 #endif
90 nsTArray<nsString> familyArray;
91 ForEachFont(FontCallback, &familyArray);
93 if (familyArray.Length() == 0) {
94 nsAutoString prefFamilies;
95 gfxToolkitPlatform::GetPlatform()->GetPrefFonts(aStyle->language, prefFamilies, nullptr);
96 if (!prefFamilies.IsEmpty()) {
97 ForEachFont(prefFamilies, aStyle->language, FontCallback, &familyArray);
98 }
99 }
100 if (familyArray.Length() == 0) {
101 #if defined(MOZ_WIDGET_QT) /* FIXME DFB */
102 printf("failde to find a font. sadface\n");
103 // We want to get rid of this entirely at some point, but first we need real lists of fonts.
104 QFont defaultFont;
105 QFontInfo fi (defaultFont);
106 familyArray.AppendElement(nsDependentString(static_cast<const char16_t *>(fi.family().utf16())));
107 #elif defined(MOZ_WIDGET_GTK)
108 FcResult result;
109 FcChar8 *family = nullptr;
110 FcPattern* pat = FcPatternCreate();
111 FcPattern *match = FcFontMatch(nullptr, pat, &result);
112 if (match)
113 FcPatternGetString(match, FC_FAMILY, 0, &family);
114 if (family)
115 familyArray.AppendElement(NS_ConvertUTF8toUTF16((char*)family));
116 #elif defined(XP_WIN)
117 HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT);
118 LOGFONTW logFont;
119 if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont))
120 familyArray.AppendElement(nsDependentString(logFont.lfFaceName));
121 #elif defined(ANDROID)
122 familyArray.AppendElement(NS_LITERAL_STRING("Droid Sans"));
123 familyArray.AppendElement(NS_LITERAL_STRING("Roboto"));
124 #else
125 #error "Platform not supported"
126 #endif
127 }
129 for (uint32_t i = 0; i < familyArray.Length(); i++) {
130 nsRefPtr<gfxFT2Font> font = gfxFT2Font::GetOrMakeFont(familyArray[i], &mStyle);
131 if (font) {
132 mFonts.AppendElement(font);
133 }
134 }
135 NS_ASSERTION(mFonts.Length() > 0, "We need at least one font in a fontgroup");
136 }
138 gfxFT2FontGroup::~gfxFT2FontGroup()
139 {
140 }
142 gfxFontGroup *
143 gfxFT2FontGroup::Copy(const gfxFontStyle *aStyle)
144 {
145 return new gfxFT2FontGroup(mFamilies, aStyle, nullptr);
146 }
148 // Helper function to return the leading UTF-8 character in a char pointer
149 // as 32bit number. Also sets the length of the current character (i.e. the
150 // offset to the next one) in the second argument
151 uint32_t getUTF8CharAndNext(const uint8_t *aString, uint8_t *aLength)
152 {
153 *aLength = 1;
154 if (aString[0] < 0x80) { // normal 7bit ASCII char
155 return aString[0];
156 }
157 if ((aString[0] >> 5) == 6) { // two leading ones -> two bytes
158 *aLength = 2;
159 return ((aString[0] & 0x1F) << 6) + (aString[1] & 0x3F);
160 }
161 if ((aString[0] >> 4) == 14) { // three leading ones -> three bytes
162 *aLength = 3;
163 return ((aString[0] & 0x0F) << 12) + ((aString[1] & 0x3F) << 6) +
164 (aString[2] & 0x3F);
165 }
166 if ((aString[0] >> 4) == 15) { // four leading ones -> four bytes
167 *aLength = 4;
168 return ((aString[0] & 0x07) << 18) + ((aString[1] & 0x3F) << 12) +
169 ((aString[2] & 0x3F) << 6) + (aString[3] & 0x3F);
170 }
171 return aString[0];
172 }
175 static bool
176 AddFontNameToArray(const nsAString& aName,
177 const nsACString& aGenericName,
178 bool aUseFontSet,
179 void *aClosure)
180 {
181 if (!aName.IsEmpty()) {
182 nsTArray<nsString> *list = static_cast<nsTArray<nsString> *>(aClosure);
184 if (list->IndexOf(aName) == list->NoIndex)
185 list->AppendElement(aName);
186 }
188 return true;
189 }
191 void
192 gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies,
193 nsIAtom *aLangGroup,
194 nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList)
195 {
196 nsAutoTArray<nsString, 15> fonts;
197 ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
199 uint32_t len = fonts.Length();
200 for (uint32_t i = 0; i < len; ++i) {
201 const nsString& str = fonts[i];
202 nsRefPtr<gfxFontEntry> fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle));
203 aFontEntryList->AppendElement(fe);
204 }
205 }
207 void gfxFT2FontGroup::GetPrefFonts(nsIAtom *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList)
208 {
209 NS_ASSERTION(aLangGroup, "aLangGroup is null");
210 gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
211 nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
212 nsAutoCString key;
213 aLangGroup->ToUTF8String(key);
214 key.Append("-");
215 key.AppendInt(GetStyle()->style);
216 key.Append("-");
217 key.AppendInt(GetStyle()->weight);
218 if (!platform->GetPrefFontEntries(key, &fonts)) {
219 nsString fontString;
220 platform->GetPrefFonts(aLangGroup, fontString);
221 if (fontString.IsEmpty())
222 return;
224 FamilyListToArrayList(fontString, aLangGroup, &fonts);
226 platform->SetPrefFontEntries(key, fonts);
227 }
228 aFontEntryList.AppendElements(fonts);
229 }
231 static int32_t GetCJKLangGroupIndex(const char *aLangGroup) {
232 int32_t i;
233 for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) {
234 if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i]))
235 return i;
236 }
237 return -1;
238 }
240 // this function assigns to the array passed in.
241 void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) {
242 gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
244 nsAutoCString key("x-internal-cjk-");
245 key.AppendInt(mStyle.style);
246 key.Append("-");
247 key.AppendInt(mStyle.weight);
249 if (!platform->GetPrefFontEntries(key, &aFontEntryList)) {
250 NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
251 // Add the CJK pref fonts from accept languages, the order should be same order
252 nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
253 if (!list.IsEmpty()) {
254 const char kComma = ',';
255 const char *p, *p_end;
256 list.BeginReading(p);
257 list.EndReading(p_end);
258 while (p < p_end) {
259 while (nsCRT::IsAsciiSpace(*p)) {
260 if (++p == p_end)
261 break;
262 }
263 if (p == p_end)
264 break;
265 const char *start = p;
266 while (++p != p_end && *p != kComma)
267 /* nothing */ ;
268 nsAutoCString lang(Substring(start, p));
269 lang.CompressWhitespace(false, true);
270 int32_t index = GetCJKLangGroupIndex(lang.get());
271 if (index >= 0) {
272 nsCOMPtr<nsIAtom> atom = do_GetAtom(sCJKLangGroup[index]);
273 GetPrefFonts(atom, aFontEntryList);
274 }
275 p++;
276 }
277 }
279 // Add the system locale
280 #ifdef XP_WIN
281 switch (::GetACP()) {
282 case 932: GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); break;
283 case 936: GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); break;
284 case 949: GetPrefFonts(nsGkAtoms::ko, aFontEntryList); break;
285 // XXX Don't we need to append nsGkAtoms::zh_hk if the codepage is 950?
286 case 950: GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); break;
287 }
288 #else
289 const char *ctype = setlocale(LC_CTYPE, nullptr);
290 if (ctype) {
291 if (!PL_strncasecmp(ctype, "ja", 2)) {
292 GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList);
293 } else if (!PL_strncasecmp(ctype, "zh_cn", 5)) {
294 GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList);
295 } else if (!PL_strncasecmp(ctype, "zh_hk", 5)) {
296 GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList);
297 } else if (!PL_strncasecmp(ctype, "zh_tw", 5)) {
298 GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList);
299 } else if (!PL_strncasecmp(ctype, "ko", 2)) {
300 GetPrefFonts(nsGkAtoms::ko, aFontEntryList);
301 }
302 }
303 #endif
305 // last resort...
306 GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList);
307 GetPrefFonts(nsGkAtoms::ko, aFontEntryList);
308 GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList);
309 GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList);
310 GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList);
312 platform->SetPrefFontEntries(key, aFontEntryList);
313 }
314 }
316 already_AddRefed<gfxFT2Font>
317 gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList, uint32_t aCh)
318 {
319 for (uint32_t i = 0; i < aFontEntryList.Length(); i++) {
320 gfxFontEntry *fe = aFontEntryList[i].get();
321 if (fe->HasCharacter(aCh)) {
322 nsRefPtr<gfxFT2Font> font =
323 gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(fe), &mStyle);
324 return font.forget();
325 }
326 }
327 return nullptr;
328 }
330 already_AddRefed<gfxFont>
331 gfxFT2FontGroup::WhichPrefFontSupportsChar(uint32_t aCh)
332 {
333 if (aCh > 0xFFFF)
334 return nullptr;
336 nsRefPtr<gfxFT2Font> selectedFont;
338 // check out the style's language
339 nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
340 GetPrefFonts(mStyle.language, fonts);
341 selectedFont = WhichFontSupportsChar(fonts, aCh);
343 // otherwise search prefs
344 if (!selectedFont) {
345 uint32_t unicodeRange = FindCharUnicodeRange(aCh);
347 /* special case CJK */
348 if (unicodeRange == kRangeSetCJK) {
349 if (PR_LOG_TEST(GetFontLog(), PR_LOG_DEBUG)) {
350 PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
351 }
353 nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts;
354 GetCJKPrefFonts(fonts);
355 selectedFont = WhichFontSupportsChar(fonts, aCh);
356 } else {
357 nsIAtom *langGroup = LangGroupFromUnicodeRange(unicodeRange);
358 if (langGroup) {
359 PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: %s", nsAtomCString(langGroup).get()));
361 nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
362 GetPrefFonts(langGroup, fonts);
363 selectedFont = WhichFontSupportsChar(fonts, aCh);
364 }
365 }
366 }
368 if (selectedFont) {
369 nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get());
370 return f.forget();
371 }
373 return nullptr;
374 }
376 already_AddRefed<gfxFont>
377 gfxFT2FontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript)
378 {
379 #if defined(XP_WIN) || defined(ANDROID)
380 FontEntry *fe = static_cast<FontEntry*>
381 (gfxPlatformFontList::PlatformFontList()->
382 SystemFindFontForChar(aCh, aRunScript, &mStyle));
383 if (fe) {
384 nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
385 nsRefPtr<gfxFont> font = f.get();
386 return font.forget();
387 }
388 #else
389 nsRefPtr<gfxFont> selectedFont;
390 nsRefPtr<gfxFont> refFont = GetFontAt(0);
391 gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
392 selectedFont = platform->FindFontForChar(aCh, refFont);
393 if (selectedFont)
394 return selectedFont.forget();
395 #endif
396 return nullptr;
397 }
399 #endif // !ANDROID
401 /**
402 * gfxFT2Font
403 */
405 bool
406 gfxFT2Font::ShapeText(gfxContext *aContext,
407 const char16_t *aText,
408 uint32_t aOffset,
409 uint32_t aLength,
410 int32_t aScript,
411 gfxShapedText *aShapedText,
412 bool aPreferPlatformShaping)
413 {
414 bool ok = false;
416 if (FontCanSupportGraphite()) {
417 if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
418 if (!mGraphiteShaper) {
419 mGraphiteShaper = new gfxGraphiteShaper(this);
420 }
421 ok = mGraphiteShaper->ShapeText(aContext, aText,
422 aOffset, aLength,
423 aScript, aShapedText);
424 }
425 }
427 if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
428 if (!mHarfBuzzShaper) {
429 mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
430 }
431 ok = mHarfBuzzShaper->ShapeText(aContext, aText,
432 aOffset, aLength,
433 aScript, aShapedText);
434 }
436 if (!ok) {
437 AddRange(aText, aOffset, aLength, aShapedText);
438 }
440 PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
442 return true;
443 }
445 void
446 gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
447 uint32_t aLength, gfxShapedText *aShapedText)
448 {
449 const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
450 // we'll pass this in/figure it out dynamically, but at this point there can be only one face.
451 gfxFT2LockedFace faceLock(this);
452 FT_Face face = faceLock.get();
454 gfxShapedText::CompressedGlyph *charGlyphs =
455 aShapedText->GetCharacterGlyphs();
457 const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
459 FT_UInt spaceGlyph = GetSpaceGlyph();
461 for (uint32_t i = 0; i < aLength; i++, aOffset++) {
462 char16_t ch = aText[i];
464 if (ch == 0) {
465 // treat this null byte as a missing glyph, don't create a glyph for it
466 aShapedText->SetMissingGlyph(aOffset, 0, this);
467 continue;
468 }
470 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected");
472 if (cgdNext) {
473 cgd = cgdNext;
474 cgdNext = nullptr;
475 } else {
476 cgd = GetGlyphDataForChar(ch);
477 }
479 FT_UInt gid = cgd->glyphIndex;
480 int32_t advance = 0;
482 if (gid == 0) {
483 advance = -1; // trigger the missing glyphs case below
484 } else {
485 // find next character and its glyph -- in case they exist
486 // and exist in the current font face -- to compute kerning
487 char16_t chNext = 0;
488 FT_UInt gidNext = 0;
489 FT_Pos lsbDeltaNext = 0;
491 if (FT_HAS_KERNING(face) && i + 1 < aLength) {
492 chNext = aText[i + 1];
493 if (chNext != 0) {
494 cgdNext = GetGlyphDataForChar(chNext);
495 gidNext = cgdNext->glyphIndex;
496 if (gidNext && gidNext != spaceGlyph)
497 lsbDeltaNext = cgdNext->lsbDelta;
498 }
499 }
501 advance = cgd->xAdvance;
503 // now add kerning to the current glyph's advance
504 if (chNext && gidNext) {
505 FT_Vector kerning; kerning.x = 0;
506 FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning);
507 advance += kerning.x;
508 if (cgd->rsbDelta - lsbDeltaNext >= 32) {
509 advance -= 64;
510 } else if (cgd->rsbDelta - lsbDeltaNext < -32) {
511 advance += 64;
512 }
513 }
515 // convert 26.6 fixed point to app units
516 // round rather than truncate to nearest pixel
517 // because these advances are often scaled
518 advance = ((advance * appUnitsPerDevUnit + 32) >> 6);
519 }
521 if (advance >= 0 &&
522 gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
523 gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) {
524 charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
525 } else if (gid == 0) {
526 // gid = 0 only happens when the glyph is missing from the font
527 aShapedText->SetMissingGlyph(aOffset, ch, this);
528 } else {
529 gfxTextRun::DetailedGlyph details;
530 details.mGlyphID = gid;
531 NS_ASSERTION(details.mGlyphID == gid,
532 "Seriously weird glyph ID detected!");
533 details.mAdvance = advance;
534 details.mXOffset = 0;
535 details.mYOffset = 0;
536 gfxShapedText::CompressedGlyph g;
537 g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1);
538 aShapedText->SetGlyphs(aOffset, g, &details);
539 }
540 }
541 }
543 gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont,
544 FT2FontEntry *aFontEntry,
545 const gfxFontStyle *aFontStyle,
546 bool aNeedsBold)
547 : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle)
548 , mCharGlyphCache(64)
549 {
550 NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
551 mApplySyntheticBold = aNeedsBold;
552 }
554 gfxFT2Font::~gfxFT2Font()
555 {
556 }
558 /**
559 * Look up the font in the gfxFont cache. If we don't find it, create one.
560 * In either case, add a ref, append it to the aFonts array, and return it ---
561 * except for OOM in which case we do nothing and return null.
562 */
563 already_AddRefed<gfxFT2Font>
564 gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle,
565 bool aNeedsBold)
566 {
567 #ifdef ANDROID
568 FT2FontEntry *fe = static_cast<FT2FontEntry*>
569 (gfxPlatformFontList::PlatformFontList()->
570 FindFontForFamily(aName, aStyle, aNeedsBold));
571 #else
572 FT2FontEntry *fe = static_cast<FT2FontEntry*>
573 (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle));
574 #endif
575 if (!fe) {
576 NS_WARNING("Failed to find font entry for font!");
577 return nullptr;
578 }
580 nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle, aNeedsBold);
581 return font.forget();
582 }
584 already_AddRefed<gfxFT2Font>
585 gfxFT2Font::GetOrMakeFont(FT2FontEntry *aFontEntry, const gfxFontStyle *aStyle,
586 bool aNeedsBold)
587 {
588 nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry, aStyle);
589 if (!font) {
590 cairo_scaled_font_t *scaledFont = aFontEntry->CreateScaledFont(aStyle);
591 if (!scaledFont) {
592 return nullptr;
593 }
594 font = new gfxFT2Font(scaledFont, aFontEntry, aStyle, aNeedsBold);
595 cairo_scaled_font_destroy(scaledFont);
596 if (!font) {
597 return nullptr;
598 }
599 gfxFontCache::GetCache()->AddNew(font);
600 }
601 return font.forget().downcast<gfxFT2Font>();
602 }
604 void
605 gfxFT2Font::FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd)
606 {
607 gfxFT2LockedFace faceLock(this);
608 FT_Face face = faceLock.get();
610 if (!face->charmap || face->charmap->encoding != FT_ENCODING_UNICODE) {
611 FT_Select_Charmap(face, FT_ENCODING_UNICODE);
612 }
613 FT_UInt gid = FT_Get_Char_Index(face, ch);
615 if (gid == 0) {
616 // this font doesn't support this char!
617 NS_ASSERTION(gid != 0, "We don't have a glyph, but font indicated that it supported this char in tables?");
618 gd->glyphIndex = 0;
619 return;
620 }
622 FT_Int32 flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
623 FT_LOAD_DEFAULT :
624 (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
625 FT_Error err = FT_Load_Glyph(face, gid, flags);
627 if (err) {
628 // hmm, this is weird, we failed to load a glyph that we had?
629 NS_WARNING("Failed to load glyph that we got from Get_Char_index");
631 gd->glyphIndex = 0;
632 return;
633 }
635 gd->glyphIndex = gid;
636 gd->lsbDelta = face->glyph->lsb_delta;
637 gd->rsbDelta = face->glyph->rsb_delta;
638 gd->xAdvance = face->glyph->advance.x;
639 }
641 void
642 gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
643 FontCacheSizes* aSizes) const
644 {
645 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
646 aSizes->mFontInstances +=
647 mCharGlyphCache.SizeOfExcludingThis(nullptr, aMallocSizeOf);
648 }
650 void
651 gfxFT2Font::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
652 FontCacheSizes* aSizes) const
653 {
654 aSizes->mFontInstances += aMallocSizeOf(this);
655 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
656 }
658 #ifdef USE_SKIA
659 mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
660 gfxFT2Font::GetGlyphRenderingOptions()
661 {
662 mozilla::gfx::FontHinting hinting;
664 if (gfxPlatform::GetPlatform()->FontHintingEnabled()) {
665 hinting = mozilla::gfx::FontHinting::NORMAL;
666 } else {
667 hinting = mozilla::gfx::FontHinting::NONE;
668 }
670 // We don't want to force the use of the autohinter over the font's built in hints
671 return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false);
672 }
673 #endif