bug 998844 - part 5 - support bundled fonts on Windows/DWrite. r=bas

This commit is contained in:
Jonathan Kew 2014-05-29 13:01:07 +01:00
parent 159d4f0a93
commit edceb13745
2 changed files with 324 additions and 111 deletions

View File

@ -18,6 +18,10 @@
#include "nsCharSeparatedTokenizer.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include "gfxGDIFontList.h"
@ -957,11 +961,11 @@ gfxDWriteFontList::DelayedInitFontList()
QueryPerformanceCounter(&t1);
HRESULT hr;
nsRefPtr<IDWriteFactory> factory =
gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
LOGREGISTRY(L"calling GetSystemFontCollection");
nsRefPtr<IDWriteFontCollection> systemFonts;
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
GetSystemFontCollection(getter_AddRefs(systemFonts));
hr = factory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
LOGREGISTRY(L"GetSystemFontCollection done");
@ -971,106 +975,14 @@ gfxDWriteFontList::DelayedInitFontList()
QueryPerformanceCounter(&t2);
for (UINT32 i = 0; i < systemFonts->GetFontFamilyCount(); i++) {
nsRefPtr<IDWriteFontFamily> family;
systemFonts->GetFontFamily(i, getter_AddRefs(family));
GetFontsFromCollection(mSystemFonts);
nsRefPtr<IDWriteLocalizedStrings> names;
hr = family->GetFamilyNames(getter_AddRefs(names));
if (FAILED(hr)) {
continue;
}
UINT32 englishIdx = 0;
BOOL exists;
hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
if (FAILED(hr)) {
continue;
}
if (!exists) {
// Use 0 index if english is not found.
englishIdx = 0;
}
AutoFallibleTArray<WCHAR, 32> enName;
UINT32 length;
hr = names->GetStringLength(englishIdx, &length);
if (FAILED(hr)) {
continue;
}
if (!enName.SetLength(length + 1)) {
// Eeep - running out of memory. Unlikely to end well.
continue;
}
hr = names->GetString(englishIdx, enName.Elements(), length + 1);
if (FAILED(hr)) {
continue;
}
nsAutoString name(enName.Elements());
BuildKeyNameFromFontName(name);
nsRefPtr<gfxFontFamily> fam;
if (mFontFamilies.GetWeak(name)) {
continue;
}
nsDependentString familyName(enName.Elements());
fam = new gfxDWriteFontFamily(familyName, family);
if (!fam) {
continue;
}
if (mBadUnderlineFamilyNames.Contains(name)) {
fam->SetBadUnderlineFamily();
}
mFontFamilies.Put(name, fam);
// now add other family name localizations, if present
uint32_t nameCount = names->GetCount();
uint32_t nameIndex;
for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
UINT32 nameLen;
AutoFallibleTArray<WCHAR, 32> localizedName;
// only add other names
if (nameIndex == englishIdx) {
continue;
}
hr = names->GetStringLength(nameIndex, &nameLen);
if (FAILED(hr)) {
continue;
}
if (!localizedName.SetLength(nameLen + 1)) {
continue;
}
hr = names->GetString(nameIndex, localizedName.Elements(),
nameLen + 1);
if (FAILED(hr)) {
continue;
}
nsDependentString locName(localizedName.Elements());
if (!familyName.Equals(locName)) {
AddOtherFamilyName(fam, locName);
}
}
// at this point, all family names have been read in
fam->SetOtherFamilyNamesInitialized();
#ifdef MOZ_BUNDLED_FONTS
mBundledFonts = CreateBundledFontsCollection(factory);
if (mBundledFonts) {
GetFontsFromCollection(mBundledFonts);
}
#endif
mOtherFamilyNamesInitialized = true;
GetFontSubstitutes();
@ -1172,11 +1084,11 @@ gfxDWriteFontList::DelayedInitFontList()
elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL, elapsedTime);
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT,
systemFonts->GetFontFamilyCount());
mSystemFonts->GetFontFamilyCount());
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_GDI_TABLE, mGDIFontTableAccess);
LOG_FONTINIT((
"Total time in DelayedInitFontList: %9.3f ms (families: %d, %s)\n",
elapsedTime, systemFonts->GetFontFamilyCount(),
elapsedTime, mSystemFonts->GetFontFamilyCount(),
(mGDIFontTableAccess ? "gdi table access" : "dwrite table access")));
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
@ -1190,6 +1102,111 @@ gfxDWriteFontList::DelayedInitFontList()
return NS_OK;
}
void
gfxDWriteFontList::GetFontsFromCollection(IDWriteFontCollection* aCollection)
{
for (UINT32 i = 0; i < aCollection->GetFontFamilyCount(); i++) {
nsRefPtr<IDWriteFontFamily> family;
aCollection->GetFontFamily(i, getter_AddRefs(family));
nsRefPtr<IDWriteLocalizedStrings> names;
HRESULT hr = family->GetFamilyNames(getter_AddRefs(names));
if (FAILED(hr)) {
continue;
}
UINT32 englishIdx = 0;
BOOL exists;
hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
if (FAILED(hr)) {
continue;
}
if (!exists) {
// Use 0 index if english is not found.
englishIdx = 0;
}
AutoFallibleTArray<WCHAR, 32> enName;
UINT32 length;
hr = names->GetStringLength(englishIdx, &length);
if (FAILED(hr)) {
continue;
}
if (!enName.SetLength(length + 1)) {
// Eeep - running out of memory. Unlikely to end well.
continue;
}
hr = names->GetString(englishIdx, enName.Elements(), length + 1);
if (FAILED(hr)) {
continue;
}
nsAutoString name(enName.Elements());
BuildKeyNameFromFontName(name);
nsRefPtr<gfxFontFamily> fam;
if (mFontFamilies.GetWeak(name)) {
continue;
}
nsDependentString familyName(enName.Elements());
fam = new gfxDWriteFontFamily(familyName, family);
if (!fam) {
continue;
}
if (mBadUnderlineFamilyNames.Contains(name)) {
fam->SetBadUnderlineFamily();
}
mFontFamilies.Put(name, fam);
// now add other family name localizations, if present
uint32_t nameCount = names->GetCount();
uint32_t nameIndex;
for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
UINT32 nameLen;
AutoFallibleTArray<WCHAR, 32> localizedName;
// only add other names
if (nameIndex == englishIdx) {
continue;
}
hr = names->GetStringLength(nameIndex, &nameLen);
if (FAILED(hr)) {
continue;
}
if (!localizedName.SetLength(nameLen + 1)) {
continue;
}
hr = names->GetString(nameIndex, localizedName.Elements(),
nameLen + 1);
if (FAILED(hr)) {
continue;
}
nsDependentString locName(localizedName.Elements());
if (!familyName.Equals(locName)) {
AddOtherFamilyName(fam, locName);
}
}
// at this point, all family names have been read in
fam->SetOtherFamilyNamesInitialized();
}
}
static void
RemoveCharsetFromFontSubstitute(nsAString &aName)
{
@ -1561,8 +1578,17 @@ class DirectWriteFontInfo : public FontInfoData {
public:
DirectWriteFontInfo(bool aLoadOtherNames,
bool aLoadFaceNames,
bool aLoadCmaps) :
bool aLoadCmaps,
IDWriteFontCollection* aSystemFonts
#ifdef MOZ_BUNDLED_FONTS
, IDWriteFontCollection* aBundledFonts
#endif
) :
FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
, mSystemFonts(aSystemFonts)
#ifdef MOZ_BUNDLED_FONTS
, mBundledFonts(aBundledFonts)
#endif
{}
virtual ~DirectWriteFontInfo() {}
@ -1570,7 +1596,11 @@ public:
// loads font data for all members of a given family
virtual void LoadFontFamilyData(const nsAString& aFamilyName);
private:
nsRefPtr<IDWriteFontCollection> mSystemFonts;
#ifdef MOZ_BUNDLED_FONTS
nsRefPtr<IDWriteFontCollection> mBundledFonts;
#endif
};
void
@ -1588,13 +1618,24 @@ DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
BOOL exists = false;
uint32_t index;
nsRefPtr<IDWriteFontFamily> family;
hr = mSystemFonts->FindFamilyName(famName.Elements(), &index, &exists);
if (FAILED(hr) || !exists) {
return;
if (SUCCEEDED(hr) && exists) {
mSystemFonts->GetFontFamily(index, getter_AddRefs(family));
if (!family) {
return;
}
}
nsRefPtr<IDWriteFontFamily> family;
mSystemFonts->GetFontFamily(index, getter_AddRefs(family));
#ifdef MOZ_BUNDLED_FONTS
if (!family && mBundledFonts) {
hr = mBundledFonts->FindFamilyName(famName.Elements(), &index, &exists);
if (SUCCEEDED(hr) && exists) {
mBundledFonts->GetFontFamily(index, getter_AddRefs(family));
}
}
#endif
if (!family) {
return;
}
@ -1735,9 +1776,169 @@ gfxDWriteFontList::CreateFontInfoData()
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
nsRefPtr<DirectWriteFontInfo> fi =
new DirectWriteFontInfo(false, NeedFullnamePostscriptNames(), loadCmaps);
gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
GetSystemFontCollection(getter_AddRefs(fi->mSystemFonts));
new DirectWriteFontInfo(false, NeedFullnamePostscriptNames(), loadCmaps,
mSystemFonts
#ifdef MOZ_BUNDLED_FONTS
, mBundledFonts
#endif
);
return fi.forget();
}
#ifdef MOZ_BUNDLED_FONTS
#define IMPL_QI_FOR_DWRITE(_interface) \
public: \
IFACEMETHOD(QueryInterface) (IID const& riid, void** ppvObject) \
{ \
if (__uuidof(_interface) == riid) { \
*ppvObject = this; \
} else if (__uuidof(IUnknown) == riid) { \
*ppvObject = this; \
} else { \
*ppvObject = nullptr; \
return E_NOINTERFACE; \
} \
this->AddRef(); \
return S_OK; \
}
class BundledFontFileEnumerator
: public IDWriteFontFileEnumerator
{
IMPL_QI_FOR_DWRITE(IDWriteFontFileEnumerator)
NS_INLINE_DECL_REFCOUNTING(BundledFontFileEnumerator)
public:
BundledFontFileEnumerator(IDWriteFactory *aFactory,
nsIFile *aFontDir);
IFACEMETHODIMP MoveNext(BOOL * hasCurrentFile);
IFACEMETHODIMP GetCurrentFontFile(IDWriteFontFile ** fontFile);
private:
BundledFontFileEnumerator() MOZ_DELETE;
BundledFontFileEnumerator(const BundledFontFileEnumerator&) MOZ_DELETE;
BundledFontFileEnumerator& operator=(const BundledFontFileEnumerator&) MOZ_DELETE;
nsRefPtr<IDWriteFactory> mFactory;
nsCOMPtr<nsIFile> mFontDir;
nsCOMPtr<nsISimpleEnumerator> mEntries;
nsCOMPtr<nsISupports> mCurrent;
};
BundledFontFileEnumerator::BundledFontFileEnumerator(IDWriteFactory *aFactory,
nsIFile *aFontDir)
: mFactory(aFactory)
, mFontDir(aFontDir)
{
mFontDir->GetDirectoryEntries(getter_AddRefs(mEntries));
}
IFACEMETHODIMP
BundledFontFileEnumerator::MoveNext(BOOL * aHasCurrentFile)
{
bool hasMore = false;
if (mEntries) {
if (NS_SUCCEEDED(mEntries->HasMoreElements(&hasMore)) && hasMore) {
if (NS_SUCCEEDED(mEntries->GetNext(getter_AddRefs(mCurrent)))) {
hasMore = true;
}
}
}
*aHasCurrentFile = hasMore;
return S_OK;
}
IFACEMETHODIMP
BundledFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile ** aFontFile)
{
nsCOMPtr<nsIFile> file = do_QueryInterface(mCurrent);
if (!file) {
return E_FAIL;
}
nsString path;
if (NS_FAILED(file->GetPath(path))) {
return E_FAIL;
}
return mFactory->CreateFontFileReference((const WCHAR*)path.get(),
nullptr, aFontFile);
}
class BundledFontLoader
: public IDWriteFontCollectionLoader
{
IMPL_QI_FOR_DWRITE(IDWriteFontCollectionLoader)
NS_INLINE_DECL_REFCOUNTING(BundledFontLoader)
public:
BundledFontLoader()
{
}
IFACEMETHODIMP CreateEnumeratorFromKey(
IDWriteFactory *aFactory,
const void *aCollectionKey,
UINT32 aCollectionKeySize,
IDWriteFontFileEnumerator **aFontFileEnumerator);
private:
BundledFontLoader(const BundledFontLoader&) MOZ_DELETE;
BundledFontLoader& operator=(const BundledFontLoader&) MOZ_DELETE;
};
IFACEMETHODIMP
BundledFontLoader::CreateEnumeratorFromKey(
IDWriteFactory *aFactory,
const void *aCollectionKey,
UINT32 aCollectionKeySize,
IDWriteFontFileEnumerator **aFontFileEnumerator)
{
nsIFile *fontDir = *(nsIFile**)aCollectionKey;
*aFontFileEnumerator = new BundledFontFileEnumerator(aFactory, fontDir);
return S_OK;
}
already_AddRefed<IDWriteFontCollection>
gfxDWriteFontList::CreateBundledFontsCollection(IDWriteFactory* aFactory)
{
nsCOMPtr<nsIFile> localDir;
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
if (NS_FAILED(rv)) {
return nullptr;
}
if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
return nullptr;
}
bool isDir;
if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
return nullptr;
}
nsRefPtr<BundledFontLoader> loader = new BundledFontLoader();
if (FAILED(aFactory->RegisterFontCollectionLoader(loader))) {
return nullptr;
}
const void *key = localDir.get();
nsRefPtr<IDWriteFontCollection> collection;
HRESULT hr =
aFactory->CreateCustomFontCollection(loader, &key, sizeof(key),
getter_AddRefs(collection));
aFactory->UnregisterFontCollectionLoader(loader);
if (FAILED(hr)) {
return nullptr;
} else {
return collection.forget();
}
}
#endif

View File

@ -390,6 +390,13 @@ private:
virtual bool UsesSystemFallback() { return true; }
void GetFontsFromCollection(IDWriteFontCollection* aCollection);
#ifdef MOZ_BUNDLED_FONTS
already_AddRefed<IDWriteFontCollection>
CreateBundledFontsCollection(IDWriteFactory* aFactory);
#endif
/**
* Fonts listed in the registry as substitutes but for which no actual
* font family is found.
@ -417,6 +424,11 @@ private:
nsRefPtr<FontFallbackRenderer> mFallbackRenderer;
nsRefPtr<IDWriteTextFormat> mFallbackFormat;
nsRefPtr<IDWriteFontCollection> mSystemFonts;
#ifdef MOZ_BUNDLED_FONTS
nsRefPtr<IDWriteFontCollection> mBundledFonts;
#endif
};