зеркало из https://github.com/mozilla/gecko-dev.git
bug 684889 - refactor and clean up Android font-list implementation. r=jdaggett
This commit is contained in:
Родитель
51e7a7b124
Коммит
1d2932c2c0
|
@ -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, ×tamp, &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, ×tamp, &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
|
||||
|
|
Загрузка…
Ссылка в новой задаче