bug 684889 - refactor and clean up Android font-list implementation. r=jdaggett

This commit is contained in:
Jonathan Kew 2011-09-23 09:53:13 +01:00
Родитель 51e7a7b124
Коммит 1d2932c2c0
8 изменённых файлов: 676 добавлений и 753 удалений

Просмотреть файл

@ -83,9 +83,13 @@ union StorageConstructData
};
struct FontListEntry {
nsCString familyName;
nsString familyName;
nsString faceName;
nsCString filepath;
PRUint32 index;
PRUint16 weight;
PRInt16 stretch;
PRUint8 italic;
PRUint8 index;
};
rpc protocol PContent

Просмотреть файл

@ -35,39 +35,16 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/dom/ContentChild.h"
#include "nsXULAppAPI.h"
#include <android/log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "gfxAndroidPlatform.h"
#include "cairo.h"
#include "cairo-ft.h"
#include "gfxFT2FontList.h"
#include "gfxImageSurface.h"
#include "nsUnicharUtils.h"
#include "nsMathUtils.h"
#include "nsTArray.h"
#include "qcms.h"
#include "cairo.h"
#include "ft2build.h"
#include FT_FREETYPE_H
#include "gfxFT2Fonts.h"
#include "gfxPlatformFontList.h"
#include "gfxFT2FontList.h"
#include "mozilla/scache/StartupCache.h"
#include "nsXPCOMStrings.h"
using namespace mozilla;
using namespace dom;
static FT_Library gPlatformFTLibrary = NULL;
@ -76,13 +53,6 @@ static FT_Library gPlatformFTLibrary = NULL;
gfxAndroidPlatform::gfxAndroidPlatform()
{
FT_Init_FreeType(&gPlatformFTLibrary);
mFonts.Init(200);
mFontAliases.Init(20);
mFontSubstitutes.Init(50);
mPrefFonts.Init(10);
UpdateFontList();
}
gfxAndroidPlatform::~gfxAndroidPlatform()
@ -106,420 +76,27 @@ gfxAndroidPlatform::CreateOffscreenSurface(const gfxIntSize& size,
return newSurface.forget();
}
struct FontListData {
FontListData(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
nsIAtom *mLangGroup;
const nsACString& mGenericFamily;
nsTArray<nsString>& mStringArray;
};
static PLDHashOperator
FontListHashEnumFunc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
FontListData *data = (FontListData*)userArg;
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.language = data->mLangGroup;
nsRefPtr<FontEntry> aFontEntry = aFontFamily->FindFontEntry(style);
NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
if (!aFontEntry)
return PL_DHASH_NEXT;
data->mStringArray.AppendElement(aFontFamily->Name());
return PL_DHASH_NEXT;
}
nsresult
gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts)
{
FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
mFonts.Enumerate(FontListHashEnumFunc, &data);
aListOfFonts.Sort();
aListOfFonts.Compact();
gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
aGenericFamily,
aListOfFonts);
return NS_OK;
}
class FontNameCache {
public:
typedef nsAutoTArray<PRUint32, 8> IndexList;
PLDHashTableOps ops;
FontNameCache() : mWriteNeeded(PR_FALSE) {
ops = (PLDHashTableOps) {
PL_DHashAllocTable,
PL_DHashFreeTable,
StringHash,
HashMatchEntry,
MoveEntry,
PL_DHashClearEntryStub,
PL_DHashFinalizeStub,
NULL};
if (!PL_DHashTableInit(&mMap, &ops, nsnull,
sizeof(FNCMapEntry), 0)) {
mMap.ops = nsnull;
LOG("initializing the map failed");
}
NS_ABORT_IF_FALSE(XRE_GetProcessType() == GeckoProcessType_Default,
"StartupCacheFontNameCache should only be used in chrome procsess");
mCache = mozilla::scache::StartupCache::GetSingleton();
Init();
}
void Init()
{
if (!mMap.ops || !mCache)
return;
nsCAutoString prefName("font.cache");
PRUint32 size;
char* buf;
if (NS_FAILED(mCache->GetBuffer(prefName.get(), &buf, &size)))
return;
LOG("got: %s from the cache", nsDependentCString(buf, size).get());
char* entry = strtok(buf, ";");
while (entry) {
nsCString faceList, filename, indexes;
PRUint32 timestamp, fileSize;
filename.Assign(entry);
entry = strtok(NULL, ";");
if (!entry)
break;
faceList.Assign(entry);
entry = strtok(NULL, ";");
if (!entry)
break;
char* endptr;
timestamp = strtoul(entry, &endptr, 10);
if (*endptr != '\0')
break;
entry = strtok(NULL, ";");
if (!entry)
break;
fileSize = strtoul(entry, &endptr, 10);
if (*endptr != '\0')
break;
entry = strtok(NULL, ";");
if (!entry)
break;
indexes.Assign(entry);
FNCMapEntry* mapEntry =
static_cast<FNCMapEntry*>
(PL_DHashTableOperate(&mMap, filename.get(), PL_DHASH_ADD));
if (mapEntry) {
mapEntry->mFilename = filename;
mapEntry->mTimestamp = timestamp;
mapEntry->mFilesize = fileSize;
mapEntry->mFaces.AssignWithConversion(faceList);
mapEntry->mIndexes = indexes;
}
entry = strtok(NULL, ";");
}
free(buf);
}
virtual void
GetInfoForFile(nsCString& aFileName, nsAString& aFaceList,
PRUint32 *aTimestamp, PRUint32 *aFileSize,
IndexList &aIndexList)
{
if (!mMap.ops)
return;
PLDHashEntryHdr *hdr = PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_LOOKUP);
if (!hdr)
return;
FNCMapEntry* entry = static_cast<FNCMapEntry*>(hdr);
if (entry && entry->mTimestamp && entry->mFilesize) {
*aTimestamp = entry->mTimestamp;
*aFileSize = entry->mFilesize;
char* indexes = const_cast<char*>(entry->mIndexes.get());
char* endptr = indexes + 1;
unsigned long index = strtoul(indexes, &endptr, 10);
while (indexes < endptr && indexes[0] != '\0') {
aIndexList.AppendElement(index);
indexes = endptr + 1;
}
aFaceList.Assign(entry->mFaces);
}
}
virtual void
CacheFileInfo(nsCString& aFileName, nsAString& aFaceList,
PRUint32 aTimestamp, PRUint32 aFileSize,
IndexList &aIndexList)
{
if (!mMap.ops)
return;
FNCMapEntry* entry =
static_cast<FNCMapEntry*>
(PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_ADD));
if (entry) {
entry->mFilename = aFileName;
entry->mTimestamp = aTimestamp;
entry->mFilesize = aFileSize;
entry->mFaces.Assign(aFaceList);
for (PRUint32 i = 0; i < aIndexList.Length(); i++) {
entry->mIndexes.AppendInt(aIndexList[i]);
entry->mIndexes.Append(",");
}
}
mWriteNeeded = PR_TRUE;
}
~FontNameCache() {
if (!mMap.ops)
return;
if (!mWriteNeeded || !mCache) {
PL_DHashTableFinish(&mMap);
return;
}
nsCAutoString buf;
PL_DHashTableEnumerate(&mMap, WriteOutMap, &buf);
PL_DHashTableFinish(&mMap);
nsCAutoString prefName("font.cache");
mCache->PutBuffer(prefName.get(), buf.get(), buf.Length() + 1);
}
private:
mozilla::scache::StartupCache* mCache;
PLDHashTable mMap;
PRBool mWriteNeeded;
static PLDHashOperator WriteOutMap(PLDHashTable *aTable,
PLDHashEntryHdr *aHdr,
PRUint32 aNumber, void *aData)
{
nsCAutoString* buf = (nsCAutoString*)aData;
FNCMapEntry* entry = static_cast<FNCMapEntry*>(aHdr);
buf->Append(entry->mFilename);
buf->Append(";");
buf->AppendWithConversion(entry->mFaces);
buf->Append(";");
buf->AppendInt(entry->mTimestamp);
buf->Append(";");
buf->AppendInt(entry->mFilesize);
buf->Append(";");
buf->Append(entry->mIndexes);
buf->Append(";");
return PL_DHASH_NEXT;
}
typedef struct : public PLDHashEntryHdr {
public:
nsCString mFilename;
PRUint32 mTimestamp;
PRUint32 mFilesize;
nsString mFaces;
nsCString mIndexes;
} FNCMapEntry;
static PLDHashNumber StringHash(PLDHashTable *table, const void *key) {
PLDHashNumber h = 0;
for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
h = PR_ROTATE_LEFT32(h, 4) ^ NS_ToLower(*s);
return h;
}
static PRBool HashMatchEntry(PLDHashTable *table,
const PLDHashEntryHdr *aHdr, const void *key)
{
const FNCMapEntry* entry =
static_cast<const FNCMapEntry*>(aHdr);
return entry->mFilename.Equals((char*)key);
}
static void MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *aFrom,
PLDHashEntryHdr *aTo)
{
FNCMapEntry* to =
static_cast<FNCMapEntry*>(aTo);
const FNCMapEntry* from =
static_cast<const FNCMapEntry*>(aFrom);
to->mFilename.Assign(from->mFilename);
to->mTimestamp = from->mTimestamp;
to->mFilesize = from->mFilesize;
to->mFaces.Assign(from->mFaces);
to->mIndexes.Assign(from->mIndexes);
}
};
void
gfxAndroidPlatform::AppendFacesFromFontFile(const char *aFileName, FontNameCache* aFontCache, InfallibleTArray<FontListEntry>* aFontList)
{
nsString faceList;
PRUint32 timestamp = 0;
PRUint32 filesize = 0;
FontNameCache::IndexList indexList;
nsCString fileName(aFileName);
if (aFontCache)
aFontCache->GetInfoForFile(fileName, faceList, &timestamp, &filesize, indexList);
struct stat s;
int stat_ret = stat(aFileName, &s);
if (!faceList.IsEmpty() && indexList.Length() && 0 == stat_ret &&
s.st_mtime == timestamp && s.st_size == filesize) {
PRInt32 beginning = 0;
PRInt32 end = faceList.Find(",", PR_TRUE, beginning, -1);
for (PRUint32 i = 0; i < indexList.Length() && end != kNotFound; i++) {
nsDependentSubstring name(faceList, beginning, end);
ToLowerCase(name);
FontListEntry fle(NS_ConvertUTF16toUTF8(name), fileName,
indexList[i]);
aFontList->AppendElement(fle);
beginning = end + 1;
end = faceList.Find(",", PR_TRUE, beginning, -1);
}
return;
}
faceList.AssignLiteral("");
timestamp = s.st_mtime;
filesize = s.st_size;
FT_Face dummy;
if (FT_Err_Ok == FT_New_Face(GetFTLibrary(), aFileName, -1, &dummy)) {
for (FT_Long i = 0; i < dummy->num_faces; i++) {
FT_Face face;
if (FT_Err_Ok != FT_New_Face(GetFTLibrary(), aFileName,
i, &face))
continue;
nsDependentCString name(face->family_name);
ToLowerCase(name);
nsRefPtr<FontFamily> ff;
faceList.AppendWithConversion(name);
faceList.AppendLiteral(",");
indexList.AppendElement(i);
ToLowerCase(name);
FontListEntry fle(name, fileName, i);
aFontList->AppendElement(fle);
}
FT_Done_Face(dummy);
if (aFontCache && 0 == stat_ret)
aFontCache->CacheFileInfo(fileName, faceList, timestamp, filesize, indexList);
}
}
void
gfxAndroidPlatform::FindFontsInDirectory(const nsCString& aFontsDir,
FontNameCache* aFontCache)
{
static const char* sStandardFonts[] = {
"DroidSans.ttf",
"DroidSans-Bold.ttf",
"DroidSerif-Regular.ttf",
"DroidSerif-Bold.ttf",
"DroidSerif-Italic.ttf",
"DroidSerif-BoldItalic.ttf",
"DroidSansMono.ttf",
"DroidSansArabic.ttf",
"DroidSansHebrew.ttf",
"DroidSansThai.ttf",
"MTLmr3m.ttf",
"MTLc3m.ttf",
"DroidSansJapanese.ttf",
"DroidSansFallback.ttf"
};
DIR *d = opendir(aFontsDir.get());
struct dirent *ent = NULL;
while(d && (ent = readdir(d)) != NULL) {
int namelen = strlen(ent->d_name);
if (namelen > 4 &&
strcasecmp(ent->d_name + namelen - 4, ".ttf") == 0)
{
bool isStdFont = false;
for (unsigned int i = 0; i < NS_ARRAY_LENGTH(sStandardFonts) && !isStdFont; i++) {
isStdFont = strcmp(sStandardFonts[i], ent->d_name) == 0;
}
if (!isStdFont) {
nsCString s(aFontsDir);
s.Append(nsDependentCString(ent->d_name));
AppendFacesFromFontFile(s.get(), aFontCache, &mFontList);
}
}
}
closedir(d);
for (unsigned int i = 0; i < NS_ARRAY_LENGTH(sStandardFonts); i++) {
nsCString s(aFontsDir);
s.Append(nsDependentCString(sStandardFonts[i]));
AppendFacesFromFontFile(s.get(), aFontCache, &mFontList);
}
}
void
gfxAndroidPlatform::GetFontList(InfallibleTArray<FontListEntry>* retValue)
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
mozilla::dom::ContentChild::GetSingleton()->SendReadFontList(retValue);
return;
}
if (mFontList.Length() > 0) {
*retValue = mFontList;
return;
}
// ANDROID_ROOT is the root of the android system, typically /system
// font files are in /$ANDROID_ROOT/fonts/
FontNameCache fnc;
FindFontsInDirectory(NS_LITERAL_CSTRING("/system/fonts/"), &fnc);
char *androidRoot = PR_GetEnv("ANDROID_ROOT");
if (androidRoot && strcmp(androidRoot, "/system")) {
nsCString root(androidRoot);
root.Append("/fonts/");
FindFontsInDirectory(root, &fnc);
}
*retValue = mFontList;
gfxFT2FontList::PlatformFontList()->GetFontList(retValue);
}
nsresult
gfxAndroidPlatform::UpdateFontList()
{
gfxFontCache *fc = gfxFontCache::GetCache();
if (fc)
fc->AgeAllGenerations();
mFonts.Clear();
mFontAliases.Clear();
mFontSubstitutes.Clear();
mPrefFonts.Clear();
mCodepointsWithNoFonts.reset();
InfallibleTArray<FontListEntry> fontList;
GetFontList(&fontList);
for (PRUint32 i = 0; i < fontList.Length(); i++) {
NS_ConvertUTF8toUTF16 name(fontList[i].familyName());
nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff)) {
ff = new FontFamily(name);
mFonts.Put(name, ff);
}
ff->AddFontFileAndIndex(fontList[i].filepath(), fontList[i].index());
}
// initialize the cmap loading process after font list has been initialized
//StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
// initialize ranges of characters for which system-wide font search should be skipped
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
return NS_OK;
}
@ -529,47 +106,21 @@ gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName,
void *aClosure,
PRBool& aAborted)
{
if (aFontName.IsEmpty())
return NS_ERROR_FAILURE;
nsAutoString resolvedName;
gfxPlatformFontList* platformFontList = gfxPlatformFontList::PlatformFontList();
if (platformFontList) {
if (!platformFontList->ResolveFontName(aFontName, resolvedName)) {
aAborted = PR_FALSE;
return NS_OK;
}
}
nsAutoString keyName(aFontName);
ToLowerCase(keyName);
nsRefPtr<FontFamily> ff;
if (mFonts.Get(keyName, &ff) ||
mFontSubstitutes.Get(keyName, &ff) ||
mFontAliases.Get(keyName, &ff))
{
aAborted = !(*aCallback)(ff->Name(), aClosure);
} else {
if (!gfxPlatformFontList::PlatformFontList()->
ResolveFontName(aFontName, resolvedName)) {
aAborted = PR_FALSE;
return NS_OK;
}
aAborted = !(*aCallback)(resolvedName, aClosure);
return NS_OK;
}
static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
{
nsString *result = static_cast<nsString*>(aClosure);
result->Assign(aName);
return PR_FALSE;
}
nsresult
gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
aFamilyName.Truncate();
PRBool aborted;
return ResolveFontName(aFontName, SimpleResolverCallback, &aFamilyName, aborted);
gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
return NS_OK;
}
gfxPlatformFontList*
@ -611,7 +162,7 @@ gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle,
gfxUserFontSet* aUserFontSet)
{
return new gfxFT2FontGroup(aFamilies, aStyle, aUserFontSet);
return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
}
FT_Library
@ -620,68 +171,6 @@ gfxAndroidPlatform::GetFTLibrary()
return gPlatformFTLibrary;
}
FontFamily *
gfxAndroidPlatform::FindFontFamily(const nsAString& aName)
{
nsAutoString name(aName);
ToLowerCase(name);
nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff) &&
!mFontSubstitutes.Get(name, &ff) &&
!mFontAliases.Get(name, &ff)) {
return nsnull;
}
return ff.get();
}
FontEntry *
gfxAndroidPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
{
nsRefPtr<FontFamily> ff = FindFontFamily(aName);
if (!ff)
return nsnull;
return ff->FindFontEntry(aFontStyle);
}
static PLDHashOperator
FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* aUserArg)
{
FontSearch *data = (FontSearch*)aUserArg;
aFontFamily->FindFontForChar(data);
return PL_DHASH_NEXT;
}
already_AddRefed<gfxFont>
gfxAndroidPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
{
// is codepoint with no matching font? return null immediately
if (mCodepointsWithNoFonts.test(aCh)) {
return nsnull;
}
FontSearch data(aCh, aFont);
// find fonts that support the character
mFonts.Enumerate(FindFontForCharProc, &data);
if (data.mBestMatch) {
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle());
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
}
// no match? add to set of non-matching codepoints
mCodepointsWithNoFonts.set(aCh);
return nsnull;
}
gfxFontEntry*
gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength)
@ -691,14 +180,3 @@ gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
aLength);
}
PRBool
gfxAndroidPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList)
{
return mPrefFonts.Get(aKey, aFontEntryList);
}
void
gfxAndroidPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList)
{
mPrefFonts.Put(aKey, aFontEntryList);
}

Просмотреть файл

@ -39,27 +39,13 @@
#ifndef GFX_PLATFORM_ANDROID_H
#define GFX_PLATFORM_ANDROID_H
#include "gfxFontUtils.h"
#include "gfxFT2Fonts.h"
#include "gfxPlatform.h"
#include "nsDataHashtable.h"
#include "gfxUserFontSet.h"
#include "nsTArray.h"
typedef struct FT_LibraryRec_ *FT_Library;
class FontFamily;
class FontEntry;
namespace mozilla {
namespace dom {
class FontListEntry;
};
};
using namespace mozilla;
using namespace dom;
class FontNameCache;
class THEBES_API gfxAndroidPlatform : public gfxPlatform {
public:
gfxAndroidPlatform();
@ -69,57 +55,39 @@ public:
return (gfxAndroidPlatform*) gfxPlatform::GetPlatform();
}
void GetFontList(InfallibleTArray<FontListEntry>* retValue);
already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxContentType contentType);
virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
virtual gfxPlatformFontList* CreatePlatformFontList();
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength);
nsresult GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts);
nsresult UpdateFontList();
nsresult ResolveFontName(const nsAString& aFontName,
FontResolverCallback aCallback,
void *aClosure, PRBool& aAborted);
nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle,
gfxUserFontSet* aUserFontSet);
FontFamily *FindFontFamily(const nsAString& aName);
FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle);
already_AddRefed<gfxFont> FindFontForChar(PRUint32 aCh, gfxFont *aFont);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
FT_Library GetFTLibrary();
virtual already_AddRefed<gfxASurface>
CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxContentType contentType);
virtual gfxImageFormat GetOffscreenFormat() { return gfxASurface::ImageFormatRGB16_565; }
protected:
void AppendFacesFromFontFile(const char *aFileName, FontNameCache* aFontCache, InfallibleTArray<FontListEntry>* retValue);
void FindFontsInDirectory(const nsCString& aFontsDir, FontNameCache* aFontCache);
// to support IPC font list (sharing between chrome and content)
void GetFontList(InfallibleTArray<FontListEntry>* retValue);
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
// platform implementations of font functions
virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
virtual gfxPlatformFontList* CreatePlatformFontList();
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength);
FontTable mFonts;
FontTable mFontAliases;
FontTable mFontSubstitutes;
InfallibleTArray<FontListEntry> mFontList;
virtual nsresult GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts);
// when system-wide font lookup fails for a character, cache it to skip future searches
gfxSparseBitSet mCodepointsWithNoFonts;
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
virtual nsresult UpdateFontList();
virtual nsresult ResolveFontName(const nsAString& aFontName,
FontResolverCallback aCallback,
void *aClosure, PRBool& aAborted);
virtual nsresult GetStandardFamilyName(const nsAString& aFontName,
nsAString& aFamilyName);
virtual gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle,
gfxUserFontSet* aUserFontSet);
FT_Library GetFTLibrary();
};
#endif /* GFX_PLATFORM_ANDROID_H */

Просмотреть файл

@ -39,6 +39,16 @@
*
* ***** END LICENSE BLOCK ***** */
#ifdef ANDROID
#include "mozilla/dom/ContentChild.h"
#include "nsXULAppAPI.h"
#include "gfxAndroidPlatform.h"
#include <dirent.h>
#include <android/log.h>
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
#endif
#include "gfxFT2FontList.h"
#include "gfxUserFontSet.h"
#include "gfxFontUtils.h"
@ -56,24 +66,18 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/scache/StartupCache.h"
#include <sys/stat.h>
#ifdef XP_WIN
#include "nsIWindowsRegKey.h"
#include <windows.h>
#endif
#define ROUND(x) floor((x) + 0.5)
#ifdef PR_LOGGING
static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
#endif /* PR_LOGGING */
#ifdef ANDROID
#include "gfxAndroidPlatform.h"
#include <dirent.h>
#include <android/log.h>
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
#endif
#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
@ -87,49 +91,338 @@ BuildKeyNameFromFontName(nsAString &aName)
ToLowerCase(aName);
}
#define CACHE_KEY "font.cached-list"
class FontNameCache {
public:
FontNameCache()
: mWriteNeeded(PR_FALSE)
{
mOps = (PLDHashTableOps) {
PL_DHashAllocTable,
PL_DHashFreeTable,
StringHash,
HashMatchEntry,
MoveEntry,
PL_DHashClearEntryStub,
PL_DHashFinalizeStub,
NULL
};
if (!PL_DHashTableInit(&mMap, &mOps, nsnull,
sizeof(FNCMapEntry), 0))
{
mMap.ops = nsnull;
LOG(("initializing the map failed"));
}
NS_ABORT_IF_FALSE(XRE_GetProcessType() == GeckoProcessType_Default,
"StartupCacheFontNameCache should only be used in chrome process");
mCache = mozilla::scache::StartupCache::GetSingleton();
Init();
}
~FontNameCache()
{
if (!mMap.ops) {
return;
}
if (!mWriteNeeded || !mCache) {
PL_DHashTableFinish(&mMap);
return;
}
nsCAutoString buf;
PL_DHashTableEnumerate(&mMap, WriteOutMap, &buf);
PL_DHashTableFinish(&mMap);
mCache->PutBuffer(CACHE_KEY, buf.get(), buf.Length() + 1);
}
void Init()
{
if (!mMap.ops || !mCache) {
return;
}
PRUint32 size;
char* buf;
if (NS_FAILED(mCache->GetBuffer(CACHE_KEY, &buf, &size))) {
return;
}
LOG(("got: %s from the cache", nsDependentCString(buf, size).get()));
const char* beginning = buf;
const char* end = strchr(beginning, ';');
while (end) {
nsCString filename(beginning, end - beginning);
beginning = end + 1;
if (!(end = strchr(beginning, ';'))) {
break;
}
nsCString faceList(beginning, end - beginning);
beginning = end + 1;
if (!(end = strchr(beginning, ';'))) {
break;
}
PRUint32 timestamp = strtoul(beginning, NULL, 10);
beginning = end + 1;
if (!(end = strchr(beginning, ';'))) {
break;
}
PRUint32 filesize = strtoul(beginning, NULL, 10);
FNCMapEntry* mapEntry =
static_cast<FNCMapEntry*>
(PL_DHashTableOperate(&mMap, filename.get(), PL_DHASH_ADD));
if (mapEntry) {
mapEntry->mFilename.Assign(filename);
mapEntry->mTimestamp = timestamp;
mapEntry->mFilesize = filesize;
mapEntry->mFaces.Assign(faceList);
// entries from the startupcache are marked "non-existing"
// until we have confirmed that the file still exists
mapEntry->mFileExists = PR_FALSE;
}
beginning = end + 1;
end = strchr(beginning, ';');
}
// Should we use free() or delete[] here? See bug 684700.
free(buf);
}
virtual void
GetInfoForFile(nsCString& aFileName, nsCString& aFaceList,
PRUint32 *aTimestamp, PRUint32 *aFilesize)
{
if (!mMap.ops) {
return;
}
PLDHashEntryHdr *hdr =
PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_LOOKUP);
if (!hdr) {
return;
}
FNCMapEntry* entry = static_cast<FNCMapEntry*>(hdr);
if (entry && entry->mTimestamp && entry->mFilesize) {
*aTimestamp = entry->mTimestamp;
*aFilesize = entry->mFilesize;
aFaceList.Assign(entry->mFaces);
// this entry does correspond to an existing file
// (although it might not be up-to-date, in which case
// it will get overwritten via CacheFileInfo)
entry->mFileExists = PR_TRUE;
}
}
virtual void
CacheFileInfo(nsCString& aFileName, nsCString& aFaceList,
PRUint32 aTimestamp, PRUint32 aFilesize)
{
if (!mMap.ops) {
return;
}
FNCMapEntry* entry =
static_cast<FNCMapEntry*>
(PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_ADD));
if (entry) {
entry->mFilename.Assign(aFileName);
entry->mTimestamp = aTimestamp;
entry->mFilesize = aFilesize;
entry->mFaces.Assign(aFaceList);
entry->mFileExists = PR_TRUE;
}
mWriteNeeded = PR_TRUE;
}
private:
mozilla::scache::StartupCache* mCache;
PLDHashTable mMap;
PRBool mWriteNeeded;
PLDHashTableOps mOps;
static PLDHashOperator WriteOutMap(PLDHashTable *aTable,
PLDHashEntryHdr *aHdr,
PRUint32 aNumber, void *aData)
{
FNCMapEntry* entry = static_cast<FNCMapEntry*>(aHdr);
if (!entry->mFileExists) {
// skip writing entries for files that are no longer present
return PL_DHASH_NEXT;
}
nsCAutoString* buf = reinterpret_cast<nsCAutoString*>(aData);
buf->Append(entry->mFilename);
buf->Append(';');
buf->Append(entry->mFaces);
buf->Append(';');
buf->AppendInt(entry->mTimestamp);
buf->Append(';');
buf->AppendInt(entry->mFilesize);
buf->Append(';');
return PL_DHASH_NEXT;
}
typedef struct : public PLDHashEntryHdr {
public:
nsCString mFilename;
PRUint32 mTimestamp;
PRUint32 mFilesize;
nsCString mFaces;
PRBool mFileExists;
} FNCMapEntry;
static PLDHashNumber StringHash(PLDHashTable *table, const void *key)
{
return HashString(reinterpret_cast<const char*>(key));
}
static PRBool HashMatchEntry(PLDHashTable *table,
const PLDHashEntryHdr *aHdr, const void *key)
{
const FNCMapEntry* entry =
static_cast<const FNCMapEntry*>(aHdr);
return entry->mFilename.Equals(reinterpret_cast<const char*>(key));
}
static void MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *aFrom,
PLDHashEntryHdr *aTo)
{
FNCMapEntry* to = static_cast<FNCMapEntry*>(aTo);
const FNCMapEntry* from = static_cast<const FNCMapEntry*>(aFrom);
to->mFilename.Assign(from->mFilename);
to->mTimestamp = from->mTimestamp;
to->mFilesize = from->mFilesize;
to->mFaces.Assign(from->mFaces);
to->mFileExists = from->mFileExists;
}
};
/***************************************************************
*
* gfxFT2FontList
*
*/
// For Mobile, we use gfxFT2Fonts, and we build the font list by directly scanning
// the system's Fonts directory for OpenType and TrueType files.
// For Mobile, we use gfxFT2Fonts, and we build the font list by directly
// scanning the system's Fonts directory for OpenType and TrueType files.
//
// FontEntry is currently defined in gfxFT2Fonts.h, but will probably be moved here
// as part of the Freetype/Linux font restructuring for Harfbuzz integration.
//
// TODO: investigate startup performance - we might be able to improve by avoiding
// the creation of FT_Faces here, and just reading names directly from the file;
// or even consider caching a mapping from font family name to (list of) filenames,
// so that we don't have to scan all the files before we can do any font lookups.
// FontEntry is currently defined in gfxFT2Fonts.h, but should probably be
// moved here for consistency with other platform implementations, and
// because it logically "belongs" to the fontlist that manages the families
// and entries.
gfxFT2FontList::gfxFT2FontList()
{
}
void
gfxFT2FontList::AppendFacesFromFontFile(const PRUnichar *aFileName)
gfxFT2FontList::AppendFacesFromCachedFaceList(nsCString& aFileName,
PRBool aStdFile,
nsCString& aFaceList)
{
AppendFacesFromFontFile(NS_ConvertUTF16toUTF8(aFileName).get());
const char *beginning = aFaceList.get();
const char *end = strchr(beginning, ',');
while (end) {
nsString familyName =
NS_ConvertUTF8toUTF16(beginning, end - beginning);
ToLowerCase(familyName);
beginning = end + 1;
if (!(end = strchr(beginning, ','))) {
break;
}
nsString faceName =
NS_ConvertUTF8toUTF16(beginning, end - beginning);
beginning = end + 1;
if (!(end = strchr(beginning, ','))) {
break;
}
PRUint32 index = strtoul(beginning, NULL, 10);
beginning = end + 1;
if (!(end = strchr(beginning, ','))) {
break;
}
PRBool italic = (*beginning != '0');
beginning = end + 1;
if (!(end = strchr(beginning, ','))) {
break;
}
PRUint32 weight = strtoul(beginning, NULL, 10);
beginning = end + 1;
if (!(end = strchr(beginning, ','))) {
break;
}
PRInt32 stretch = strtol(beginning, NULL, 10);
FontListEntry fle(familyName, faceName, aFileName,
weight, stretch, italic, index);
AppendFaceFromFontListEntry(fle, aStdFile);
beginning = end + 1;
end = strchr(beginning, ',');
}
}
static void
AppendToFaceList(nsCString& aFaceList,
nsAString& aFamilyName, FontEntry* aFontEntry)
{
aFaceList.Append(NS_ConvertUTF16toUTF8(aFamilyName));
aFaceList.Append(',');
aFaceList.Append(NS_ConvertUTF16toUTF8(aFontEntry->Name()));
aFaceList.Append(',');
aFaceList.AppendInt(aFontEntry->mFTFontIndex);
aFaceList.Append(',');
aFaceList.Append(aFontEntry->IsItalic() ? '1' : '0');
aFaceList.Append(',');
aFaceList.AppendInt(aFontEntry->Weight());
aFaceList.Append(',');
aFaceList.AppendInt(aFontEntry->Stretch());
aFaceList.Append(',');
}
void
gfxFT2FontList::AppendFacesFromFontFile(const char *aFileName)
gfxFT2FontList::AppendFacesFromFontFile(nsCString& aFileName,
PRBool aStdFile,
FontNameCache *aCache)
{
nsCString faceList;
PRUint32 filesize = 0, timestamp = 0;
if (aCache) {
aCache->GetInfoForFile(aFileName, faceList, &timestamp, &filesize);
}
struct stat s;
int statRetval = stat(aFileName.get(), &s);
if (!faceList.IsEmpty() && 0 == statRetval &&
s.st_mtime == timestamp && s.st_size == filesize)
{
LOG(("using cached font info for %s", aFileName.get()));
AppendFacesFromCachedFaceList(aFileName, aStdFile, faceList);
return;
}
#ifdef XP_WIN
FT_Library ftLibrary = gfxWindowsPlatform::GetPlatform()->GetFTLibrary();
#elif defined(ANDROID)
FT_Library ftLibrary = gfxAndroidPlatform::GetPlatform()->GetFTLibrary();
#endif
FT_Face dummy;
if (FT_Err_Ok == FT_New_Face(ftLibrary, aFileName, -1, &dummy)) {
if (FT_Err_Ok == FT_New_Face(ftLibrary, aFileName.get(), -1, &dummy)) {
LOG(("reading font info via FreeType for %s", aFileName.get()));
nsCString faceList;
timestamp = s.st_mtime;
filesize = s.st_size;
for (FT_Long i = 0; i < dummy->num_faces; i++) {
FT_Face face;
if (FT_Err_Ok != FT_New_Face(ftLibrary, aFileName, i, &face))
if (FT_Err_Ok != FT_New_Face(ftLibrary, aFileName.get(), i, &face)) {
continue;
}
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
FontEntry* fe = FontEntry::CreateFontEntry(face, aFileName.get(), i);
if (fe) {
NS_ConvertUTF8toUTF16 name(face->family_name);
BuildKeyNameFromFontName(name);
@ -137,13 +430,16 @@ gfxFT2FontList::AppendFacesFromFontFile(const char *aFileName)
if (!family) {
family = new gfxFontFamily(name);
mFontFamilies.Put(name, family);
if (mBadUnderlineFamilyNames.Contains(name))
if (mBadUnderlineFamilyNames.Contains(name)) {
family->SetBadUnderlineFamily();
}
}
fe->mStandardFace = aStdFile;
family->AddFontEntry(fe);
family->SetHasStyles(PR_TRUE);
if (family->IsBadUnderlineFamily())
if (family->IsBadUnderlineFamily()) {
fe->mIsBadUnderlineFont = PR_TRUE;
}
AppendToFaceList(faceList, name, fe);
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("(fontinit) added (%s) to family (%s)"
@ -157,9 +453,33 @@ gfxFT2FontList::AppendFacesFromFontFile(const char *aFileName)
}
}
FT_Done_Face(dummy);
if (aCache && 0 == statRetval && !faceList.IsEmpty()) {
aCache->CacheFileInfo(aFileName, faceList, timestamp, filesize);
}
}
}
// Called on each family after all fonts are added to the list;
// this will sort faces to give priority to "standard" font files
// if aUserArg is non-null (i.e. we're using it as a boolean flag)
static PLDHashOperator
FinalizeFamilyMemberList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
gfxFontFamily *family = aFamily.get();
PRBool sortFaces = (aUserArg != nsnull);
family->SetHasStyles(PR_TRUE);
if (sortFaces) {
family->SortAvailableFonts();
}
family->CheckForSimpleFamily();
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::FindFonts()
{
@ -199,7 +519,7 @@ gfxFT2FontList::FindFonts()
nsAutoString filePath(path);
filePath.AppendLiteral("\\");
filePath.Append(results.cFileName);
AppendFacesFromFontFile(static_cast<const PRUnichar*>(filePath.get()));
AppendFacesFromFontFile(NS_ConvertUTF16toUTF8(filePath));
moreFiles = FindNextFile(handle, &results);
}
if (handle != INVALID_HANDLE_VALUE)
@ -213,29 +533,144 @@ gfxFT2FontList::FindFonts()
mPrefFonts.Clear();
mCodepointsWithNoFonts.reset();
DIR *d = opendir("/system/fonts");
struct dirent *ent = NULL;
while(d && (ent = readdir(d)) != NULL) {
int namelen = strlen(ent->d_name);
if (namelen > 4 &&
strcasecmp(ent->d_name + namelen - 4, ".ttf") == 0)
{
nsCString s("/system/fonts");
s.Append("/");
s.Append(nsDependentCString(ent->d_name));
AppendFacesFromFontFile(nsPromiseFlatCString(s).get());
}
}
if (d) {
closedir(d);
}
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// Content process: ask the Chrome process to give us the list
InfallibleTArray<FontListEntry> fonts;
mozilla::dom::ContentChild::GetSingleton()->SendReadFontList(&fonts);
for (PRUint32 i = 0, n = fonts.Length(); i < n; ++i) {
AppendFaceFromFontListEntry(fonts[i], PR_FALSE);
}
// Passing null for userdata tells Finalize that it does not need
// to sort faces (because they were already sorted by chrome,
// so we just maintain the existing order)
mFontFamilies.Enumerate(FinalizeFamilyMemberList, nsnull);
LOG(("got font list from chrome process: %d faces in %d families",
fonts.Length(), mFontFamilies.Count()));
return;
}
// Chrome process: get the cached list (if any)
FontNameCache fnc;
// ANDROID_ROOT is the root of the android system, typically /system;
// font files are in /$ANDROID_ROOT/fonts/
nsCString root;
char *androidRoot = PR_GetEnv("ANDROID_ROOT");
if (androidRoot) {
root = androidRoot;
} else {
root = NS_LITERAL_CSTRING("/system");
}
root.Append("/fonts");
static const char* sStandardFonts[] = {
"DroidSans.ttf",
"DroidSans-Bold.ttf",
"DroidSerif-Regular.ttf",
"DroidSerif-Bold.ttf",
"DroidSerif-Italic.ttf",
"DroidSerif-BoldItalic.ttf",
"DroidSansMono.ttf",
"DroidSansArabic.ttf",
"DroidSansHebrew.ttf",
"DroidSansThai.ttf",
"MTLmr3m.ttf",
"MTLc3m.ttf",
"DroidSansJapanese.ttf",
"DroidSansFallback.ttf"
};
DIR *d = opendir(root.get());
if (!d) {
// if we can't find/read the font directory, we are doomed!
NS_RUNTIMEABORT("Could not read the system fonts directory");
}
struct dirent *ent = NULL;
while ((ent = readdir(d)) != NULL) {
int namelen = strlen(ent->d_name);
if (namelen <= 4) {
// cannot be a usable font filename
continue;
}
const char *ext = ent->d_name + namelen - 4;
if (strcasecmp(ext, ".ttf") == 0 ||
strcasecmp(ext, ".otf") == 0 ||
strcasecmp(ext, ".ttc") == 0)
{
bool isStdFont = false;
for (unsigned int i = 0;
i < NS_ARRAY_LENGTH(sStandardFonts) && !isStdFont; i++)
{
isStdFont = strcmp(sStandardFonts[i], ent->d_name) == 0;
}
nsCString s(root);
s.Append('/');
s.Append(ent->d_name, namelen);
// Add the face(s) from this file to our font list;
// note that if we have cached info for this file in fnc,
// and the file is unchanged, we won't actually need to read it.
// If the file is new/changed, this will update the FontNameCache.
AppendFacesFromFontFile(s, isStdFont, &fnc);
}
}
closedir(d);
// Finalize the families by sorting faces into standard order
// and marking "simple" families.
// Passing non-null userData here says that we want faces to be sorted.
mFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
#endif // XP_WIN && ANDROID
}
void
gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
PRBool aStdFile)
{
FontEntry* fe = FontEntry::CreateFontEntry(aFLE);
if (fe) {
fe->mStandardFace = aStdFile;
nsAutoString name(aFLE.familyName());
gfxFontFamily *family = mFontFamilies.GetWeak(name);
if (!family) {
family = new gfxFontFamily(name);
mFontFamilies.Put(name, family);
if (mBadUnderlineFamilyNames.Contains(name)) {
family->SetBadUnderlineFamily();
}
}
family->AddFontEntry(fe);
if (family->IsBadUnderlineFamily()) {
fe->mIsBadUnderlineFont = PR_TRUE;
}
}
}
static PLDHashOperator
AddFamilyToFontList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
InfallibleTArray<FontListEntry>* fontlist =
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FontFamily *family = static_cast<FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist);
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::GetFontList(InfallibleTArray<FontListEntry>* retValue)
{
mFontFamilies.Enumerate(AddFamilyToFontList, retValue);
}
nsresult
gfxFT2FontList::InitFontList()
{

Просмотреть файл

@ -47,7 +47,14 @@
#endif
#include "gfxPlatformFontList.h"
#include <bitset>
namespace mozilla {
namespace dom {
class FontListEntry;
};
};
using mozilla::dom::FontListEntry;
class FontNameCache;
class gfxFT2FontList : public gfxPlatformFontList
{
@ -64,11 +71,26 @@ public:
const PRUint8 *aFontData,
PRUint32 aLength);
void GetFontList(InfallibleTArray<FontListEntry>* retValue);
static gfxFT2FontList* PlatformFontList() {
return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList());
}
protected:
virtual nsresult InitFontList();
void AppendFacesFromFontFile(const PRUnichar *aFileName);
void AppendFacesFromFontFile(const char *aFileName);
void AppendFaceFromFontListEntry(const FontListEntry& aFLE,
PRBool isStdFile);
void AppendFacesFromFontFile(nsCString& aFileName,
PRBool isStdFile = PR_FALSE,
FontNameCache *aCache = nsnull);
void AppendFacesFromCachedFaceList(nsCString& aFileName,
PRBool isStdFile,
nsCString& aFaceList);
void FindFonts();
};

Просмотреть файл

@ -46,6 +46,7 @@
#define gfxToolkitPlatform gfxWindowsPlatform
#include "gfxFT2FontList.h"
#elif defined(ANDROID)
#include "mozilla/dom/ContentChild.h"
#include "gfxAndroidPlatform.h"
#define gfxToolkitPlatform gfxAndroidPlatform
#endif
@ -71,19 +72,8 @@
#include "mozilla/Preferences.h"
using namespace mozilla;
static PRLogModuleInfo *gFontLog = PR_NewLogModule("ft2fonts");
static const char *sCJKLangGroup[] = {
"ja",
"ko",
"zh-cn",
"zh-hk",
"zh-tw"
};
#define COUNT_OF_CJK_LANG_GROUP 5
// rounding and truncation functions for a Freetype floating point number
// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
// part and low 6 bits for the fractional part.
@ -92,6 +82,54 @@ static const char *sCJKLangGroup[] = {
#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
static cairo_scaled_font_t *
CreateScaledFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
cairo_scaled_font_t *scaledFont = NULL;
cairo_matrix_t sizeMatrix;
cairo_matrix_t identityMatrix;
// XXX deal with adjusted size
cairo_matrix_init_scale(&sizeMatrix, aStyle->size, aStyle->size);
cairo_matrix_init_identity(&identityMatrix);
// synthetic oblique by skewing via the font matrix
PRBool needsOblique =
!aFontEntry->mItalic &&
(aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE));
if (needsOblique) {
const double kSkewFactor = 0.25;
cairo_matrix_t style;
cairo_matrix_init(&style,
1, //xx
0, //yx
-1 * kSkewFactor, //xy
1, //yy
0, //x0
0); //y0
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
}
cairo_font_options_t *fontOptions = cairo_font_options_create();
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
#endif
scaledFont = cairo_scaled_font_create(aFontEntry->CairoFontFace(),
&sizeMatrix,
&identityMatrix, fontOptions);
cairo_font_options_destroy(fontOptions);
NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
"Failed to make scaled font");
return scaledFont;
}
/**
* FontEntry
*/
@ -110,9 +148,12 @@ FontEntry::~FontEntry()
}
gfxFont*
FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold) {
already_AddRefed<gfxFT2Font> font = gfxFT2Font::GetOrMakeFont(this, aFontStyle, aNeedsBold);
return font.get();
FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold)
{
cairo_scaled_font_t *scaledFont = CreateScaledFont(this, aFontStyle);
gfxFont *font = new gfxFT2Font(scaledFont, this, aFontStyle, aNeedsBold);
cairo_scaled_font_destroy(scaledFont);
return font;
}
/* static */
@ -132,7 +173,7 @@ FontEntry::CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
NS_Free((void*)aFontData);
return nsnull;
}
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face, aFontData);
FontEntry* fe = FontEntry::CreateFontEntry(face, nsnull, 0, aFontData);
if (fe) {
fe->mItalic = aProxyEntry.mItalic;
fe->mWeight = aProxyEntry.mWeight;
@ -169,7 +210,22 @@ FTFontDestroyFunc(void *data)
}
/* static */ FontEntry*
FontEntry::CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData) {
FontEntry::CreateFontEntry(const FontListEntry& aFLE)
{
FontEntry *fe = new FontEntry(aFLE.faceName());
fe->mFilename = aFLE.filepath();
fe->mFTFontIndex = aFLE.index();
fe->mWeight = aFLE.weight();
fe->mStretch = aFLE.stretch();
fe->mItalic = aFLE.italic();
return fe;
}
/* static */ FontEntry*
FontEntry::CreateFontEntry(FT_Face aFace,
const char* aFilename, PRUint8 aIndex,
const PRUint8 *aFontData)
{
static cairo_user_data_key_t key;
if (!aFace->family_name) {
@ -191,6 +247,8 @@ FontEntry::CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData) {
#else
fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0);
#endif
fe->mFilename = aFilename;
fe->mFTFontIndex = aIndex;
FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData);
cairo_font_face_set_user_data(fe->mFontFace, &key,
userFontData, FTFontDestroyFunc);
@ -302,37 +360,25 @@ FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
return static_cast<FontEntry*>(FindFontForStyle(aFontStyle, needsBold));
}
void FontFamily::AddFontFileAndIndex(nsCString aFilename, PRUint32 aIndex)
{
SetHasStyles(PR_FALSE);
mFilenames.AppendElement(new FileAndIndex(aFilename, aIndex));
}
void
FontFamily::FindStyleVariations()
FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList)
{
if (mHasStyles) {
return;
}
mHasStyles = PR_TRUE;
for (int i = 0; i < mFilenames.Length(); i++) {
FT_Face face;
gfxToolkitPlatform* platform = gfxToolkitPlatform::GetPlatform();
if (FT_Err_Ok == FT_New_Face(platform->GetFTLibrary(),
mFilenames[i].filename.get(),
mFilenames[i].index, &face)) {
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
if (fe)
AddFontEntry(fe);
for (int i = 0, n = mAvailableFonts.Length(); i < n; ++i) {
const FontEntry *fe =
static_cast<const FontEntry*>(mAvailableFonts[i].get());
if (!fe) {
continue;
}
aFontList->AppendElement(FontListEntry(Name(), fe->Name(),
fe->mFilename,
fe->Weight(), fe->Stretch(),
fe->IsItalic(),
fe->mFTFontIndex));
}
mFilenames.Clear();
SetHasStyles(PR_TRUE);
}
#ifndef ANDROID // not needed on Android, we use the generic gfxFontGroup
/**
* gfxFT2FontGroup
*/
@ -651,7 +697,7 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
already_AddRefed<gfxFont>
gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
{
#ifdef XP_WIN
#if defined(XP_WIN) || defined(ANDROID)
FontEntry *fe = static_cast<FontEntry*>
(gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
if (fe) {
@ -670,6 +716,8 @@ gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
return nsnull;
}
#endif // !ANDROID
/**
* gfxFT2Font
*/
@ -824,57 +872,12 @@ gfxFT2Font::CairoFontFace()
return GetFontEntry()->CairoFontFace();
}
static cairo_scaled_font_t *
CreateScaledFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
cairo_scaled_font_t *scaledFont = NULL;
cairo_matrix_t sizeMatrix;
cairo_matrix_t identityMatrix;
// XXX deal with adjusted size
cairo_matrix_init_scale(&sizeMatrix, aStyle->size, aStyle->size);
cairo_matrix_init_identity(&identityMatrix);
// synthetic oblique by skewing via the font matrix
PRBool needsOblique = (!aFontEntry->mItalic && (aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
if (needsOblique) {
const double kSkewFactor = 0.25;
cairo_matrix_t style;
cairo_matrix_init(&style,
1, //xx
0, //yx
-1 * kSkewFactor, //xy
1, //yy
0, //x0
0); //y0
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
}
cairo_font_options_t *fontOptions = cairo_font_options_create();
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
#endif
scaledFont = cairo_scaled_font_create(aFontEntry->CairoFontFace(),
&sizeMatrix,
&identityMatrix, fontOptions);
cairo_font_options_destroy(fontOptions);
NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
"Failed to make scaled font");
return scaledFont;
}
/**
* Look up the font in the gfxFont cache. If we don't find it, create one.
* In either case, add a ref, append it to the aFonts array, and return it ---
* except for OOM in which case we do nothing and return null.
*/
#ifndef ANDROID // this is only for gfxFT2FontGroup, which is not used on Android
already_AddRefed<gfxFT2Font>
gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PRBool aNeedsBold)
{
@ -888,6 +891,7 @@ gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PR
nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle, aNeedsBold);
return font.forget();
}
#endif
already_AddRefed<gfxFT2Font>
gfxFT2Font::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNeedsBold)

Просмотреть файл

@ -47,17 +47,14 @@
#include "gfxFontUtils.h"
#include "gfxUserFontSet.h"
typedef struct FT_FaceRec_* FT_Face;
class FileAndIndex {
public:
FileAndIndex(nsCString aFilename, PRUint32 aIndex) :
filename(aFilename), index(aIndex) {}
FileAndIndex(FileAndIndex* fai) :
filename(fai->filename), index(fai->index) {}
nsCString filename;
PRUint32 index;
namespace mozilla {
namespace dom {
class FontListEntry;
};
};
using mozilla::dom::FontListEntry;
typedef struct FT_FaceRec_* FT_Face;
/**
* FontFamily is a class that describes one of the fonts on the users system. It holds
@ -72,13 +69,9 @@ public:
gfxFontFamily(aName) { }
FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
virtual void FindStyleVariations();
void AddFontFileAndIndex(nsCString aFilename, PRUint32 aIndex);
private:
// mFilenames are queus of font files that
// need to be lazily processed into font entries
nsTArray<FileAndIndex> mFilenames;
// Append this family's faces to the IPC fontlist
void AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList);
};
class FontEntry : public gfxFontEntry
@ -98,12 +91,22 @@ public:
return Name();
}
// create a font entry for a downloaded font
static FontEntry*
CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength);
// create a font entry representing an installed font, identified by
// a FontListEntry; the freetype and cairo faces will not be instantiated
// until actually needed
static FontEntry*
CreateFontEntry(const FontListEntry& aFLE);
// create a font entry for a given freetype face; if it is an installed font,
// also record the filename and index
static FontEntry*
CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData = nsnull);
CreateFontEntry(FT_Face aFace, const char *aFilename, PRUint8 aIndex,
const PRUint8 *aFontData = nsnull);
// aFontData is NS_Malloc'ed data that aFace depends on, to be freed
// after the face is destroyed; null if there is no such buffer
@ -134,8 +137,11 @@ public: // new functions
FontEntry *GetFontEntry();
#ifndef ANDROID
static already_AddRefed<gfxFT2Font>
GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PRBool aNeedsBold = PR_FALSE);
#endif
static already_AddRefed<gfxFT2Font>
GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNeedsBold = PR_FALSE);

Просмотреть файл

@ -540,15 +540,21 @@ gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
void
gfxFontFamily::CheckForSimpleFamily()
{
if (mAvailableFonts.Length() > 4 || mAvailableFonts.Length() == 0) {
PRUint32 count = mAvailableFonts.Length();
if (count > 4 || count == 0) {
return; // can't be "simple" if there are >4 faces;
// if none then the family is unusable anyway
}
if (count == 1) {
mIsSimpleFamily = PR_TRUE;
return;
}
PRInt16 firstStretch = mAvailableFonts[0]->Stretch();
gfxFontEntry *faces[4] = { 0 };
for (PRUint8 i = 0; i < mAvailableFonts.Length(); ++i) {
for (PRUint8 i = 0; i < count; ++i) {
gfxFontEntry *fe = mAvailableFonts[i];
if (fe->Stretch() != firstStretch) {
return; // font-stretch doesn't match, don't treat as simple family