michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #if defined(MOZ_WIDGET_GTK) michael@0: #include "gfxPlatformGtk.h" michael@0: #define gfxToolkitPlatform gfxPlatformGtk michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: #include michael@0: #include "gfxQtPlatform.h" michael@0: #define gfxToolkitPlatform gfxQtPlatform michael@0: #elif defined(XP_WIN) michael@0: #include "gfxWindowsPlatform.h" michael@0: #define gfxToolkitPlatform gfxWindowsPlatform michael@0: #elif defined(ANDROID) michael@0: #include "gfxAndroidPlatform.h" michael@0: #define gfxToolkitPlatform gfxAndroidPlatform michael@0: #endif michael@0: michael@0: #include "gfxTypes.h" michael@0: #include "gfxFT2Fonts.h" michael@0: #include "gfxFT2FontBase.h" michael@0: #include "gfxFT2Utils.h" michael@0: #include "gfxFT2FontList.h" michael@0: #include michael@0: #include "gfxHarfBuzzShaper.h" michael@0: #include "gfxGraphiteShaper.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsTArray.h" michael@0: #include "nsUnicodeRange.h" michael@0: #include "nsCRT.h" michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: #include "prlog.h" michael@0: #include "prinit.h" michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: // rounding and truncation functions for a Freetype floating point number michael@0: // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer michael@0: // part and low 6 bits for the fractional part. michael@0: #define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1 michael@0: #define MOZ_FT_TRUNC(x) ((x) >> 6) michael@0: #define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \ michael@0: MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s)))) michael@0: michael@0: #ifndef ANDROID // not needed on Android, we use the generic gfxFontGroup michael@0: /** michael@0: * gfxFT2FontGroup michael@0: */ michael@0: michael@0: static PRLogModuleInfo * michael@0: GetFontLog() michael@0: { michael@0: static PRLogModuleInfo *sLog; michael@0: if (!sLog) michael@0: sLog = PR_NewLogModule("ft2fonts"); michael@0: return sLog; michael@0: } michael@0: michael@0: bool michael@0: gfxFT2FontGroup::FontCallback(const nsAString& fontName, michael@0: const nsACString& genericName, michael@0: bool aUseFontSet, michael@0: void *closure) michael@0: { michael@0: nsTArray *sa = static_cast*>(closure); michael@0: michael@0: if (!fontName.IsEmpty() && !sa->Contains(fontName)) { michael@0: sa->AppendElement(fontName); michael@0: #ifdef DEBUG_pavlov michael@0: printf(" - %s\n", NS_ConvertUTF16toUTF8(fontName).get()); michael@0: #endif michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: gfxFT2FontGroup::gfxFT2FontGroup(const nsAString& families, michael@0: const gfxFontStyle *aStyle, michael@0: gfxUserFontSet *aUserFontSet) michael@0: : gfxFontGroup(families, aStyle, aUserFontSet) michael@0: { michael@0: #ifdef DEBUG_pavlov michael@0: printf("Looking for %s\n", NS_ConvertUTF16toUTF8(families).get()); michael@0: #endif michael@0: nsTArray familyArray; michael@0: ForEachFont(FontCallback, &familyArray); michael@0: michael@0: if (familyArray.Length() == 0) { michael@0: nsAutoString prefFamilies; michael@0: gfxToolkitPlatform::GetPlatform()->GetPrefFonts(aStyle->language, prefFamilies, nullptr); michael@0: if (!prefFamilies.IsEmpty()) { michael@0: ForEachFont(prefFamilies, aStyle->language, FontCallback, &familyArray); michael@0: } michael@0: } michael@0: if (familyArray.Length() == 0) { michael@0: #if defined(MOZ_WIDGET_QT) /* FIXME DFB */ michael@0: printf("failde to find a font. sadface\n"); michael@0: // We want to get rid of this entirely at some point, but first we need real lists of fonts. michael@0: QFont defaultFont; michael@0: QFontInfo fi (defaultFont); michael@0: familyArray.AppendElement(nsDependentString(static_cast(fi.family().utf16()))); michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: FcResult result; michael@0: FcChar8 *family = nullptr; michael@0: FcPattern* pat = FcPatternCreate(); michael@0: FcPattern *match = FcFontMatch(nullptr, pat, &result); michael@0: if (match) michael@0: FcPatternGetString(match, FC_FAMILY, 0, &family); michael@0: if (family) michael@0: familyArray.AppendElement(NS_ConvertUTF8toUTF16((char*)family)); michael@0: #elif defined(XP_WIN) michael@0: HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT); michael@0: LOGFONTW logFont; michael@0: if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) michael@0: familyArray.AppendElement(nsDependentString(logFont.lfFaceName)); michael@0: #elif defined(ANDROID) michael@0: familyArray.AppendElement(NS_LITERAL_STRING("Droid Sans")); michael@0: familyArray.AppendElement(NS_LITERAL_STRING("Roboto")); michael@0: #else michael@0: #error "Platform not supported" michael@0: #endif michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < familyArray.Length(); i++) { michael@0: nsRefPtr font = gfxFT2Font::GetOrMakeFont(familyArray[i], &mStyle); michael@0: if (font) { michael@0: mFonts.AppendElement(font); michael@0: } michael@0: } michael@0: NS_ASSERTION(mFonts.Length() > 0, "We need at least one font in a fontgroup"); michael@0: } michael@0: michael@0: gfxFT2FontGroup::~gfxFT2FontGroup() michael@0: { michael@0: } michael@0: michael@0: gfxFontGroup * michael@0: gfxFT2FontGroup::Copy(const gfxFontStyle *aStyle) michael@0: { michael@0: return new gfxFT2FontGroup(mFamilies, aStyle, nullptr); michael@0: } michael@0: michael@0: // Helper function to return the leading UTF-8 character in a char pointer michael@0: // as 32bit number. Also sets the length of the current character (i.e. the michael@0: // offset to the next one) in the second argument michael@0: uint32_t getUTF8CharAndNext(const uint8_t *aString, uint8_t *aLength) michael@0: { michael@0: *aLength = 1; michael@0: if (aString[0] < 0x80) { // normal 7bit ASCII char michael@0: return aString[0]; michael@0: } michael@0: if ((aString[0] >> 5) == 6) { // two leading ones -> two bytes michael@0: *aLength = 2; michael@0: return ((aString[0] & 0x1F) << 6) + (aString[1] & 0x3F); michael@0: } michael@0: if ((aString[0] >> 4) == 14) { // three leading ones -> three bytes michael@0: *aLength = 3; michael@0: return ((aString[0] & 0x0F) << 12) + ((aString[1] & 0x3F) << 6) + michael@0: (aString[2] & 0x3F); michael@0: } michael@0: if ((aString[0] >> 4) == 15) { // four leading ones -> four bytes michael@0: *aLength = 4; michael@0: return ((aString[0] & 0x07) << 18) + ((aString[1] & 0x3F) << 12) + michael@0: ((aString[2] & 0x3F) << 6) + (aString[3] & 0x3F); michael@0: } michael@0: return aString[0]; michael@0: } michael@0: michael@0: michael@0: static bool michael@0: AddFontNameToArray(const nsAString& aName, michael@0: const nsACString& aGenericName, michael@0: bool aUseFontSet, michael@0: void *aClosure) michael@0: { michael@0: if (!aName.IsEmpty()) { michael@0: nsTArray *list = static_cast *>(aClosure); michael@0: michael@0: if (list->IndexOf(aName) == list->NoIndex) michael@0: list->AppendElement(aName); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies, michael@0: nsIAtom *aLangGroup, michael@0: nsTArray > *aFontEntryList) michael@0: { michael@0: nsAutoTArray fonts; michael@0: ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts); michael@0: michael@0: uint32_t len = fonts.Length(); michael@0: for (uint32_t i = 0; i < len; ++i) { michael@0: const nsString& str = fonts[i]; michael@0: nsRefPtr fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle)); michael@0: aFontEntryList->AppendElement(fe); michael@0: } michael@0: } michael@0: michael@0: void gfxFT2FontGroup::GetPrefFonts(nsIAtom *aLangGroup, nsTArray >& aFontEntryList) michael@0: { michael@0: NS_ASSERTION(aLangGroup, "aLangGroup is null"); michael@0: gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); michael@0: nsAutoTArray, 5> fonts; michael@0: nsAutoCString key; michael@0: aLangGroup->ToUTF8String(key); michael@0: key.Append("-"); michael@0: key.AppendInt(GetStyle()->style); michael@0: key.Append("-"); michael@0: key.AppendInt(GetStyle()->weight); michael@0: if (!platform->GetPrefFontEntries(key, &fonts)) { michael@0: nsString fontString; michael@0: platform->GetPrefFonts(aLangGroup, fontString); michael@0: if (fontString.IsEmpty()) michael@0: return; michael@0: michael@0: FamilyListToArrayList(fontString, aLangGroup, &fonts); michael@0: michael@0: platform->SetPrefFontEntries(key, fonts); michael@0: } michael@0: aFontEntryList.AppendElements(fonts); michael@0: } michael@0: michael@0: static int32_t GetCJKLangGroupIndex(const char *aLangGroup) { michael@0: int32_t i; michael@0: for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) { michael@0: if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i])) michael@0: return i; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: // this function assigns to the array passed in. michael@0: void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray >& aFontEntryList) { michael@0: gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); michael@0: michael@0: nsAutoCString key("x-internal-cjk-"); michael@0: key.AppendInt(mStyle.style); michael@0: key.Append("-"); michael@0: key.AppendInt(mStyle.weight); michael@0: michael@0: if (!platform->GetPrefFontEntries(key, &aFontEntryList)) { michael@0: NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch()); michael@0: // Add the CJK pref fonts from accept languages, the order should be same order michael@0: nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages"); michael@0: if (!list.IsEmpty()) { michael@0: const char kComma = ','; michael@0: const char *p, *p_end; michael@0: list.BeginReading(p); michael@0: list.EndReading(p_end); michael@0: while (p < p_end) { michael@0: while (nsCRT::IsAsciiSpace(*p)) { michael@0: if (++p == p_end) michael@0: break; michael@0: } michael@0: if (p == p_end) michael@0: break; michael@0: const char *start = p; michael@0: while (++p != p_end && *p != kComma) michael@0: /* nothing */ ; michael@0: nsAutoCString lang(Substring(start, p)); michael@0: lang.CompressWhitespace(false, true); michael@0: int32_t index = GetCJKLangGroupIndex(lang.get()); michael@0: if (index >= 0) { michael@0: nsCOMPtr atom = do_GetAtom(sCJKLangGroup[index]); michael@0: GetPrefFonts(atom, aFontEntryList); michael@0: } michael@0: p++; michael@0: } michael@0: } michael@0: michael@0: // Add the system locale michael@0: #ifdef XP_WIN michael@0: switch (::GetACP()) { michael@0: case 932: GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); break; michael@0: case 936: GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); break; michael@0: case 949: GetPrefFonts(nsGkAtoms::ko, aFontEntryList); break; michael@0: // XXX Don't we need to append nsGkAtoms::zh_hk if the codepage is 950? michael@0: case 950: GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); break; michael@0: } michael@0: #else michael@0: const char *ctype = setlocale(LC_CTYPE, nullptr); michael@0: if (ctype) { michael@0: if (!PL_strncasecmp(ctype, "ja", 2)) { michael@0: GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); michael@0: } else if (!PL_strncasecmp(ctype, "zh_cn", 5)) { michael@0: GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); michael@0: } else if (!PL_strncasecmp(ctype, "zh_hk", 5)) { michael@0: GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList); michael@0: } else if (!PL_strncasecmp(ctype, "zh_tw", 5)) { michael@0: GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); michael@0: } else if (!PL_strncasecmp(ctype, "ko", 2)) { michael@0: GetPrefFonts(nsGkAtoms::ko, aFontEntryList); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // last resort... michael@0: GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); michael@0: GetPrefFonts(nsGkAtoms::ko, aFontEntryList); michael@0: GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); michael@0: GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList); michael@0: GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); michael@0: michael@0: platform->SetPrefFontEntries(key, aFontEntryList); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray >& aFontEntryList, uint32_t aCh) michael@0: { michael@0: for (uint32_t i = 0; i < aFontEntryList.Length(); i++) { michael@0: gfxFontEntry *fe = aFontEntryList[i].get(); michael@0: if (fe->HasCharacter(aCh)) { michael@0: nsRefPtr font = michael@0: gfxFT2Font::GetOrMakeFont(static_cast(fe), &mStyle); michael@0: return font.forget(); michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxFT2FontGroup::WhichPrefFontSupportsChar(uint32_t aCh) michael@0: { michael@0: if (aCh > 0xFFFF) michael@0: return nullptr; michael@0: michael@0: nsRefPtr selectedFont; michael@0: michael@0: // check out the style's language michael@0: nsAutoTArray, 5> fonts; michael@0: GetPrefFonts(mStyle.language, fonts); michael@0: selectedFont = WhichFontSupportsChar(fonts, aCh); michael@0: michael@0: // otherwise search prefs michael@0: if (!selectedFont) { michael@0: uint32_t unicodeRange = FindCharUnicodeRange(aCh); michael@0: michael@0: /* special case CJK */ michael@0: if (unicodeRange == kRangeSetCJK) { michael@0: if (PR_LOG_TEST(GetFontLog(), PR_LOG_DEBUG)) { michael@0: PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: CJK")); michael@0: } michael@0: michael@0: nsAutoTArray, 15> fonts; michael@0: GetCJKPrefFonts(fonts); michael@0: selectedFont = WhichFontSupportsChar(fonts, aCh); michael@0: } else { michael@0: nsIAtom *langGroup = LangGroupFromUnicodeRange(unicodeRange); michael@0: if (langGroup) { michael@0: PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: %s", nsAtomCString(langGroup).get())); michael@0: michael@0: nsAutoTArray, 5> fonts; michael@0: GetPrefFonts(langGroup, fonts); michael@0: selectedFont = WhichFontSupportsChar(fonts, aCh); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (selectedFont) { michael@0: nsRefPtr f = static_cast(selectedFont.get()); michael@0: return f.forget(); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxFT2FontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript) michael@0: { michael@0: #if defined(XP_WIN) || defined(ANDROID) michael@0: FontEntry *fe = static_cast michael@0: (gfxPlatformFontList::PlatformFontList()-> michael@0: SystemFindFontForChar(aCh, aRunScript, &mStyle)); michael@0: if (fe) { michael@0: nsRefPtr f = gfxFT2Font::GetOrMakeFont(fe, &mStyle); michael@0: nsRefPtr font = f.get(); michael@0: return font.forget(); michael@0: } michael@0: #else michael@0: nsRefPtr selectedFont; michael@0: nsRefPtr refFont = GetFontAt(0); michael@0: gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); michael@0: selectedFont = platform->FindFontForChar(aCh, refFont); michael@0: if (selectedFont) michael@0: return selectedFont.forget(); michael@0: #endif michael@0: return nullptr; michael@0: } michael@0: michael@0: #endif // !ANDROID michael@0: michael@0: /** michael@0: * gfxFT2Font michael@0: */ michael@0: michael@0: bool michael@0: gfxFT2Font::ShapeText(gfxContext *aContext, michael@0: const char16_t *aText, michael@0: uint32_t aOffset, michael@0: uint32_t aLength, michael@0: int32_t aScript, michael@0: gfxShapedText *aShapedText, michael@0: bool aPreferPlatformShaping) michael@0: { michael@0: bool ok = false; michael@0: michael@0: if (FontCanSupportGraphite()) { michael@0: if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) { michael@0: if (!mGraphiteShaper) { michael@0: mGraphiteShaper = new gfxGraphiteShaper(this); michael@0: } michael@0: ok = mGraphiteShaper->ShapeText(aContext, aText, michael@0: aOffset, aLength, michael@0: aScript, aShapedText); michael@0: } michael@0: } michael@0: michael@0: if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) { michael@0: if (!mHarfBuzzShaper) { michael@0: mHarfBuzzShaper = new gfxHarfBuzzShaper(this); michael@0: } michael@0: ok = mHarfBuzzShaper->ShapeText(aContext, aText, michael@0: aOffset, aLength, michael@0: aScript, aShapedText); michael@0: } michael@0: michael@0: if (!ok) { michael@0: AddRange(aText, aOffset, aLength, aShapedText); michael@0: } michael@0: michael@0: PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset, michael@0: uint32_t aLength, gfxShapedText *aShapedText) michael@0: { michael@0: const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit(); michael@0: // we'll pass this in/figure it out dynamically, but at this point there can be only one face. michael@0: gfxFT2LockedFace faceLock(this); michael@0: FT_Face face = faceLock.get(); michael@0: michael@0: gfxShapedText::CompressedGlyph *charGlyphs = michael@0: aShapedText->GetCharacterGlyphs(); michael@0: michael@0: const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr; michael@0: michael@0: FT_UInt spaceGlyph = GetSpaceGlyph(); michael@0: michael@0: for (uint32_t i = 0; i < aLength; i++, aOffset++) { michael@0: char16_t ch = aText[i]; michael@0: michael@0: if (ch == 0) { michael@0: // treat this null byte as a missing glyph, don't create a glyph for it michael@0: aShapedText->SetMissingGlyph(aOffset, 0, this); michael@0: continue; michael@0: } michael@0: michael@0: NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected"); michael@0: michael@0: if (cgdNext) { michael@0: cgd = cgdNext; michael@0: cgdNext = nullptr; michael@0: } else { michael@0: cgd = GetGlyphDataForChar(ch); michael@0: } michael@0: michael@0: FT_UInt gid = cgd->glyphIndex; michael@0: int32_t advance = 0; michael@0: michael@0: if (gid == 0) { michael@0: advance = -1; // trigger the missing glyphs case below michael@0: } else { michael@0: // find next character and its glyph -- in case they exist michael@0: // and exist in the current font face -- to compute kerning michael@0: char16_t chNext = 0; michael@0: FT_UInt gidNext = 0; michael@0: FT_Pos lsbDeltaNext = 0; michael@0: michael@0: if (FT_HAS_KERNING(face) && i + 1 < aLength) { michael@0: chNext = aText[i + 1]; michael@0: if (chNext != 0) { michael@0: cgdNext = GetGlyphDataForChar(chNext); michael@0: gidNext = cgdNext->glyphIndex; michael@0: if (gidNext && gidNext != spaceGlyph) michael@0: lsbDeltaNext = cgdNext->lsbDelta; michael@0: } michael@0: } michael@0: michael@0: advance = cgd->xAdvance; michael@0: michael@0: // now add kerning to the current glyph's advance michael@0: if (chNext && gidNext) { michael@0: FT_Vector kerning; kerning.x = 0; michael@0: FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning); michael@0: advance += kerning.x; michael@0: if (cgd->rsbDelta - lsbDeltaNext >= 32) { michael@0: advance -= 64; michael@0: } else if (cgd->rsbDelta - lsbDeltaNext < -32) { michael@0: advance += 64; michael@0: } michael@0: } michael@0: michael@0: // convert 26.6 fixed point to app units michael@0: // round rather than truncate to nearest pixel michael@0: // because these advances are often scaled michael@0: advance = ((advance * appUnitsPerDevUnit + 32) >> 6); michael@0: } michael@0: michael@0: if (advance >= 0 && michael@0: gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) && michael@0: gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) { michael@0: charGlyphs[aOffset].SetSimpleGlyph(advance, gid); michael@0: } else if (gid == 0) { michael@0: // gid = 0 only happens when the glyph is missing from the font michael@0: aShapedText->SetMissingGlyph(aOffset, ch, this); michael@0: } else { michael@0: gfxTextRun::DetailedGlyph details; michael@0: details.mGlyphID = gid; michael@0: NS_ASSERTION(details.mGlyphID == gid, michael@0: "Seriously weird glyph ID detected!"); michael@0: details.mAdvance = advance; michael@0: details.mXOffset = 0; michael@0: details.mYOffset = 0; michael@0: gfxShapedText::CompressedGlyph g; michael@0: g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1); michael@0: aShapedText->SetGlyphs(aOffset, g, &details); michael@0: } michael@0: } michael@0: } michael@0: michael@0: gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont, michael@0: FT2FontEntry *aFontEntry, michael@0: const gfxFontStyle *aFontStyle, michael@0: bool aNeedsBold) michael@0: : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle) michael@0: , mCharGlyphCache(64) michael@0: { michael@0: NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack."); michael@0: mApplySyntheticBold = aNeedsBold; michael@0: } michael@0: michael@0: gfxFT2Font::~gfxFT2Font() michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Look up the font in the gfxFont cache. If we don't find it, create one. michael@0: * In either case, add a ref, append it to the aFonts array, and return it --- michael@0: * except for OOM in which case we do nothing and return null. michael@0: */ michael@0: already_AddRefed michael@0: gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, michael@0: bool aNeedsBold) michael@0: { michael@0: #ifdef ANDROID michael@0: FT2FontEntry *fe = static_cast michael@0: (gfxPlatformFontList::PlatformFontList()-> michael@0: FindFontForFamily(aName, aStyle, aNeedsBold)); michael@0: #else michael@0: FT2FontEntry *fe = static_cast michael@0: (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle)); michael@0: #endif michael@0: if (!fe) { michael@0: NS_WARNING("Failed to find font entry for font!"); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr font = GetOrMakeFont(fe, aStyle, aNeedsBold); michael@0: return font.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxFT2Font::GetOrMakeFont(FT2FontEntry *aFontEntry, const gfxFontStyle *aStyle, michael@0: bool aNeedsBold) michael@0: { michael@0: nsRefPtr font = gfxFontCache::GetCache()->Lookup(aFontEntry, aStyle); michael@0: if (!font) { michael@0: cairo_scaled_font_t *scaledFont = aFontEntry->CreateScaledFont(aStyle); michael@0: if (!scaledFont) { michael@0: return nullptr; michael@0: } michael@0: font = new gfxFT2Font(scaledFont, aFontEntry, aStyle, aNeedsBold); michael@0: cairo_scaled_font_destroy(scaledFont); michael@0: if (!font) { michael@0: return nullptr; michael@0: } michael@0: gfxFontCache::GetCache()->AddNew(font); michael@0: } michael@0: return font.forget().downcast(); michael@0: } michael@0: michael@0: void michael@0: gfxFT2Font::FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd) michael@0: { michael@0: gfxFT2LockedFace faceLock(this); michael@0: FT_Face face = faceLock.get(); michael@0: michael@0: if (!face->charmap || face->charmap->encoding != FT_ENCODING_UNICODE) { michael@0: FT_Select_Charmap(face, FT_ENCODING_UNICODE); michael@0: } michael@0: FT_UInt gid = FT_Get_Char_Index(face, ch); michael@0: michael@0: if (gid == 0) { michael@0: // this font doesn't support this char! michael@0: NS_ASSERTION(gid != 0, "We don't have a glyph, but font indicated that it supported this char in tables?"); michael@0: gd->glyphIndex = 0; michael@0: return; michael@0: } michael@0: michael@0: FT_Int32 flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ? michael@0: FT_LOAD_DEFAULT : michael@0: (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING); michael@0: FT_Error err = FT_Load_Glyph(face, gid, flags); michael@0: michael@0: if (err) { michael@0: // hmm, this is weird, we failed to load a glyph that we had? michael@0: NS_WARNING("Failed to load glyph that we got from Get_Char_index"); michael@0: michael@0: gd->glyphIndex = 0; michael@0: return; michael@0: } michael@0: michael@0: gd->glyphIndex = gid; michael@0: gd->lsbDelta = face->glyph->lsb_delta; michael@0: gd->rsbDelta = face->glyph->rsb_delta; michael@0: gd->xAdvance = face->glyph->advance.x; michael@0: } michael@0: michael@0: void michael@0: gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontCacheSizes* aSizes) const michael@0: { michael@0: gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); michael@0: aSizes->mFontInstances += michael@0: mCharGlyphCache.SizeOfExcludingThis(nullptr, aMallocSizeOf); michael@0: } michael@0: michael@0: void michael@0: gfxFT2Font::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontCacheSizes* aSizes) const michael@0: { michael@0: aSizes->mFontInstances += aMallocSizeOf(this); michael@0: AddSizeOfExcludingThis(aMallocSizeOf, aSizes); michael@0: } michael@0: michael@0: #ifdef USE_SKIA michael@0: mozilla::TemporaryRef michael@0: gfxFT2Font::GetGlyphRenderingOptions() michael@0: { michael@0: mozilla::gfx::FontHinting hinting; michael@0: michael@0: if (gfxPlatform::GetPlatform()->FontHintingEnabled()) { michael@0: hinting = mozilla::gfx::FontHinting::NORMAL; michael@0: } else { michael@0: hinting = mozilla::gfx::FontHinting::NONE; michael@0: } michael@0: michael@0: // We don't want to force the use of the autohinter over the font's built in hints michael@0: return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false); michael@0: } michael@0: #endif michael@0: