1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxFT2Fonts.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,674 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#if defined(MOZ_WIDGET_GTK) 1.10 +#include "gfxPlatformGtk.h" 1.11 +#define gfxToolkitPlatform gfxPlatformGtk 1.12 +#elif defined(MOZ_WIDGET_QT) 1.13 +#include <qfontinfo.h> 1.14 +#include "gfxQtPlatform.h" 1.15 +#define gfxToolkitPlatform gfxQtPlatform 1.16 +#elif defined(XP_WIN) 1.17 +#include "gfxWindowsPlatform.h" 1.18 +#define gfxToolkitPlatform gfxWindowsPlatform 1.19 +#elif defined(ANDROID) 1.20 +#include "gfxAndroidPlatform.h" 1.21 +#define gfxToolkitPlatform gfxAndroidPlatform 1.22 +#endif 1.23 + 1.24 +#include "gfxTypes.h" 1.25 +#include "gfxFT2Fonts.h" 1.26 +#include "gfxFT2FontBase.h" 1.27 +#include "gfxFT2Utils.h" 1.28 +#include "gfxFT2FontList.h" 1.29 +#include <locale.h> 1.30 +#include "gfxHarfBuzzShaper.h" 1.31 +#include "gfxGraphiteShaper.h" 1.32 +#include "nsGkAtoms.h" 1.33 +#include "nsTArray.h" 1.34 +#include "nsUnicodeRange.h" 1.35 +#include "nsCRT.h" 1.36 +#include "nsXULAppAPI.h" 1.37 + 1.38 +#include "prlog.h" 1.39 +#include "prinit.h" 1.40 + 1.41 +#include "mozilla/MemoryReporting.h" 1.42 +#include "mozilla/Preferences.h" 1.43 +#include "mozilla/gfx/2D.h" 1.44 + 1.45 +// rounding and truncation functions for a Freetype floating point number 1.46 +// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer 1.47 +// part and low 6 bits for the fractional part. 1.48 +#define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1 1.49 +#define MOZ_FT_TRUNC(x) ((x) >> 6) 1.50 +#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \ 1.51 + MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s)))) 1.52 + 1.53 +#ifndef ANDROID // not needed on Android, we use the generic gfxFontGroup 1.54 +/** 1.55 + * gfxFT2FontGroup 1.56 + */ 1.57 + 1.58 +static PRLogModuleInfo * 1.59 +GetFontLog() 1.60 +{ 1.61 + static PRLogModuleInfo *sLog; 1.62 + if (!sLog) 1.63 + sLog = PR_NewLogModule("ft2fonts"); 1.64 + return sLog; 1.65 +} 1.66 + 1.67 +bool 1.68 +gfxFT2FontGroup::FontCallback(const nsAString& fontName, 1.69 + const nsACString& genericName, 1.70 + bool aUseFontSet, 1.71 + void *closure) 1.72 +{ 1.73 + nsTArray<nsString> *sa = static_cast<nsTArray<nsString>*>(closure); 1.74 + 1.75 + if (!fontName.IsEmpty() && !sa->Contains(fontName)) { 1.76 + sa->AppendElement(fontName); 1.77 +#ifdef DEBUG_pavlov 1.78 + printf(" - %s\n", NS_ConvertUTF16toUTF8(fontName).get()); 1.79 +#endif 1.80 + } 1.81 + 1.82 + return true; 1.83 +} 1.84 + 1.85 +gfxFT2FontGroup::gfxFT2FontGroup(const nsAString& families, 1.86 + const gfxFontStyle *aStyle, 1.87 + gfxUserFontSet *aUserFontSet) 1.88 + : gfxFontGroup(families, aStyle, aUserFontSet) 1.89 +{ 1.90 +#ifdef DEBUG_pavlov 1.91 + printf("Looking for %s\n", NS_ConvertUTF16toUTF8(families).get()); 1.92 +#endif 1.93 + nsTArray<nsString> familyArray; 1.94 + ForEachFont(FontCallback, &familyArray); 1.95 + 1.96 + if (familyArray.Length() == 0) { 1.97 + nsAutoString prefFamilies; 1.98 + gfxToolkitPlatform::GetPlatform()->GetPrefFonts(aStyle->language, prefFamilies, nullptr); 1.99 + if (!prefFamilies.IsEmpty()) { 1.100 + ForEachFont(prefFamilies, aStyle->language, FontCallback, &familyArray); 1.101 + } 1.102 + } 1.103 + if (familyArray.Length() == 0) { 1.104 +#if defined(MOZ_WIDGET_QT) /* FIXME DFB */ 1.105 + printf("failde to find a font. sadface\n"); 1.106 + // We want to get rid of this entirely at some point, but first we need real lists of fonts. 1.107 + QFont defaultFont; 1.108 + QFontInfo fi (defaultFont); 1.109 + familyArray.AppendElement(nsDependentString(static_cast<const char16_t *>(fi.family().utf16()))); 1.110 +#elif defined(MOZ_WIDGET_GTK) 1.111 + FcResult result; 1.112 + FcChar8 *family = nullptr; 1.113 + FcPattern* pat = FcPatternCreate(); 1.114 + FcPattern *match = FcFontMatch(nullptr, pat, &result); 1.115 + if (match) 1.116 + FcPatternGetString(match, FC_FAMILY, 0, &family); 1.117 + if (family) 1.118 + familyArray.AppendElement(NS_ConvertUTF8toUTF16((char*)family)); 1.119 +#elif defined(XP_WIN) 1.120 + HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT); 1.121 + LOGFONTW logFont; 1.122 + if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) 1.123 + familyArray.AppendElement(nsDependentString(logFont.lfFaceName)); 1.124 +#elif defined(ANDROID) 1.125 + familyArray.AppendElement(NS_LITERAL_STRING("Droid Sans")); 1.126 + familyArray.AppendElement(NS_LITERAL_STRING("Roboto")); 1.127 +#else 1.128 +#error "Platform not supported" 1.129 +#endif 1.130 + } 1.131 + 1.132 + for (uint32_t i = 0; i < familyArray.Length(); i++) { 1.133 + nsRefPtr<gfxFT2Font> font = gfxFT2Font::GetOrMakeFont(familyArray[i], &mStyle); 1.134 + if (font) { 1.135 + mFonts.AppendElement(font); 1.136 + } 1.137 + } 1.138 + NS_ASSERTION(mFonts.Length() > 0, "We need at least one font in a fontgroup"); 1.139 +} 1.140 + 1.141 +gfxFT2FontGroup::~gfxFT2FontGroup() 1.142 +{ 1.143 +} 1.144 + 1.145 +gfxFontGroup * 1.146 +gfxFT2FontGroup::Copy(const gfxFontStyle *aStyle) 1.147 +{ 1.148 + return new gfxFT2FontGroup(mFamilies, aStyle, nullptr); 1.149 +} 1.150 + 1.151 +// Helper function to return the leading UTF-8 character in a char pointer 1.152 +// as 32bit number. Also sets the length of the current character (i.e. the 1.153 +// offset to the next one) in the second argument 1.154 +uint32_t getUTF8CharAndNext(const uint8_t *aString, uint8_t *aLength) 1.155 +{ 1.156 + *aLength = 1; 1.157 + if (aString[0] < 0x80) { // normal 7bit ASCII char 1.158 + return aString[0]; 1.159 + } 1.160 + if ((aString[0] >> 5) == 6) { // two leading ones -> two bytes 1.161 + *aLength = 2; 1.162 + return ((aString[0] & 0x1F) << 6) + (aString[1] & 0x3F); 1.163 + } 1.164 + if ((aString[0] >> 4) == 14) { // three leading ones -> three bytes 1.165 + *aLength = 3; 1.166 + return ((aString[0] & 0x0F) << 12) + ((aString[1] & 0x3F) << 6) + 1.167 + (aString[2] & 0x3F); 1.168 + } 1.169 + if ((aString[0] >> 4) == 15) { // four leading ones -> four bytes 1.170 + *aLength = 4; 1.171 + return ((aString[0] & 0x07) << 18) + ((aString[1] & 0x3F) << 12) + 1.172 + ((aString[2] & 0x3F) << 6) + (aString[3] & 0x3F); 1.173 + } 1.174 + return aString[0]; 1.175 +} 1.176 + 1.177 + 1.178 +static bool 1.179 +AddFontNameToArray(const nsAString& aName, 1.180 + const nsACString& aGenericName, 1.181 + bool aUseFontSet, 1.182 + void *aClosure) 1.183 +{ 1.184 + if (!aName.IsEmpty()) { 1.185 + nsTArray<nsString> *list = static_cast<nsTArray<nsString> *>(aClosure); 1.186 + 1.187 + if (list->IndexOf(aName) == list->NoIndex) 1.188 + list->AppendElement(aName); 1.189 + } 1.190 + 1.191 + return true; 1.192 +} 1.193 + 1.194 +void 1.195 +gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies, 1.196 + nsIAtom *aLangGroup, 1.197 + nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList) 1.198 +{ 1.199 + nsAutoTArray<nsString, 15> fonts; 1.200 + ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts); 1.201 + 1.202 + uint32_t len = fonts.Length(); 1.203 + for (uint32_t i = 0; i < len; ++i) { 1.204 + const nsString& str = fonts[i]; 1.205 + nsRefPtr<gfxFontEntry> fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle)); 1.206 + aFontEntryList->AppendElement(fe); 1.207 + } 1.208 +} 1.209 + 1.210 +void gfxFT2FontGroup::GetPrefFonts(nsIAtom *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) 1.211 +{ 1.212 + NS_ASSERTION(aLangGroup, "aLangGroup is null"); 1.213 + gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); 1.214 + nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts; 1.215 + nsAutoCString key; 1.216 + aLangGroup->ToUTF8String(key); 1.217 + key.Append("-"); 1.218 + key.AppendInt(GetStyle()->style); 1.219 + key.Append("-"); 1.220 + key.AppendInt(GetStyle()->weight); 1.221 + if (!platform->GetPrefFontEntries(key, &fonts)) { 1.222 + nsString fontString; 1.223 + platform->GetPrefFonts(aLangGroup, fontString); 1.224 + if (fontString.IsEmpty()) 1.225 + return; 1.226 + 1.227 + FamilyListToArrayList(fontString, aLangGroup, &fonts); 1.228 + 1.229 + platform->SetPrefFontEntries(key, fonts); 1.230 + } 1.231 + aFontEntryList.AppendElements(fonts); 1.232 +} 1.233 + 1.234 +static int32_t GetCJKLangGroupIndex(const char *aLangGroup) { 1.235 + int32_t i; 1.236 + for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) { 1.237 + if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i])) 1.238 + return i; 1.239 + } 1.240 + return -1; 1.241 +} 1.242 + 1.243 +// this function assigns to the array passed in. 1.244 +void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) { 1.245 + gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); 1.246 + 1.247 + nsAutoCString key("x-internal-cjk-"); 1.248 + key.AppendInt(mStyle.style); 1.249 + key.Append("-"); 1.250 + key.AppendInt(mStyle.weight); 1.251 + 1.252 + if (!platform->GetPrefFontEntries(key, &aFontEntryList)) { 1.253 + NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch()); 1.254 + // Add the CJK pref fonts from accept languages, the order should be same order 1.255 + nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages"); 1.256 + if (!list.IsEmpty()) { 1.257 + const char kComma = ','; 1.258 + const char *p, *p_end; 1.259 + list.BeginReading(p); 1.260 + list.EndReading(p_end); 1.261 + while (p < p_end) { 1.262 + while (nsCRT::IsAsciiSpace(*p)) { 1.263 + if (++p == p_end) 1.264 + break; 1.265 + } 1.266 + if (p == p_end) 1.267 + break; 1.268 + const char *start = p; 1.269 + while (++p != p_end && *p != kComma) 1.270 + /* nothing */ ; 1.271 + nsAutoCString lang(Substring(start, p)); 1.272 + lang.CompressWhitespace(false, true); 1.273 + int32_t index = GetCJKLangGroupIndex(lang.get()); 1.274 + if (index >= 0) { 1.275 + nsCOMPtr<nsIAtom> atom = do_GetAtom(sCJKLangGroup[index]); 1.276 + GetPrefFonts(atom, aFontEntryList); 1.277 + } 1.278 + p++; 1.279 + } 1.280 + } 1.281 + 1.282 + // Add the system locale 1.283 +#ifdef XP_WIN 1.284 + switch (::GetACP()) { 1.285 + case 932: GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); break; 1.286 + case 936: GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); break; 1.287 + case 949: GetPrefFonts(nsGkAtoms::ko, aFontEntryList); break; 1.288 + // XXX Don't we need to append nsGkAtoms::zh_hk if the codepage is 950? 1.289 + case 950: GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); break; 1.290 + } 1.291 +#else 1.292 + const char *ctype = setlocale(LC_CTYPE, nullptr); 1.293 + if (ctype) { 1.294 + if (!PL_strncasecmp(ctype, "ja", 2)) { 1.295 + GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); 1.296 + } else if (!PL_strncasecmp(ctype, "zh_cn", 5)) { 1.297 + GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); 1.298 + } else if (!PL_strncasecmp(ctype, "zh_hk", 5)) { 1.299 + GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList); 1.300 + } else if (!PL_strncasecmp(ctype, "zh_tw", 5)) { 1.301 + GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); 1.302 + } else if (!PL_strncasecmp(ctype, "ko", 2)) { 1.303 + GetPrefFonts(nsGkAtoms::ko, aFontEntryList); 1.304 + } 1.305 + } 1.306 +#endif 1.307 + 1.308 + // last resort... 1.309 + GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); 1.310 + GetPrefFonts(nsGkAtoms::ko, aFontEntryList); 1.311 + GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); 1.312 + GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList); 1.313 + GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); 1.314 + 1.315 + platform->SetPrefFontEntries(key, aFontEntryList); 1.316 + } 1.317 +} 1.318 + 1.319 +already_AddRefed<gfxFT2Font> 1.320 +gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList, uint32_t aCh) 1.321 +{ 1.322 + for (uint32_t i = 0; i < aFontEntryList.Length(); i++) { 1.323 + gfxFontEntry *fe = aFontEntryList[i].get(); 1.324 + if (fe->HasCharacter(aCh)) { 1.325 + nsRefPtr<gfxFT2Font> font = 1.326 + gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(fe), &mStyle); 1.327 + return font.forget(); 1.328 + } 1.329 + } 1.330 + return nullptr; 1.331 +} 1.332 + 1.333 +already_AddRefed<gfxFont> 1.334 +gfxFT2FontGroup::WhichPrefFontSupportsChar(uint32_t aCh) 1.335 +{ 1.336 + if (aCh > 0xFFFF) 1.337 + return nullptr; 1.338 + 1.339 + nsRefPtr<gfxFT2Font> selectedFont; 1.340 + 1.341 + // check out the style's language 1.342 + nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts; 1.343 + GetPrefFonts(mStyle.language, fonts); 1.344 + selectedFont = WhichFontSupportsChar(fonts, aCh); 1.345 + 1.346 + // otherwise search prefs 1.347 + if (!selectedFont) { 1.348 + uint32_t unicodeRange = FindCharUnicodeRange(aCh); 1.349 + 1.350 + /* special case CJK */ 1.351 + if (unicodeRange == kRangeSetCJK) { 1.352 + if (PR_LOG_TEST(GetFontLog(), PR_LOG_DEBUG)) { 1.353 + PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: CJK")); 1.354 + } 1.355 + 1.356 + nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts; 1.357 + GetCJKPrefFonts(fonts); 1.358 + selectedFont = WhichFontSupportsChar(fonts, aCh); 1.359 + } else { 1.360 + nsIAtom *langGroup = LangGroupFromUnicodeRange(unicodeRange); 1.361 + if (langGroup) { 1.362 + PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: %s", nsAtomCString(langGroup).get())); 1.363 + 1.364 + nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts; 1.365 + GetPrefFonts(langGroup, fonts); 1.366 + selectedFont = WhichFontSupportsChar(fonts, aCh); 1.367 + } 1.368 + } 1.369 + } 1.370 + 1.371 + if (selectedFont) { 1.372 + nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get()); 1.373 + return f.forget(); 1.374 + } 1.375 + 1.376 + return nullptr; 1.377 +} 1.378 + 1.379 +already_AddRefed<gfxFont> 1.380 +gfxFT2FontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript) 1.381 +{ 1.382 +#if defined(XP_WIN) || defined(ANDROID) 1.383 + FontEntry *fe = static_cast<FontEntry*> 1.384 + (gfxPlatformFontList::PlatformFontList()-> 1.385 + SystemFindFontForChar(aCh, aRunScript, &mStyle)); 1.386 + if (fe) { 1.387 + nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle); 1.388 + nsRefPtr<gfxFont> font = f.get(); 1.389 + return font.forget(); 1.390 + } 1.391 +#else 1.392 + nsRefPtr<gfxFont> selectedFont; 1.393 + nsRefPtr<gfxFont> refFont = GetFontAt(0); 1.394 + gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); 1.395 + selectedFont = platform->FindFontForChar(aCh, refFont); 1.396 + if (selectedFont) 1.397 + return selectedFont.forget(); 1.398 +#endif 1.399 + return nullptr; 1.400 +} 1.401 + 1.402 +#endif // !ANDROID 1.403 + 1.404 +/** 1.405 + * gfxFT2Font 1.406 + */ 1.407 + 1.408 +bool 1.409 +gfxFT2Font::ShapeText(gfxContext *aContext, 1.410 + const char16_t *aText, 1.411 + uint32_t aOffset, 1.412 + uint32_t aLength, 1.413 + int32_t aScript, 1.414 + gfxShapedText *aShapedText, 1.415 + bool aPreferPlatformShaping) 1.416 +{ 1.417 + bool ok = false; 1.418 + 1.419 + if (FontCanSupportGraphite()) { 1.420 + if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) { 1.421 + if (!mGraphiteShaper) { 1.422 + mGraphiteShaper = new gfxGraphiteShaper(this); 1.423 + } 1.424 + ok = mGraphiteShaper->ShapeText(aContext, aText, 1.425 + aOffset, aLength, 1.426 + aScript, aShapedText); 1.427 + } 1.428 + } 1.429 + 1.430 + if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) { 1.431 + if (!mHarfBuzzShaper) { 1.432 + mHarfBuzzShaper = new gfxHarfBuzzShaper(this); 1.433 + } 1.434 + ok = mHarfBuzzShaper->ShapeText(aContext, aText, 1.435 + aOffset, aLength, 1.436 + aScript, aShapedText); 1.437 + } 1.438 + 1.439 + if (!ok) { 1.440 + AddRange(aText, aOffset, aLength, aShapedText); 1.441 + } 1.442 + 1.443 + PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); 1.444 + 1.445 + return true; 1.446 +} 1.447 + 1.448 +void 1.449 +gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset, 1.450 + uint32_t aLength, gfxShapedText *aShapedText) 1.451 +{ 1.452 + const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit(); 1.453 + // we'll pass this in/figure it out dynamically, but at this point there can be only one face. 1.454 + gfxFT2LockedFace faceLock(this); 1.455 + FT_Face face = faceLock.get(); 1.456 + 1.457 + gfxShapedText::CompressedGlyph *charGlyphs = 1.458 + aShapedText->GetCharacterGlyphs(); 1.459 + 1.460 + const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr; 1.461 + 1.462 + FT_UInt spaceGlyph = GetSpaceGlyph(); 1.463 + 1.464 + for (uint32_t i = 0; i < aLength; i++, aOffset++) { 1.465 + char16_t ch = aText[i]; 1.466 + 1.467 + if (ch == 0) { 1.468 + // treat this null byte as a missing glyph, don't create a glyph for it 1.469 + aShapedText->SetMissingGlyph(aOffset, 0, this); 1.470 + continue; 1.471 + } 1.472 + 1.473 + NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected"); 1.474 + 1.475 + if (cgdNext) { 1.476 + cgd = cgdNext; 1.477 + cgdNext = nullptr; 1.478 + } else { 1.479 + cgd = GetGlyphDataForChar(ch); 1.480 + } 1.481 + 1.482 + FT_UInt gid = cgd->glyphIndex; 1.483 + int32_t advance = 0; 1.484 + 1.485 + if (gid == 0) { 1.486 + advance = -1; // trigger the missing glyphs case below 1.487 + } else { 1.488 + // find next character and its glyph -- in case they exist 1.489 + // and exist in the current font face -- to compute kerning 1.490 + char16_t chNext = 0; 1.491 + FT_UInt gidNext = 0; 1.492 + FT_Pos lsbDeltaNext = 0; 1.493 + 1.494 + if (FT_HAS_KERNING(face) && i + 1 < aLength) { 1.495 + chNext = aText[i + 1]; 1.496 + if (chNext != 0) { 1.497 + cgdNext = GetGlyphDataForChar(chNext); 1.498 + gidNext = cgdNext->glyphIndex; 1.499 + if (gidNext && gidNext != spaceGlyph) 1.500 + lsbDeltaNext = cgdNext->lsbDelta; 1.501 + } 1.502 + } 1.503 + 1.504 + advance = cgd->xAdvance; 1.505 + 1.506 + // now add kerning to the current glyph's advance 1.507 + if (chNext && gidNext) { 1.508 + FT_Vector kerning; kerning.x = 0; 1.509 + FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning); 1.510 + advance += kerning.x; 1.511 + if (cgd->rsbDelta - lsbDeltaNext >= 32) { 1.512 + advance -= 64; 1.513 + } else if (cgd->rsbDelta - lsbDeltaNext < -32) { 1.514 + advance += 64; 1.515 + } 1.516 + } 1.517 + 1.518 + // convert 26.6 fixed point to app units 1.519 + // round rather than truncate to nearest pixel 1.520 + // because these advances are often scaled 1.521 + advance = ((advance * appUnitsPerDevUnit + 32) >> 6); 1.522 + } 1.523 + 1.524 + if (advance >= 0 && 1.525 + gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) && 1.526 + gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) { 1.527 + charGlyphs[aOffset].SetSimpleGlyph(advance, gid); 1.528 + } else if (gid == 0) { 1.529 + // gid = 0 only happens when the glyph is missing from the font 1.530 + aShapedText->SetMissingGlyph(aOffset, ch, this); 1.531 + } else { 1.532 + gfxTextRun::DetailedGlyph details; 1.533 + details.mGlyphID = gid; 1.534 + NS_ASSERTION(details.mGlyphID == gid, 1.535 + "Seriously weird glyph ID detected!"); 1.536 + details.mAdvance = advance; 1.537 + details.mXOffset = 0; 1.538 + details.mYOffset = 0; 1.539 + gfxShapedText::CompressedGlyph g; 1.540 + g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1); 1.541 + aShapedText->SetGlyphs(aOffset, g, &details); 1.542 + } 1.543 + } 1.544 +} 1.545 + 1.546 +gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont, 1.547 + FT2FontEntry *aFontEntry, 1.548 + const gfxFontStyle *aFontStyle, 1.549 + bool aNeedsBold) 1.550 + : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle) 1.551 + , mCharGlyphCache(64) 1.552 +{ 1.553 + NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack."); 1.554 + mApplySyntheticBold = aNeedsBold; 1.555 +} 1.556 + 1.557 +gfxFT2Font::~gfxFT2Font() 1.558 +{ 1.559 +} 1.560 + 1.561 +/** 1.562 + * Look up the font in the gfxFont cache. If we don't find it, create one. 1.563 + * In either case, add a ref, append it to the aFonts array, and return it --- 1.564 + * except for OOM in which case we do nothing and return null. 1.565 + */ 1.566 +already_AddRefed<gfxFT2Font> 1.567 +gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, 1.568 + bool aNeedsBold) 1.569 +{ 1.570 +#ifdef ANDROID 1.571 + FT2FontEntry *fe = static_cast<FT2FontEntry*> 1.572 + (gfxPlatformFontList::PlatformFontList()-> 1.573 + FindFontForFamily(aName, aStyle, aNeedsBold)); 1.574 +#else 1.575 + FT2FontEntry *fe = static_cast<FT2FontEntry*> 1.576 + (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle)); 1.577 +#endif 1.578 + if (!fe) { 1.579 + NS_WARNING("Failed to find font entry for font!"); 1.580 + return nullptr; 1.581 + } 1.582 + 1.583 + nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle, aNeedsBold); 1.584 + return font.forget(); 1.585 +} 1.586 + 1.587 +already_AddRefed<gfxFT2Font> 1.588 +gfxFT2Font::GetOrMakeFont(FT2FontEntry *aFontEntry, const gfxFontStyle *aStyle, 1.589 + bool aNeedsBold) 1.590 +{ 1.591 + nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry, aStyle); 1.592 + if (!font) { 1.593 + cairo_scaled_font_t *scaledFont = aFontEntry->CreateScaledFont(aStyle); 1.594 + if (!scaledFont) { 1.595 + return nullptr; 1.596 + } 1.597 + font = new gfxFT2Font(scaledFont, aFontEntry, aStyle, aNeedsBold); 1.598 + cairo_scaled_font_destroy(scaledFont); 1.599 + if (!font) { 1.600 + return nullptr; 1.601 + } 1.602 + gfxFontCache::GetCache()->AddNew(font); 1.603 + } 1.604 + return font.forget().downcast<gfxFT2Font>(); 1.605 +} 1.606 + 1.607 +void 1.608 +gfxFT2Font::FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd) 1.609 +{ 1.610 + gfxFT2LockedFace faceLock(this); 1.611 + FT_Face face = faceLock.get(); 1.612 + 1.613 + if (!face->charmap || face->charmap->encoding != FT_ENCODING_UNICODE) { 1.614 + FT_Select_Charmap(face, FT_ENCODING_UNICODE); 1.615 + } 1.616 + FT_UInt gid = FT_Get_Char_Index(face, ch); 1.617 + 1.618 + if (gid == 0) { 1.619 + // this font doesn't support this char! 1.620 + NS_ASSERTION(gid != 0, "We don't have a glyph, but font indicated that it supported this char in tables?"); 1.621 + gd->glyphIndex = 0; 1.622 + return; 1.623 + } 1.624 + 1.625 + FT_Int32 flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ? 1.626 + FT_LOAD_DEFAULT : 1.627 + (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING); 1.628 + FT_Error err = FT_Load_Glyph(face, gid, flags); 1.629 + 1.630 + if (err) { 1.631 + // hmm, this is weird, we failed to load a glyph that we had? 1.632 + NS_WARNING("Failed to load glyph that we got from Get_Char_index"); 1.633 + 1.634 + gd->glyphIndex = 0; 1.635 + return; 1.636 + } 1.637 + 1.638 + gd->glyphIndex = gid; 1.639 + gd->lsbDelta = face->glyph->lsb_delta; 1.640 + gd->rsbDelta = face->glyph->rsb_delta; 1.641 + gd->xAdvance = face->glyph->advance.x; 1.642 +} 1.643 + 1.644 +void 1.645 +gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.646 + FontCacheSizes* aSizes) const 1.647 +{ 1.648 + gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); 1.649 + aSizes->mFontInstances += 1.650 + mCharGlyphCache.SizeOfExcludingThis(nullptr, aMallocSizeOf); 1.651 +} 1.652 + 1.653 +void 1.654 +gfxFT2Font::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.655 + FontCacheSizes* aSizes) const 1.656 +{ 1.657 + aSizes->mFontInstances += aMallocSizeOf(this); 1.658 + AddSizeOfExcludingThis(aMallocSizeOf, aSizes); 1.659 +} 1.660 + 1.661 +#ifdef USE_SKIA 1.662 +mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> 1.663 +gfxFT2Font::GetGlyphRenderingOptions() 1.664 +{ 1.665 + mozilla::gfx::FontHinting hinting; 1.666 + 1.667 + if (gfxPlatform::GetPlatform()->FontHintingEnabled()) { 1.668 + hinting = mozilla::gfx::FontHinting::NORMAL; 1.669 + } else { 1.670 + hinting = mozilla::gfx::FontHinting::NONE; 1.671 + } 1.672 + 1.673 + // We don't want to force the use of the autohinter over the font's built in hints 1.674 + return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false); 1.675 +} 1.676 +#endif 1.677 +