123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170 |
- /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "mozilla/DebugOnly.h"
- #include <algorithm>
- #include "mozilla/Logging.h"
- #include "mozilla/Sprintf.h"
- #include "gfxGDIFontList.h"
- #include "gfxWindowsPlatform.h"
- #include "gfxUserFontSet.h"
- #include "gfxFontUtils.h"
- #include "gfxGDIFont.h"
- #include "nsServiceManagerUtils.h"
- #include "nsTArray.h"
- #include "nsUnicharUtils.h"
- #include "nsDirectoryServiceUtils.h"
- #include "nsDirectoryServiceDefs.h"
- #include "nsAppDirectoryServiceDefs.h"
- #include "nsISimpleEnumerator.h"
- #include "nsIWindowsRegKey.h"
- #include "gfxFontConstants.h"
- #include "GeckoProfiler.h"
- #include "mozilla/MemoryReporting.h"
- #include "mozilla/Telemetry.h"
- #include "mozilla/WindowsVersion.h"
- #include <usp10.h>
- using namespace mozilla;
- #define ROUND(x) floor((x) + 0.5)
- #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
- LogLevel::Debug, args)
- #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
- gfxPlatform::GetLog(eGfxLog_fontlist), \
- LogLevel::Debug)
- #define LOG_CMAPDATA_ENABLED() MOZ_LOG_TEST( \
- gfxPlatform::GetLog(eGfxLog_cmapdata), \
- LogLevel::Debug)
- static __inline void
- BuildKeyNameFromFontName(nsAString &aName)
- {
- if (aName.Length() >= LF_FACESIZE)
- aName.Truncate(LF_FACESIZE - 1);
- ToLowerCase(aName);
- }
- // Implementation of gfxPlatformFontList for Win32 GDI,
- // using GDI font enumeration APIs to get the list of fonts
- class WinUserFontData : public gfxUserFontData {
- public:
- WinUserFontData(HANDLE aFontRef)
- : mFontRef(aFontRef)
- { }
- virtual ~WinUserFontData()
- {
- DebugOnly<BOOL> success;
- success = RemoveFontMemResourceEx(mFontRef);
- #if DEBUG
- if (!success) {
- char buf[256];
- SprintfLiteral(buf, "error deleting font handle (%p) - RemoveFontMemResourceEx failed", mFontRef);
- NS_ASSERTION(success, buf);
- }
- #endif
- }
- HANDLE mFontRef;
- };
- BYTE
- FontTypeToOutPrecision(uint8_t fontType)
- {
- BYTE ret;
- switch (fontType) {
- case GFX_FONT_TYPE_TT_OPENTYPE:
- case GFX_FONT_TYPE_TRUETYPE:
- ret = OUT_TT_ONLY_PRECIS;
- break;
- case GFX_FONT_TYPE_PS_OPENTYPE:
- ret = OUT_PS_ONLY_PRECIS;
- break;
- case GFX_FONT_TYPE_TYPE1:
- ret = OUT_OUTLINE_PRECIS;
- break;
- case GFX_FONT_TYPE_RASTER:
- ret = OUT_RASTER_PRECIS;
- break;
- case GFX_FONT_TYPE_DEVICE:
- ret = OUT_DEVICE_PRECIS;
- break;
- default:
- ret = OUT_DEFAULT_PRECIS;
- }
- return ret;
- }
- /***************************************************************
- *
- * GDIFontEntry
- *
- */
- GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
- gfxWindowsFontType aFontType,
- uint8_t aStyle, uint16_t aWeight,
- int16_t aStretch,
- gfxUserFontData *aUserFontData,
- bool aFamilyHasItalicFace)
- : gfxFontEntry(aFaceName),
- mWindowsFamily(0), mWindowsPitch(0),
- mFontType(aFontType),
- mForceGDI(false),
- mFamilyHasItalicFace(aFamilyHasItalicFace),
- mCharset(), mUnicodeRanges()
- {
- mUserFontData.reset(aUserFontData);
- mStyle = aStyle;
- mWeight = aWeight;
- mStretch = aStretch;
- if (IsType1())
- mForceGDI = true;
- mIsDataUserFont = aUserFontData != nullptr;
- InitLogFont(aFaceName, aFontType);
- }
- nsresult
- GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
- {
- PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
- // attempt this once, if errors occur leave a blank cmap
- if (mCharacterMap) {
- return NS_OK;
- }
- // skip non-SFNT fonts completely
- if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE &&
- mFontType != GFX_FONT_TYPE_TT_OPENTYPE &&
- mFontType != GFX_FONT_TYPE_TRUETYPE)
- {
- mCharacterMap = new gfxCharacterMap();
- mCharacterMap->mBuildOnTheFly = true;
- return NS_ERROR_FAILURE;
- }
- RefPtr<gfxCharacterMap> charmap;
- nsresult rv;
- bool unicodeFont = false, symbolFont = false;
- if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
- mUVSOffset,
- symbolFont))) {
- mSymbolFont = symbolFont;
- rv = NS_OK;
- } else {
- uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
- charmap = new gfxCharacterMap();
- AutoTArray<uint8_t, 16384> cmap;
- rv = CopyFontTable(kCMAP, cmap);
- if (NS_SUCCEEDED(rv)) {
- rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
- *charmap, mUVSOffset,
- unicodeFont, symbolFont);
- }
- mSymbolFont = symbolFont;
- }
- mHasCmapTable = NS_SUCCEEDED(rv);
- if (mHasCmapTable) {
- gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
- mCharacterMap = pfl->FindCharMap(charmap);
- } else {
- // if error occurred, initialize to null cmap
- mCharacterMap = new gfxCharacterMap();
- // For fonts where we failed to read the character map,
- // we can take a slow path to look up glyphs character by character
- mCharacterMap->mBuildOnTheFly = true;
- }
- LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
- NS_ConvertUTF16toUTF8(mName).get(),
- charmap->SizeOfIncludingThis(moz_malloc_size_of),
- charmap->mHash, mCharacterMap == charmap ? " new" : ""));
- if (LOG_CMAPDATA_ENABLED()) {
- char prefix[256];
- SprintfLiteral(prefix, "(cmapdata) name: %.220s",
- NS_ConvertUTF16toUTF8(mName).get());
- charmap->Dump(prefix, eGfxLog_cmapdata);
- }
- return rv;
- }
- bool
- GDIFontEntry::IsSymbolFont()
- {
- // initialize cmap first
- HasCmapTable();
- return mSymbolFont;
- }
- gfxFont *
- GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold)
- {
- return new gfxGDIFont(this, aFontStyle, aNeedsBold);
- }
- nsresult
- GDIFontEntry::CopyFontTable(uint32_t aTableTag, nsTArray<uint8_t>& aBuffer)
- {
- if (!IsTrueType()) {
- return NS_ERROR_FAILURE;
- }
- AutoDC dc;
- AutoSelectFont font(dc.GetDC(), &mLogFont);
- if (font.IsValid()) {
- uint32_t tableSize =
- ::GetFontData(dc.GetDC(),
- NativeEndian::swapToBigEndian(aTableTag),
- 0, nullptr, 0);
- if (tableSize != GDI_ERROR) {
- if (aBuffer.SetLength(tableSize, fallible)) {
- ::GetFontData(dc.GetDC(),
- NativeEndian::swapToBigEndian(aTableTag), 0,
- aBuffer.Elements(), tableSize);
- return NS_OK;
- }
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
- return NS_ERROR_FAILURE;
- }
- void
- GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
- uint16_t aWeight, gfxFloat aSize)
- {
- memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
- aLogFont->lfHeight = (LONG)-ROUND(aSize);
- if (aLogFont->lfHeight == 0) {
- aLogFont->lfHeight = -1;
- }
- // If a non-zero weight is passed in, use this to override the original
- // weight in the entry's logfont. This is used to control synthetic bolding
- // for installed families with no bold face, and for downloaded fonts
- // (but NOT for local user fonts, because it could cause a different,
- // glyph-incompatible face to be used)
- if (aWeight) {
- aLogFont->lfWeight = aWeight;
- }
- // for non-local() user fonts, we never want to apply italics here;
- // if the face is described as italic, we should use it as-is,
- // and if it's not, but then the element is styled italic, we'll use
- // a cairo transform to create fake italic (oblique)
- if (mIsDataUserFont) {
- aLogFont->lfItalic = 0;
- }
- }
- #define MISSING_GLYPH 0x1F // glyph index returned for missing characters
- // on WinXP with .fon fonts, but not Type1 (.pfb)
- bool
- GDIFontEntry::TestCharacterMap(uint32_t aCh)
- {
- if (!mCharacterMap) {
- ReadCMAP();
- NS_ASSERTION(mCharacterMap, "failed to initialize a character map");
- }
- if (mCharacterMap->mBuildOnTheFly) {
- if (aCh > 0xFFFF)
- return false;
- // previous code was using the group style
- gfxFontStyle fakeStyle;
- if (!IsUpright()) {
- fakeStyle.style = NS_FONT_STYLE_ITALIC;
- }
- fakeStyle.weight = mWeight * 100;
- RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
- if (!tempFont || !tempFont->Valid())
- return false;
- gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get());
- HDC dc = GetDC((HWND)nullptr);
- SetGraphicsMode(dc, GM_ADVANCED);
- HFONT hfont = font->GetHFONT();
- HFONT oldFont = (HFONT)SelectObject(dc, hfont);
- wchar_t str[1] = { (wchar_t)aCh };
- WORD glyph[1];
- bool hasGlyph = false;
- // Bug 573038 - in some cases GetGlyphIndicesW returns 0xFFFF for a
- // missing glyph or 0x1F in other cases to indicate the "invalid"
- // glyph. Map both cases to "not found"
- if (IsType1() || mForceGDI) {
- // Type1 fonts and uniscribe APIs don't get along.
- // ScriptGetCMap will return E_HANDLE
- DWORD ret = GetGlyphIndicesW(dc, str, 1,
- glyph, GGI_MARK_NONEXISTING_GLYPHS);
- if (ret != GDI_ERROR
- && glyph[0] != 0xFFFF
- && (IsType1() || glyph[0] != MISSING_GLYPH))
- {
- hasGlyph = true;
- }
- } else {
- // ScriptGetCMap works better than GetGlyphIndicesW
- // for things like bitmap/vector fonts
- SCRIPT_CACHE sc = nullptr;
- HRESULT rv = ScriptGetCMap(dc, &sc, str, 1, 0, glyph);
- if (rv == S_OK)
- hasGlyph = true;
- }
- SelectObject(dc, oldFont);
- ReleaseDC(nullptr, dc);
- if (hasGlyph) {
- mCharacterMap->set(aCh);
- return true;
- }
- } else {
- // font had a cmap so simply check that
- return mCharacterMap->test(aCh);
- }
- return false;
- }
- void
- GDIFontEntry::InitLogFont(const nsAString& aName,
- gfxWindowsFontType aFontType)
- {
- #define CLIP_TURNOFF_FONTASSOCIATION 0x40
- mLogFont.lfHeight = -1;
- // Fill in logFont structure
- mLogFont.lfWidth = 0;
- mLogFont.lfEscapement = 0;
- mLogFont.lfOrientation = 0;
- mLogFont.lfUnderline = FALSE;
- mLogFont.lfStrikeOut = FALSE;
- mLogFont.lfCharSet = DEFAULT_CHARSET;
- mLogFont.lfOutPrecision = FontTypeToOutPrecision(aFontType);
- mLogFont.lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION;
- mLogFont.lfQuality = DEFAULT_QUALITY;
- mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- // always force lfItalic if we want it. Font selection code will
- // do its best to give us an italic font entry, but if no face exists
- // it may give us a regular one based on weight. Windows should
- // do fake italic for us in that case.
- mLogFont.lfItalic = !IsUpright();
- mLogFont.lfWeight = mWeight;
- int len = std::min<int>(aName.Length(), LF_FACESIZE - 1);
- memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(char16_t));
- mLogFont.lfFaceName[len] = '\0';
- }
- GDIFontEntry*
- GDIFontEntry::CreateFontEntry(const nsAString& aName,
- gfxWindowsFontType aFontType,
- uint8_t aStyle,
- uint16_t aWeight, int16_t aStretch,
- gfxUserFontData* aUserFontData,
- bool aFamilyHasItalicFace)
- {
- // jtdfix - need to set charset, unicode ranges, pitch/family
- GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aStyle,
- aWeight, aStretch, aUserFontData,
- aFamilyHasItalicFace);
- return fe;
- }
- void
- GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
- FontListSizes* aSizes) const
- {
- aSizes->mFontListSize += aMallocSizeOf(this);
- AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
- }
- /***************************************************************
- *
- * GDIFontFamily
- *
- */
- int CALLBACK
- GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
- const NEWTEXTMETRICEXW *nmetrics,
- DWORD fontType, LPARAM data)
- {
- const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
- LOGFONTW logFont = lpelfe->elfLogFont;
- GDIFontFamily *ff = reinterpret_cast<GDIFontFamily*>(data);
- // Some fonts claim to support things > 900, but we don't so clamp the sizes
- logFont.lfWeight = clamped(logFont.lfWeight, LONG(100), LONG(900));
- gfxWindowsFontType feType = GDIFontEntry::DetermineFontType(metrics, fontType);
- GDIFontEntry *fe = nullptr;
- for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
- fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
- if (feType > fe->mFontType) {
- // if the new type is better than the old one, remove the old entries
- ff->mAvailableFonts.RemoveElementAt(i);
- --i;
- } else if (feType < fe->mFontType) {
- // otherwise if the new type is worse, skip it
- return 1;
- }
- }
- for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
- fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
- // check if we already know about this face
- if (fe->mWeight == logFont.lfWeight &&
- fe->IsItalic() == (logFont.lfItalic == 0xFF)) {
- // update the charset bit here since this could be different
- fe->mCharset.set(metrics.tmCharSet);
- return 1;
- }
- }
- // We can't set the hasItalicFace flag correctly here,
- // because we might not have seen the family's italic face(s) yet.
- // So we'll set that flag for all members after loading all the faces.
- uint8_t italicStyle = (logFont.lfItalic == 0xFF ?
- NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
- fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName),
- feType, italicStyle,
- (uint16_t) (logFont.lfWeight), 0,
- nullptr, false);
- if (!fe)
- return 1;
- ff->AddFontEntry(fe);
- // mark the charset bit
- fe->mCharset.set(metrics.tmCharSet);
- fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
- fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
- if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
- nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
- nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
- nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) {
- // set the unicode ranges
- uint32_t x = 0;
- for (uint32_t i = 0; i < 4; ++i) {
- DWORD range = nmetrics->ntmFontSig.fsUsb[i];
- for (uint32_t k = 0; k < 32; ++k) {
- fe->mUnicodeRanges.set(x++, (range & (1 << k)) != 0);
- }
- }
- }
- if (LOG_FONTLIST_ENABLED()) {
- LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
- " with style: %s weight: %d stretch: %d",
- NS_ConvertUTF16toUTF8(fe->Name()).get(),
- NS_ConvertUTF16toUTF8(ff->Name()).get(),
- (logFont.lfItalic == 0xff) ? "italic" : "normal",
- logFont.lfWeight, fe->Stretch()));
- }
- return 1;
- }
- void
- GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
- {
- if (mHasStyles)
- return;
- mHasStyles = true;
- HDC hdc = GetDC(nullptr);
- SetGraphicsMode(hdc, GM_ADVANCED);
- LOGFONTW logFont;
- memset(&logFont, 0, sizeof(LOGFONTW));
- logFont.lfCharSet = DEFAULT_CHARSET;
- logFont.lfPitchAndFamily = 0;
- uint32_t l = std::min<uint32_t>(mName.Length(), LF_FACESIZE - 1);
- memcpy(logFont.lfFaceName, mName.get(), l * sizeof(char16_t));
- EnumFontFamiliesExW(hdc, &logFont,
- (FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc,
- (LPARAM)this, 0);
- if (LOG_FONTLIST_ENABLED() && mAvailableFonts.Length() == 0) {
- LOG_FONTLIST(("(fontlist) no styles available in family \"%s\"",
- NS_ConvertUTF16toUTF8(mName).get()));
- }
- ReleaseDC(nullptr, hdc);
- if (mIsBadUnderlineFamily) {
- SetBadUnderlineFonts();
- }
- // check for existence of italic face(s); if present, set the
- // FamilyHasItalic flag on all faces so that we'll know *not*
- // to use GDI's fake-italic effect with them
- size_t count = mAvailableFonts.Length();
- for (size_t i = 0; i < count; ++i) {
- if (mAvailableFonts[i]->IsItalic()) {
- for (uint32_t j = 0; j < count; ++j) {
- static_cast<GDIFontEntry*>(mAvailableFonts[j].get())->
- mFamilyHasItalicFace = true;
- }
- break;
- }
- }
- }
- /***************************************************************
- *
- * gfxGDIFontList
- *
- */
- gfxGDIFontList::gfxGDIFontList()
- : mFontSubstitutes(32)
- {
- #ifdef MOZ_BUNDLED_FONTS
- ActivateBundledFonts();
- #endif
- }
- static void
- RemoveCharsetFromFontSubstitute(nsAString &aName)
- {
- int32_t comma = aName.FindChar(char16_t(','));
- if (comma >= 0)
- aName.Truncate(comma);
- }
- #define MAX_VALUE_NAME 512
- #define MAX_VALUE_DATA 512
- nsresult
- gfxGDIFontList::GetFontSubstitutes()
- {
- HKEY hKey;
- DWORD i, rv, lenAlias, lenActual, valueType;
- WCHAR aliasName[MAX_VALUE_NAME];
- WCHAR actualName[MAX_VALUE_DATA];
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
- 0, KEY_READ, &hKey) != ERROR_SUCCESS)
- {
- return NS_ERROR_FAILURE;
- }
- for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
- aliasName[0] = 0;
- lenAlias = ArrayLength(aliasName);
- actualName[0] = 0;
- lenActual = sizeof(actualName);
- rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType,
- (LPBYTE)actualName, &lenActual);
- if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
- continue;
- }
- if (aliasName[0] == WCHAR('@')) {
- continue;
- }
- nsAutoString substituteName((char16_t*) aliasName);
- nsAutoString actualFontName((char16_t*) actualName);
- RemoveCharsetFromFontSubstitute(substituteName);
- BuildKeyNameFromFontName(substituteName);
- RemoveCharsetFromFontSubstitute(actualFontName);
- BuildKeyNameFromFontName(actualFontName);
- gfxFontFamily *ff;
- if (!actualFontName.IsEmpty() &&
- (ff = mFontFamilies.GetWeak(actualFontName))) {
- mFontSubstitutes.Put(substituteName, ff);
- } else {
- mNonExistingFonts.AppendElement(substituteName);
- }
- }
- // "Courier" on a default Windows install is an ugly bitmap font.
- // If there is no substitution for Courier in the registry
- // substitute "Courier" with "Courier New".
- nsAutoString substituteName;
- substituteName.AssignLiteral("Courier");
- BuildKeyNameFromFontName(substituteName);
- if (!mFontSubstitutes.GetWeak(substituteName)) {
- gfxFontFamily *ff;
- nsAutoString actualFontName;
- actualFontName.AssignLiteral("Courier New");
- BuildKeyNameFromFontName(actualFontName);
- ff = mFontFamilies.GetWeak(actualFontName);
- if (ff) {
- mFontSubstitutes.Put(substituteName, ff);
- }
- }
- return NS_OK;
- }
- nsresult
- gfxGDIFontList::InitFontListForPlatform()
- {
- mFontSubstitutes.Clear();
- mNonExistingFonts.Clear();
- // iterate over available families
- LOGFONTW logfont;
- memset(&logfont, 0, sizeof(logfont));
- logfont.lfCharSet = DEFAULT_CHARSET;
- AutoDC hdc;
- int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont,
- (FONTENUMPROCW)&EnumFontFamExProc,
- 0, 0);
- GetFontSubstitutes();
- GetPrefsAndStartLoader();
- return NS_OK;
- }
- int CALLBACK
- gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
- NEWTEXTMETRICEXW *lpntme,
- DWORD fontType,
- LPARAM lParam)
- {
- const LOGFONTW& lf = lpelfe->elfLogFont;
- if (lf.lfFaceName[0] == '@') {
- return 1;
- }
- nsAutoString name(lf.lfFaceName);
- BuildKeyNameFromFontName(name);
- gfxGDIFontList *fontList = PlatformFontList();
- if (!fontList->mFontFamilies.GetWeak(name)) {
- nsDependentString faceName(lf.lfFaceName);
- RefPtr<gfxFontFamily> family = new GDIFontFamily(faceName);
- fontList->mFontFamilies.Put(name, family);
- // if locale is such that CJK font names are the default coming from
- // GDI, then if a family name is non-ASCII immediately read in other
- // family names. This assures that MS Gothic, MS Mincho are all found
- // before lookups begin.
- if (!IsASCII(faceName)) {
- family->ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());
- }
- if (fontList->mBadUnderlineFamilyNames.Contains(name))
- family->SetBadUnderlineFamily();
- }
- return 1;
- }
- gfxFontEntry*
- gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
- uint16_t aWeight,
- int16_t aStretch,
- uint8_t aStyle)
- {
- gfxFontEntry *lookup;
- lookup = LookupInFaceNameLists(aFontName);
- if (!lookup) {
- return nullptr;
- }
- bool isCFF = false; // jtdfix -- need to determine this
-
- // use the face name from the lookup font entry, which will be the localized
- // face name which GDI mapping tables use (e.g. with the system locale set to
- // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
- // 'Arial Vet' which can be used as a key in GDI font lookups).
- GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(),
- gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
- lookup->mStyle, lookup->mWeight, aStretch, nullptr,
- static_cast<GDIFontEntry*>(lookup)->mFamilyHasItalicFace);
- if (!fe)
- return nullptr;
- fe->mIsLocalUserFont = true;
- // make the new font entry match the userfont entry style characteristics
- fe->mWeight = (aWeight == 0 ? 400 : aWeight);
- fe->mStyle = aStyle;
- return fe;
- }
- // If aFontData contains only a MS/Symbol cmap subtable, not MS/Unicode,
- // we modify the subtable header to mark it as Unicode instead, because
- // otherwise GDI will refuse to load the font.
- // NOTE that this function does not bounds-check every access to the font data.
- // This is OK because we only use it on data that has already been validated
- // by OTS, and therefore we will not hit out-of-bounds accesses here.
- static bool
- FixupSymbolEncodedFont(uint8_t* aFontData, uint32_t aLength)
- {
- struct CmapHeader {
- AutoSwap_PRUint16 version;
- AutoSwap_PRUint16 numTables;
- };
- struct CmapEncodingRecord {
- AutoSwap_PRUint16 platformID;
- AutoSwap_PRUint16 encodingID;
- AutoSwap_PRUint32 offset;
- };
- const uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
- const TableDirEntry* dir =
- gfxFontUtils::FindTableDirEntry(aFontData, kCMAP);
- if (dir && uint32_t(dir->length) >= sizeof(CmapHeader)) {
- CmapHeader *cmap =
- reinterpret_cast<CmapHeader*>(aFontData + uint32_t(dir->offset));
- CmapEncodingRecord *encRec =
- reinterpret_cast<CmapEncodingRecord*>(cmap + 1);
- int32_t symbolSubtable = -1;
- for (uint32_t i = 0; i < (uint16_t)cmap->numTables; ++i) {
- if (uint16_t(encRec[i].platformID) !=
- gfxFontUtils::PLATFORM_ID_MICROSOFT) {
- continue; // only interested in MS platform
- }
- if (uint16_t(encRec[i].encodingID) ==
- gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP) {
- // We've got a Microsoft/Unicode table, so don't interfere.
- symbolSubtable = -1;
- break;
- }
- if (uint16_t(encRec[i].encodingID) ==
- gfxFontUtils::ENCODING_ID_MICROSOFT_SYMBOL) {
- // Found a symbol subtable; remember it for possible fixup,
- // but if we subsequently find a Microsoft/Unicode subtable,
- // we'll cancel this.
- symbolSubtable = i;
- }
- }
- if (symbolSubtable != -1) {
- // We found a windows/symbol cmap table, and no windows/unicode one;
- // change the encoding ID so that AddFontMemResourceEx will accept it
- encRec[symbolSubtable].encodingID =
- gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP;
- return true;
- }
- }
- return false;
- }
- gfxFontEntry*
- gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
- uint16_t aWeight,
- int16_t aStretch,
- uint8_t aStyle,
- const uint8_t* aFontData,
- uint32_t aLength)
- {
- // MakePlatformFont is responsible for deleting the font data with free
- // so we set up a stack object to ensure it is freed even if we take an
- // early exit
- struct FontDataDeleter {
- FontDataDeleter(const uint8_t* aFontData)
- : mFontData(aFontData) { }
- ~FontDataDeleter() { free((void*)mFontData); }
- const uint8_t *mFontData;
- };
- FontDataDeleter autoDelete(aFontData);
- bool isCFF = gfxFontUtils::IsCffFont(aFontData);
- nsresult rv;
- HANDLE fontRef = nullptr;
- nsAutoString uniqueName;
- rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
- if (NS_FAILED(rv))
- return nullptr;
- FallibleTArray<uint8_t> newFontData;
- rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
- if (NS_FAILED(rv))
- return nullptr;
-
- DWORD numFonts = 0;
- uint8_t *fontData = reinterpret_cast<uint8_t*> (newFontData.Elements());
- uint32_t fontLength = newFontData.Length();
- NS_ASSERTION(fontData, "null font data after renaming");
- // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
- // "A font that is added by AddFontMemResourceEx is always private
- // to the process that made the call and is not enumerable."
- fontRef = AddFontMemResourceEx(fontData, fontLength,
- 0 /* reserved */, &numFonts);
- if (!fontRef) {
- if (FixupSymbolEncodedFont(fontData, fontLength)) {
- fontRef = AddFontMemResourceEx(fontData, fontLength, 0, &numFonts);
- }
- }
- if (!fontRef) {
- return nullptr;
- }
- // only load fonts with a single face contained in the data
- // AddFontMemResourceEx generates an additional face name for
- // vertical text if the font supports vertical writing but since
- // the font is referenced via the name this can be ignored
- if (fontRef && numFonts > 2) {
- RemoveFontMemResourceEx(fontRef);
- return nullptr;
- }
- // make a new font entry using the unique name
- WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
- uint16_t w = (aWeight == 0 ? 400 : aWeight);
- GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName,
- gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
- aStyle, w, aStretch, winUserFontData, false);
- if (fe) {
- fe->mIsDataUserFont = true;
- }
- return fe;
- }
- bool
- gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily,
- nsTArray<gfxFontFamily*>* aOutput,
- gfxFontStyle* aStyle,
- gfxFloat aDevToCssSize)
- {
- nsAutoString keyName(aFamily);
- BuildKeyNameFromFontName(keyName);
- gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
- if (ff) {
- aOutput->AppendElement(ff);
- return true;
- }
- if (mNonExistingFonts.Contains(keyName)) {
- return false;
- }
- return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aStyle,
- aDevToCssSize);
- }
- gfxFontFamily*
- gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
- {
- gfxFontFamily *ff = nullptr;
- // this really shouldn't fail to find a font....
- NONCLIENTMETRICSW ncm;
- ncm.cbSize = sizeof(ncm);
- BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
- sizeof(ncm), &ncm, 0);
- if (status) {
- ff = FindFamily(nsDependentString(ncm.lfMessageFont.lfFaceName));
- if (ff) {
- return ff;
- }
- }
- // ...but just in case, try another (long-deprecated) approach as well
- HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
- LOGFONTW logFont;
- if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
- ff = FindFamily(nsDependentString(logFont.lfFaceName));
- }
- return ff;
- }
- void
- gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
- FontListSizes* aSizes) const
- {
- gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
- aSizes->mFontListSize +=
- SizeOfFontFamilyTableExcludingThis(mFontSubstitutes, aMallocSizeOf);
- aSizes->mFontListSize +=
- mNonExistingFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
- for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
- aSizes->mFontListSize +=
- mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
- }
- }
- void
- gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
- FontListSizes* aSizes) const
- {
- aSizes->mFontListSize += aMallocSizeOf(this);
- AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
- }
- // used to load system-wide font info on off-main thread
- class GDIFontInfo : public FontInfoData {
- public:
- GDIFontInfo(bool aLoadOtherNames,
- bool aLoadFaceNames,
- bool aLoadCmaps) :
- FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
- {}
- virtual ~GDIFontInfo() {}
- virtual void Load() {
- mHdc = GetDC(nullptr);
- SetGraphicsMode(mHdc, GM_ADVANCED);
- FontInfoData::Load();
- ReleaseDC(nullptr, mHdc);
- }
- // loads font data for all members of a given family
- virtual void LoadFontFamilyData(const nsAString& aFamilyName);
- // callback for GDI EnumFontFamiliesExW call
- static int CALLBACK EnumerateFontsForFamily(const ENUMLOGFONTEXW *lpelfe,
- const NEWTEXTMETRICEXW *nmetrics,
- DWORD fontType, LPARAM data);
- HDC mHdc;
- };
- struct EnumerateFontsForFamilyData {
- EnumerateFontsForFamilyData(const nsAString& aFamilyName,
- GDIFontInfo& aFontInfo)
- : mFamilyName(aFamilyName), mFontInfo(aFontInfo)
- {}
- nsString mFamilyName;
- nsTArray<nsString> mOtherFamilyNames;
- GDIFontInfo& mFontInfo;
- nsString mPreviousFontName;
- };
- int CALLBACK GDIFontInfo::EnumerateFontsForFamily(
- const ENUMLOGFONTEXW *lpelfe,
- const NEWTEXTMETRICEXW *nmetrics,
- DWORD fontType, LPARAM data)
- {
- EnumerateFontsForFamilyData *famData =
- reinterpret_cast<EnumerateFontsForFamilyData*>(data);
- HDC hdc = famData->mFontInfo.mHdc;
- LOGFONTW logFont = lpelfe->elfLogFont;
- const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
- AutoSelectFont font(hdc, &logFont);
- if (!font.IsValid()) {
- return 1;
- }
- FontFaceData fontData;
- nsDependentString fontName(lpelfe->elfFullName);
- // callback called for each style-charset so return if style already seen
- if (fontName.Equals(famData->mPreviousFontName)) {
- return 1;
- }
- famData->mPreviousFontName = fontName;
- famData->mFontInfo.mLoadStats.fonts++;
- // read name table info
- bool nameDataLoaded = false;
- if (famData->mFontInfo.mLoadFaceNames || famData->mFontInfo.mLoadOtherNames) {
- uint32_t kNAME =
- NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e'));
- uint32_t nameSize;
- AutoTArray<uint8_t, 1024> nameData;
- nameSize = ::GetFontData(hdc, kNAME, 0, nullptr, 0);
- if (nameSize != GDI_ERROR &&
- nameSize > 0 &&
- nameData.SetLength(nameSize, fallible)) {
- ::GetFontData(hdc, kNAME, 0, nameData.Elements(), nameSize);
- // face names
- if (famData->mFontInfo.mLoadFaceNames) {
- gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize,
- gfxFontUtils::NAME_ID_FULL,
- fontData.mFullName);
- gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize,
- gfxFontUtils::NAME_ID_POSTSCRIPT,
- fontData.mPostscriptName);
- nameDataLoaded = true;
- famData->mFontInfo.mLoadStats.facenames++;
- }
- // other family names
- if (famData->mFontInfo.mLoadOtherNames) {
- gfxFontFamily::ReadOtherFamilyNamesForFace(famData->mFamilyName,
- (const char*)(nameData.Elements()),
- nameSize,
- famData->mOtherFamilyNames,
- false);
- }
- }
- }
- // read cmap
- bool cmapLoaded = false;
- gfxWindowsFontType feType =
- GDIFontEntry::DetermineFontType(metrics, fontType);
- if (famData->mFontInfo.mLoadCmaps &&
- (feType == GFX_FONT_TYPE_PS_OPENTYPE ||
- feType == GFX_FONT_TYPE_TT_OPENTYPE ||
- feType == GFX_FONT_TYPE_TRUETYPE))
- {
- uint32_t kCMAP =
- NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p'));
- uint32_t cmapSize;
- AutoTArray<uint8_t, 1024> cmapData;
- cmapSize = ::GetFontData(hdc, kCMAP, 0, nullptr, 0);
- if (cmapSize != GDI_ERROR &&
- cmapSize > 0 &&
- cmapData.SetLength(cmapSize, fallible)) {
- ::GetFontData(hdc, kCMAP, 0, cmapData.Elements(), cmapSize);
- bool cmapLoaded = false;
- bool unicodeFont = false, symbolFont = false;
- RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
- uint32_t offset;
- if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData.Elements(),
- cmapSize, *charmap,
- offset, unicodeFont,
- symbolFont))) {
- fontData.mCharacterMap = charmap;
- fontData.mUVSOffset = offset;
- fontData.mSymbolFont = symbolFont;
- cmapLoaded = true;
- famData->mFontInfo.mLoadStats.cmaps++;
- }
- }
- }
- if (cmapLoaded || nameDataLoaded) {
- famData->mFontInfo.mFontFaceData.Put(fontName, fontData);
- }
- return famData->mFontInfo.mCanceled ? 0 : 1;
- }
- void
- GDIFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
- {
- // iterate over the family
- LOGFONTW logFont;
- memset(&logFont, 0, sizeof(LOGFONTW));
- logFont.lfCharSet = DEFAULT_CHARSET;
- logFont.lfPitchAndFamily = 0;
- uint32_t l = std::min<uint32_t>(aFamilyName.Length(), LF_FACESIZE - 1);
- memcpy(logFont.lfFaceName, aFamilyName.BeginReading(), l * sizeof(char16_t));
- EnumerateFontsForFamilyData data(aFamilyName, *this);
- EnumFontFamiliesExW(mHdc, &logFont,
- (FONTENUMPROCW)GDIFontInfo::EnumerateFontsForFamily,
- (LPARAM)(&data), 0);
- // if found other names, insert them
- if (data.mOtherFamilyNames.Length() != 0) {
- mOtherFamilyNames.Put(aFamilyName, data.mOtherFamilyNames);
- mLoadStats.othernames += data.mOtherFamilyNames.Length();
- }
- }
- already_AddRefed<FontInfoData>
- gfxGDIFontList::CreateFontInfoData()
- {
- bool loadCmaps = !UsesSystemFallback() ||
- gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
- RefPtr<GDIFontInfo> fi =
- new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);
- return fi.forget();
- }
- #ifdef MOZ_BUNDLED_FONTS
- void
- gfxGDIFontList::ActivateBundledFonts()
- {
- nsCOMPtr<nsIFile> localDir;
- nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
- if (NS_FAILED(rv)) {
- return;
- }
- if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
- return;
- }
- bool isDir;
- if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
- return;
- }
- nsCOMPtr<nsISimpleEnumerator> e;
- rv = localDir->GetDirectoryEntries(getter_AddRefs(e));
- if (NS_FAILED(rv)) {
- return;
- }
- bool hasMore;
- while (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr<nsISupports> entry;
- if (NS_FAILED(e->GetNext(getter_AddRefs(entry)))) {
- break;
- }
- nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
- if (!file) {
- continue;
- }
- nsAutoString path;
- if (NS_FAILED(file->GetPath(path))) {
- continue;
- }
- AddFontResourceExW(path.get(), FR_PRIVATE, nullptr);
- }
- }
- #endif
|