Bug 710727. Share cmaps across all fonts. r=jkew, a=tracking-firefox

This commit is contained in:
John Daggett 2012-04-19 08:59:43 +09:00
Родитель 254b7db74e
Коммит 6359697534
10 изменённых файлов: 434 добавлений и 189 удалений

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

@ -375,84 +375,77 @@ gfxDWriteFontEntry::ReadCMAP()
nsresult rv; nsresult rv;
// attempt this once, if errors occur leave a blank cmap // attempt this once, if errors occur leave a blank cmap
if (mCmapInitialized) if (mCharacterMap) {
return NS_OK; return NS_OK;
mCmapInitialized = true; }
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
// if loading via GDI, just use GetFontTable // if loading via GDI, just use GetFontTable
if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) { if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) {
const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p'); PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
AutoFallibleTArray<PRUint8,16384> buffer;
if (GetFontTable(kCmapTag, buffer) != NS_OK) AutoFallibleTArray<PRUint8,16384> cmap;
return NS_ERROR_FAILURE; rv = GetFontTable(kCMAP, cmap);
PRUint8 *cmap = buffer.Elements();
bool unicodeFont = false, symbolFont = false; bool unicodeFont = false, symbolFont = false; // currently ignored
rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
mCharacterMap, mUVSOffset, if (NS_SUCCEEDED(rv)) {
unicodeFont, symbolFont); rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
#ifdef PR_LOGGING *charmap, mUVSOffset,
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", unicodeFont, symbolFont);
NS_ConvertUTF16toUTF8(mName).get(), }
mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of))); } else {
if (LOG_CMAPDATA_ENABLED()) { // loading using dwrite, don't use GetFontTable to avoid copy
char prefix[256]; nsRefPtr<IDWriteFontFace> fontFace;
sprintf(prefix, "(cmapdata) name: %.220s", rv = CreateFontFace(getter_AddRefs(fontFace));
NS_ConvertUTF16toUTF8(mName).get());
mCharacterMap.Dump(prefix, eGfxLog_cmapdata); if (NS_SUCCEEDED(rv)) {
const PRUint32 kCmapTag = DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p');
PRUint8 *tableData;
PRUint32 len;
void *tableContext = NULL;
BOOL exists;
hr = fontFace->TryGetFontTable(kCmapTag, (const void**)&tableData,
&len, &tableContext, &exists);
if (SUCCEEDED(hr)) {
bool isSymbol = fontFace->IsSymbolFont();
bool isUnicode = true;
if (exists) {
rv = gfxFontUtils::ReadCMAP(tableData, len, *charmap,
mUVSOffset, isUnicode,
isSymbol);
}
fontFace->ReleaseFontTable(tableContext);
} else {
rv = NS_ERROR_FAILURE;
}
} }
#endif
mHasCmapTable = NS_SUCCEEDED(rv);
return rv;
} }
// loading using dwrite, don't use GetFontTable to avoid copy mHasCmapTable = NS_SUCCEEDED(rv);
nsRefPtr<IDWriteFontFace> fontFace; if (mHasCmapTable) {
rv = CreateFontFace(getter_AddRefs(fontFace)); gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
mCharacterMap = pfl->FindCharMap(charmap);
if (NS_FAILED(rv)) { } else {
return rv; // if error occurred, initialize to null cmap
mCharacterMap = new gfxCharacterMap();
} }
PRUint8 *tableData;
PRUint32 len;
void *tableContext = NULL;
BOOL exists;
hr = fontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p'),
(const void**)&tableData,
&len,
&tableContext,
&exists);
if (FAILED(hr)) {
return NS_ERROR_FAILURE;
}
bool isSymbol = fontFace->IsSymbolFont();
bool isUnicode = true;
if (exists) {
rv = gfxFontUtils::ReadCMAP(tableData,
len,
mCharacterMap,
mUVSOffset,
isUnicode,
isSymbol);
}
fontFace->ReleaseFontTable(tableContext);
#ifdef PR_LOGGING #ifdef PR_LOGGING
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
NS_ConvertUTF16toUTF8(mName).get(), NS_ConvertUTF16toUTF8(mName).get(),
mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of))); charmap->SizeOfIncludingThis(moz_malloc_size_of),
charmap->mHash, mCharacterMap == charmap ? " new" : ""));
if (LOG_CMAPDATA_ENABLED()) { if (LOG_CMAPDATA_ENABLED()) {
char prefix[256]; char prefix[256];
sprintf(prefix, "(cmapdata) name: %.220s", sprintf(prefix, "(cmapdata) name: %.220s",
NS_ConvertUTF16toUTF8(mName).get()); NS_ConvertUTF16toUTF8(mName).get());
mCharacterMap.Dump(prefix, eGfxLog_cmapdata); charmap->Dump(prefix, eGfxLog_cmapdata);
} }
#endif #endif
mHasCmapTable = NS_SUCCEEDED(rv);
return rv; return rv;
} }

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

@ -343,12 +343,11 @@ FT2FontEntry::CairoFontFace()
nsresult nsresult
FT2FontEntry::ReadCMAP() FT2FontEntry::ReadCMAP()
{ {
if (mCmapInitialized) { if (mCharacterMap) {
return NS_OK; return NS_OK;
} }
// attempt this once, if errors occur leave a blank cmap nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
mCmapInitialized = true;
AutoFallibleTArray<PRUint8,16384> buffer; AutoFallibleTArray<PRUint8,16384> buffer;
nsresult rv = GetFontTable(TTAG_cmap, buffer); nsresult rv = GetFontTable(TTAG_cmap, buffer);
@ -357,11 +356,18 @@ FT2FontEntry::ReadCMAP()
bool unicodeFont; bool unicodeFont;
bool symbolFont; bool symbolFont;
rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(), rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(),
mCharacterMap, mUVSOffset, *charmap, mUVSOffset,
unicodeFont, symbolFont); unicodeFont, symbolFont);
} }
mHasCmapTable = NS_SUCCEEDED(rv); mHasCmapTable = NS_SUCCEEDED(rv);
if (mHasCmapTable) {
gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
mCharacterMap = pfl->FindCharMap(charmap);
} else {
// if error occurred, initialize to null cmap
mCharacterMap = new gfxCharacterMap();
}
return rv; return rv;
} }

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

@ -103,6 +103,16 @@ static PRUint32 gGlyphExtentsSetupLazyTight = 0;
static PRUint32 gGlyphExtentsSetupFallBackToTight = 0; static PRUint32 gGlyphExtentsSetupFallBackToTight = 0;
#endif #endif
void
gfxCharacterMap::NotifyReleased()
{
gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
if (mShared) {
fontlist->RemoveCmap(this);
}
delete this;
}
gfxFontEntry::~gfxFontEntry() gfxFontEntry::~gfxFontEntry()
{ {
delete mUserFontData; delete mUserFontData;
@ -115,18 +125,20 @@ bool gfxFontEntry::IsSymbolFont()
bool gfxFontEntry::TestCharacterMap(PRUint32 aCh) bool gfxFontEntry::TestCharacterMap(PRUint32 aCh)
{ {
if (!mCmapInitialized) { if (!mCharacterMap) {
ReadCMAP(); ReadCMAP();
NS_ASSERTION(mCharacterMap, "failed to initialize character map");
} }
return mCharacterMap.test(aCh); return mCharacterMap->test(aCh);
} }
nsresult gfxFontEntry::InitializeUVSMap() nsresult gfxFontEntry::InitializeUVSMap()
{ {
// mUVSOffset will not be initialized // mUVSOffset will not be initialized
// until cmap is initialized. // until cmap is initialized.
if (!mCmapInitialized) { if (!mCharacterMap) {
ReadCMAP(); ReadCMAP();
NS_ASSERTION(mCharacterMap, "failed to initialize character map");
} }
if (!mUVSOffset) { if (!mUVSOffset) {
@ -170,7 +182,8 @@ PRUint16 gfxFontEntry::GetUVSGlyph(PRUint32 aCh, PRUint32 aVS)
nsresult gfxFontEntry::ReadCMAP() nsresult gfxFontEntry::ReadCMAP()
{ {
mCmapInitialized = true; NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
mCharacterMap = new gfxCharacterMap();
return NS_OK; return NS_OK;
} }
@ -433,7 +446,12 @@ gfxFontEntry::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontListSizes* aSizes) const FontListSizes* aSizes) const
{ {
aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf); aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
aSizes->mCharMapsSize += mCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
// cmaps are shared so only non-shared cmaps are included here
if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
aSizes->mCharMapsSize +=
mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
}
aSizes->mFontTableCacheSize += aSizes->mFontTableCacheSize +=
mFontTableCache.SizeOfExcludingThis( mFontTableCache.SizeOfExcludingThis(
FontTableHashEntry::SizeOfEntryExcludingThis, FontTableHashEntry::SizeOfEntryExcludingThis,
@ -770,7 +788,7 @@ CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
void void
gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData) gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
{ {
if (mCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) { if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
// none of the faces in the family support the required char, // none of the faces in the family support the required char,
// so bail out immediately // so bail out immediately
return; return;
@ -1028,7 +1046,8 @@ gfxFontFamily::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
{ {
aSizes->mFontListSize += aSizes->mFontListSize +=
mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf); mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
aSizes->mCharMapsSize += mCharacterMap.SizeOfExcludingThis(aMallocSizeOf); aSizes->mCharMapsSize +=
mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
aSizes->mFontListSize += aSizes->mFontListSize +=
mAvailableFonts.SizeOfExcludingThis(aMallocSizeOf); mAvailableFonts.SizeOfExcludingThis(aMallocSizeOf);
@ -3649,7 +3668,9 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
// check other faces of the family // check other faces of the family
gfxFontFamily *family = font->GetFontEntry()->Family(); gfxFontFamily *family = font->GetFontEntry()->Family();
if (family && family->TestCharacterMap(aCh)) { if (family && !font->GetFontEntry()->mIsProxy &&
family->TestCharacterMap(aCh))
{
GlobalFontMatch matchData(aCh, aRunScript, &mStyle); GlobalFontMatch matchData(aCh, aRunScript, &mStyle);
family->SearchAllFontsForChar(&matchData); family->SearchAllFontsForChar(&matchData);
gfxFontEntry *fe = matchData.mBestMatch; gfxFontEntry *fe = matchData.mBestMatch;

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

@ -198,6 +198,56 @@ struct THEBES_API gfxFontStyle {
static PRUint32 ParseFontLanguageOverride(const nsString& aLangTag); static PRUint32 ParseFontLanguageOverride(const nsString& aLangTag);
}; };
class gfxCharacterMap : public gfxSparseBitSet {
public:
nsrefcnt AddRef() {
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "gfxCharacterMap", sizeof(*this));
return mRefCnt;
}
nsrefcnt Release() {
NS_PRECONDITION(0 != mRefCnt, "dup release");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "gfxCharacterMap");
if (mRefCnt == 0) {
NotifyReleased();
// |this| has been deleted.
return 0;
}
return mRefCnt;
}
gfxCharacterMap() :
mHash(0), mBuildOnTheFly(false), mShared(false)
{ }
void CalcHash() { mHash = GetChecksum(); }
size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
return gfxSparseBitSet::SizeOfExcludingThis(aMallocSizeOf);
}
// hash of the cmap bitvector
PRUint32 mHash;
// if cmap is built on the fly it's never shared
bool mBuildOnTheFly;
// cmap is shared globally
bool mShared;
protected:
void NotifyReleased();
nsAutoRefCnt mRefCnt;
private:
gfxCharacterMap(const gfxCharacterMap&);
gfxCharacterMap& operator=(const gfxCharacterMap&);
};
class gfxFontEntry { class gfxFontEntry {
public: public:
NS_INLINE_DECL_REFCOUNTING(gfxFontEntry) NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
@ -216,7 +266,6 @@ public:
mCheckedForGraphiteTables(false), mCheckedForGraphiteTables(false),
#endif #endif
mHasCmapTable(false), mHasCmapTable(false),
mCmapInitialized(false),
mUVSOffset(0), mUVSData(nsnull), mUVSOffset(0), mUVSData(nsnull),
mUserFontData(nsnull), mUserFontData(nsnull),
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE), mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
@ -259,16 +308,17 @@ public:
#endif #endif
inline bool HasCmapTable() { inline bool HasCmapTable() {
if (!mCmapInitialized) { if (!mCharacterMap) {
ReadCMAP(); ReadCMAP();
NS_ASSERTION(mCharacterMap, "failed to initialize character map");
} }
return mHasCmapTable; return mHasCmapTable;
} }
inline bool HasCharacter(PRUint32 ch) { inline bool HasCharacter(PRUint32 ch) {
if (mCharacterMap.test(ch)) if (mCharacterMap && mCharacterMap->test(ch)) {
return true; return true;
}
return TestCharacterMap(ch); return TestCharacterMap(ch);
} }
@ -344,8 +394,7 @@ public:
bool mCheckedForGraphiteTables; bool mCheckedForGraphiteTables;
#endif #endif
bool mHasCmapTable; bool mHasCmapTable;
bool mCmapInitialized; nsRefPtr<gfxCharacterMap> mCharacterMap;
gfxSparseBitSet mCharacterMap;
PRUint32 mUVSOffset; PRUint32 mUVSOffset;
nsAutoArrayPtr<PRUint8> mUVSData; nsAutoArrayPtr<PRUint8> mUVSData;
gfxUserFontData* mUserFontData; gfxUserFontData* mUserFontData;
@ -375,7 +424,6 @@ protected:
mCheckedForGraphiteTables(false), mCheckedForGraphiteTables(false),
#endif #endif
mHasCmapTable(false), mHasCmapTable(false),
mCmapInitialized(false),
mUVSOffset(0), mUVSData(nsnull), mUVSOffset(0), mUVSData(nsnull),
mUserFontData(nsnull), mUserFontData(nsnull),
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE), mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
@ -529,7 +577,7 @@ public:
mHasStyles(false), mHasStyles(false),
mIsSimpleFamily(false), mIsSimpleFamily(false),
mIsBadUnderlineFamily(false), mIsBadUnderlineFamily(false),
mCharacterMapInitialized(false) mFamilyCharacterMapInitialized(false)
{ } { }
virtual ~gfxFontFamily() { virtual ~gfxFontFamily() {
@ -607,26 +655,27 @@ public:
PRUint32 i, numFonts = mAvailableFonts.Length(); PRUint32 i, numFonts = mAvailableFonts.Length();
for (i = 0; i < numFonts; i++) { for (i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i]; gfxFontEntry *fe = mAvailableFonts[i];
if (!fe) { // don't try to load cmaps for downloadable fonts not yet loaded
if (!fe || fe->mIsProxy) {
continue; continue;
} }
fe->ReadCMAP(); fe->ReadCMAP();
mCharacterMap.Union(fe->mCharacterMap); mFamilyCharacterMap.Union(*(fe->mCharacterMap));
} }
mCharacterMap.Compact(); mFamilyCharacterMap.Compact();
mCharacterMapInitialized = true; mFamilyCharacterMapInitialized = true;
} }
bool TestCharacterMap(PRUint32 aCh) { bool TestCharacterMap(PRUint32 aCh) {
if (!mCharacterMapInitialized) { if (!mFamilyCharacterMapInitialized) {
ReadAllCMAPs(); ReadAllCMAPs();
} }
return mCharacterMap.test(aCh); return mFamilyCharacterMap.test(aCh);
} }
void ResetCharacterMap() { void ResetCharacterMap() {
mCharacterMap.reset(); mFamilyCharacterMap.reset();
mCharacterMapInitialized = false; mFamilyCharacterMapInitialized = false;
} }
// mark this family as being in the "bad" underline offset blacklist // mark this family as being in the "bad" underline offset blacklist
@ -675,14 +724,14 @@ protected:
nsString mName; nsString mName;
nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts; nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
gfxSparseBitSet mCharacterMap; gfxSparseBitSet mFamilyCharacterMap;
bool mOtherFamilyNamesInitialized; bool mOtherFamilyNamesInitialized : 1;
bool mHasOtherFamilyNames; bool mHasOtherFamilyNames : 1;
bool mFaceNamesInitialized; bool mFaceNamesInitialized : 1;
bool mHasStyles; bool mHasStyles : 1;
bool mIsSimpleFamily; bool mIsSimpleFamily : 1;
bool mIsBadUnderlineFamily; bool mIsBadUnderlineFamily : 1;
bool mCharacterMapInitialized; bool mFamilyCharacterMapInitialized : 1;
enum { enum {
// for "simple" families, the faces are stored in mAvailableFonts // for "simple" families, the faces are stored in mAvailableFonts

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

@ -58,6 +58,8 @@
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsIStreamBufferAccess.h" #include "nsIStreamBufferAccess.h"
#include "zlib.h"
/* Bug 341128 - w32api defines min/max which causes problems with <bitset> */ /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
#ifdef __MINGW32__ #ifdef __MINGW32__
#undef min #undef min
@ -87,6 +89,28 @@ public:
mBlocks[i] = new Block(*block); mBlocks[i] = new Block(*block);
} }
} }
bool Equals(const gfxSparseBitSet *aOther) const {
if (mBlocks.Length() != aOther->mBlocks.Length()) {
return false;
}
size_t n = mBlocks.Length();
for (size_t i = 0; i < n; ++i) {
const Block *b1 = mBlocks[i];
const Block *b2 = aOther->mBlocks[i];
if (!b1 != !b2) {
return false;
}
if (!b1) {
continue;
}
if (memcmp(&b1->mBits, &b2->mBits, BLOCK_SIZE) != 0) {
return false;
}
}
return true;
}
bool test(PRUint32 aIndex) const { bool test(PRUint32 aIndex) const {
NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad"); NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS; PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
@ -321,6 +345,18 @@ public:
mBlocks.Compact(); mBlocks.Compact();
} }
PRUint32 GetChecksum() const {
PRUint32 check = adler32(0, Z_NULL, 0);
for (PRUint32 i = 0; i < mBlocks.Length(); i++) {
if (mBlocks[i]) {
const Block *block = mBlocks[i];
check = adler32(check, (PRUint8*) (&i), 4);
check = adler32(check, (PRUint8*) block, sizeof(Block));
}
}
return check;
}
private: private:
nsTArray< nsAutoPtr<Block> > mBlocks; nsTArray< nsAutoPtr<Block> > mBlocks;
}; };

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

@ -201,7 +201,7 @@ GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
: gfxFontEntry(aFaceName), : gfxFontEntry(aFaceName),
mWindowsFamily(0), mWindowsPitch(0), mWindowsFamily(0), mWindowsPitch(0),
mFontType(aFontType), mFontType(aFontType),
mForceGDI(false), mUnknownCMAP(false), mForceGDI(false),
mCharset(), mUnicodeRanges() mCharset(), mUnicodeRanges()
{ {
mUserFontData = aUserFontData; mUserFontData = aUserFontData;
@ -218,43 +218,62 @@ GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
nsresult nsresult
GDIFontEntry::ReadCMAP() GDIFontEntry::ReadCMAP()
{ {
// attempt this once, if errors occur leave a blank cmap
if (mCharacterMap) {
return NS_OK;
}
// skip non-SFNT fonts completely // skip non-SFNT fonts completely
if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE && if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE &&
mFontType != GFX_FONT_TYPE_TT_OPENTYPE && mFontType != GFX_FONT_TYPE_TT_OPENTYPE &&
mFontType != GFX_FONT_TYPE_TRUETYPE) mFontType != GFX_FONT_TYPE_TRUETYPE)
{ {
mCharacterMap = new gfxCharacterMap();
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
// attempt this once, if errors occur leave a blank cmap nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
if (mCmapInitialized)
return NS_OK;
mCmapInitialized = true;
const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p'); PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
AutoFallibleTArray<PRUint8,16384> buffer; nsresult rv;
if (GetFontTable(kCmapTag, buffer) != NS_OK)
return NS_ERROR_FAILURE;
PRUint8 *cmap = buffer.Elements();
bool unicodeFont = false, symbolFont = false; AutoFallibleTArray<PRUint8,16384> cmap;
nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(), rv = GetFontTable(kCMAP, cmap);
mCharacterMap, mUVSOffset,
unicodeFont, symbolFont); bool unicodeFont = false, symbolFont = false; // currently ignored
if (NS_SUCCEEDED(rv)) {
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
*charmap, mUVSOffset,
unicodeFont, symbolFont);
}
mSymbolFont = symbolFont; mSymbolFont = symbolFont;
mHasCmapTable = NS_SUCCEEDED(rv); mHasCmapTable = NS_SUCCEEDED(rv);
if (mHasCmapTable) {
gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
mCharacterMap = pfl->FindCharMap(charmap);
} else {
// if error occurred, initialize to null cmap
mCharacterMap = new gfxCharacterMap();
// For fonts where we failed to read the character map,
// we can take a slow path to look up glyphs character by character
mCharacterMap->mBuildOnTheFly = true;
}
#ifdef PR_LOGGING #ifdef PR_LOGGING
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
NS_ConvertUTF16toUTF8(mName).get(), NS_ConvertUTF16toUTF8(mName).get(),
mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of))); charmap->SizeOfIncludingThis(moz_malloc_size_of),
charmap->mHash, mCharacterMap == charmap ? " new" : ""));
if (LOG_CMAPDATA_ENABLED()) { if (LOG_CMAPDATA_ENABLED()) {
char prefix[256]; char prefix[256];
sprintf(prefix, "(cmapdata) name: %.220s", sprintf(prefix, "(cmapdata) name: %.220s",
NS_ConvertUTF16toUTF8(mName).get()); NS_ConvertUTF16toUTF8(mName).get());
mCharacterMap.Dump(prefix, eGfxLog_cmapdata); charmap->Dump(prefix, eGfxLog_cmapdata);
} }
#endif #endif
return rv; return rv;
} }
@ -346,13 +365,12 @@ GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
bool bool
GDIFontEntry::TestCharacterMap(PRUint32 aCh) GDIFontEntry::TestCharacterMap(PRUint32 aCh)
{ {
if (ReadCMAP() != NS_OK) { if (!mCharacterMap) {
// For fonts where we failed to read the character map, nsresult rv = ReadCMAP();
// we can take a slow path to look up glyphs character by character NS_ASSERTION(mCharacterMap, "failed to initialize a character map");
mUnknownCMAP = true;
} }
if (mUnknownCMAP) { if (mCharacterMap->mBuildOnTheFly) {
if (aCh > 0xFFFF) if (aCh > 0xFFFF)
return false; return false;
@ -404,12 +422,12 @@ GDIFontEntry::TestCharacterMap(PRUint32 aCh)
ReleaseDC(NULL, dc); ReleaseDC(NULL, dc);
if (hasGlyph) { if (hasGlyph) {
mCharacterMap.set(aCh); mCharacterMap->set(aCh);
return true; return true;
} }
} else { } else {
// font had a cmap so simply check that // font had a cmap so simply check that
return mCharacterMap.test(aCh); return mCharacterMap->test(aCh);
} }
return false; return false;

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

@ -293,7 +293,6 @@ public:
gfxWindowsFontType mFontType; gfxWindowsFontType mFontType;
bool mForceGDI : 1; bool mForceGDI : 1;
bool mUnknownCMAP : 1;
gfxSparseBitSet mCharset; gfxSparseBitSet mCharset;
gfxSparseBitSet mUnicodeRanges; gfxSparseBitSet mUnicodeRanges;

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

@ -189,93 +189,98 @@ nsresult
MacOSFontEntry::ReadCMAP() MacOSFontEntry::ReadCMAP()
{ {
// attempt this once, if errors occur leave a blank cmap // attempt this once, if errors occur leave a blank cmap
if (mCmapInitialized) { if (mCharacterMap) {
return NS_OK; return NS_OK;
} }
mCmapInitialized = true;
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p'); PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
nsresult rv;
AutoFallibleTArray<PRUint8,16384> cmap; AutoFallibleTArray<PRUint8,16384> cmap;
if (GetFontTable(kCMAP, cmap) != NS_OK) { rv = GetFontTable(kCMAP, cmap);
return NS_ERROR_FAILURE;
bool unicodeFont = false, symbolFont = false; // currently ignored
if (NS_SUCCEEDED(rv)) {
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
*charmap, mUVSOffset,
unicodeFont, symbolFont);
} }
bool unicodeFont, symbolFont; // currently ignored if (NS_SUCCEEDED(rv)) {
nsresult rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(), // for layout support, check for the presence of mort/morx and/or
mCharacterMap, mUVSOffset, // opentype layout tables
unicodeFont, symbolFont); bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m','o','r','x')) ||
if (NS_FAILED(rv)) { HasFontTable(TRUETYPE_TAG('m','o','r','t'));
mCharacterMap.reset(); bool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B'));
return rv; bool hasGPOS = HasFontTable(TRUETYPE_TAG('G','P','O','S'));
}
mHasCmapTable = true;
CGFontRef fontRef = GetFontRef(); if (hasAATLayout && !(hasGSUB || hasGPOS)) {
if (!fontRef) { mRequiresAAT = true; // prefer CoreText if font has no OTL tables
return NS_ERROR_FAILURE; }
}
// for layout support, check for the presence of mort/morx and/or PRUint32 numScripts =
// opentype layout tables sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m','o','r','x')) ||
HasFontTable(TRUETYPE_TAG('m','o','r','t'));
bool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B'));
bool hasGPOS = HasFontTable(TRUETYPE_TAG('G','P','O','S'));
if (hasAATLayout && !(hasGSUB || hasGPOS)) { for (PRUint32 s = 0; s < numScripts; s++) {
mRequiresAAT = true; // prefer CoreText if font has no OTL tables eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
}
PRUint32 numScripts = // check to see if the cmap includes complex script codepoints
sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange); if (charmap->TestRange(gScriptsThatRequireShaping[s].rangeStart,
gScriptsThatRequireShaping[s].rangeEnd)) {
bool omitRange = true;
for (PRUint32 s = 0; s < numScripts; s++) { if (hasAATLayout) {
eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
// check to see if the cmap includes complex script codepoints
if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart,
gScriptsThatRequireShaping[s].rangeEnd)) {
bool omitRange = true;
if (hasAATLayout) {
omitRange = false;
// prefer CoreText for Apple's complex-script fonts,
// even if they also have some OpenType tables
// (e.g. Geeza Pro Bold on 10.6; see bug 614903)
mRequiresAAT = true;
} else if (whichScript == eComplexScriptArabic) {
// special-case for Arabic:
// even if there's no morph table, CoreText can shape Arabic
// using OpenType layout; or if it's a downloaded font,
// assume the site knows what it's doing (as harfbuzz will
// be able to shape even though the font itself lacks tables
// stripped during sanitization).
// We check for GSUB here, as GPOS alone would not be ok
// for Arabic shaping.
if (hasGSUB || (mIsUserFont && !mIsLocalUserFont)) {
// TODO: to be really thorough, we could check that the
// GSUB table actually supports the 'arab' script tag.
omitRange = false; omitRange = false;
// prefer CoreText for Apple's complex-script fonts,
// even if they also have some OpenType tables
// (e.g. Geeza Pro Bold on 10.6; see bug 614903)
mRequiresAAT = true;
} else if (whichScript == eComplexScriptArabic) {
// special-case for Arabic:
// even if there's no morph table, CoreText can shape Arabic
// using OpenType layout; or if it's a downloaded font,
// assume the site knows what it's doing (as harfbuzz will
// be able to shape even though the font itself lacks tables
// stripped during sanitization).
// We check for GSUB here, as GPOS alone would not be ok
// for Arabic shaping.
if (hasGSUB || (mIsUserFont && !mIsLocalUserFont)) {
// TODO: to be really thorough, we could check that the
// GSUB table actually supports the 'arab' script tag.
omitRange = false;
}
} }
}
if (omitRange) { if (omitRange) {
mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, charmap->ClearRange(gScriptsThatRequireShaping[s].rangeStart,
gScriptsThatRequireShaping[s].rangeEnd); gScriptsThatRequireShaping[s].rangeEnd);
}
} }
} }
} }
mHasCmapTable = NS_SUCCEEDED(rv);
if (mHasCmapTable) {
gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
mCharacterMap = pfl->FindCharMap(charmap);
} else {
// if error occurred, initialize to null cmap
mCharacterMap = new gfxCharacterMap();
}
#ifdef PR_LOGGING #ifdef PR_LOGGING
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
NS_ConvertUTF16toUTF8(mName).get(), NS_ConvertUTF16toUTF8(mName).get(),
mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of))); charmap->SizeOfIncludingThis(moz_malloc_size_of),
charmap->mHash, mCharacterMap == charmap ? " new" : ""));
if (LOG_CMAPDATA_ENABLED()) { if (LOG_CMAPDATA_ENABLED()) {
char prefix[256]; char prefix[256];
sprintf(prefix, "(cmapdata) name: %.220s", sprintf(prefix, "(cmapdata) name: %.220s",
NS_ConvertUTF16toUTF8(mName).get()); NS_ConvertUTF16toUTF8(mName).get());
mCharacterMap.Dump(prefix, eGfxLog_cmapdata); charmap->Dump(prefix, eGfxLog_cmapdata);
} }
#endif #endif

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

@ -213,10 +213,13 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
gFontListPrefObserver = new gfxFontListPrefObserver(); gFontListPrefObserver = new gfxFontListPrefObserver();
NS_ADDREF(gFontListPrefObserver); NS_ADDREF(gFontListPrefObserver);
Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs); Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
mSharedCmaps.Init(16);
} }
gfxPlatformFontList::~gfxPlatformFontList() gfxPlatformFontList::~gfxPlatformFontList()
{ {
mSharedCmaps.Clear();
NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer"); NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs); Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
NS_RELEASE(gFontListPrefObserver); NS_RELEASE(gFontListPrefObserver);
@ -714,6 +717,41 @@ gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString
return !aFamilyName.IsEmpty(); return !aFamilyName.IsEmpty();
} }
gfxCharacterMap*
gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
{
aCmap->CalcHash();
gfxCharacterMap *cmap = AddCmap(aCmap);
cmap->mShared = true;
return cmap;
}
// add a cmap to the shared cmap set
gfxCharacterMap*
gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap)
{
CharMapHashKey *found =
mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
return found->GetKey();
}
// remove the cmap from the shared cmap set
void
gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
{
// skip lookups during teardown
if (mSharedCmaps.Count() == 0) {
return;
}
// cmap needs to match the entry *and* be the same ptr before removing
CharMapHashKey *found =
mSharedCmaps.GetEntry(const_cast<gfxCharacterMap*>(aCharMap));
if (found && found->GetKey() == aCharMap) {
mSharedCmaps.RemoveEntry(const_cast<gfxCharacterMap*>(aCharMap));
}
}
void void
gfxPlatformFontList::InitLoader() gfxPlatformFontList::InitLoader()
{ {
@ -830,6 +868,21 @@ SizeOfStringEntryExcludingThis(nsStringHashKey* aHashEntry,
return aHashEntry->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf); return aHashEntry->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
} }
static size_t
SizeOfSharedCmapExcludingThis(CharMapHashKey* aHashEntry,
nsMallocSizeOfFun aMallocSizeOf,
void* aUserArg)
{
FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
PRUint32 size = aHashEntry->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
sizes->mCharMapsSize += size;
// we return zero here because the measurements have been added directly
// to the relevant fields of the FontListSizes record
return 0;
}
void void
gfxPlatformFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf, gfxPlatformFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontListSizes* aSizes) const FontListSizes* aSizes) const
@ -865,6 +918,10 @@ gfxPlatformFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
aSizes->mFontListSize += aSizes->mFontListSize +=
mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis, mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis,
aMallocSizeOf); aMallocSizeOf);
aSizes->mFontListSize +=
mSharedCmaps.SizeOfExcludingThis(SizeOfSharedCmapExcludingThis,
aMallocSizeOf, aSizes);
} }
void void

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

@ -50,6 +50,53 @@
#include "nsIMemoryReporter.h" #include "nsIMemoryReporter.h"
#include "mozilla/FunctionTimer.h" #include "mozilla/FunctionTimer.h"
class CharMapHashKey : public PLDHashEntryHdr
{
public:
typedef gfxCharacterMap* KeyType;
typedef const gfxCharacterMap* KeyTypePointer;
CharMapHashKey(const gfxCharacterMap *aCharMap) :
mCharMap(const_cast<gfxCharacterMap*>(aCharMap))
{
MOZ_COUNT_CTOR(CharMapHashKey);
}
CharMapHashKey(const CharMapHashKey& toCopy) :
mCharMap(toCopy.mCharMap)
{
MOZ_COUNT_CTOR(CharMapHashKey);
}
~CharMapHashKey()
{
MOZ_COUNT_DTOR(CharMapHashKey);
}
gfxCharacterMap* GetKey() const { return mCharMap; }
bool KeyEquals(const gfxCharacterMap *aCharMap) const {
NS_ASSERTION(!aCharMap->mBuildOnTheFly && !mCharMap->mBuildOnTheFly,
"custom cmap used in shared cmap hashtable");
// cmaps built on the fly never match
if (aCharMap->mHash != mCharMap->mHash)
{
return false;
}
return mCharMap->Equals(aCharMap);
}
static const gfxCharacterMap* KeyToPointer(gfxCharacterMap *aCharMap) {
return aCharMap;
}
static PLDHashNumber HashKey(const gfxCharacterMap *aCharMap) {
return aCharMap->mHash;
}
enum { ALLOW_MEMMOVE = true };
protected:
gfxCharacterMap *mCharMap;
};
// gfxPlatformFontList is an abstract class for the global font list on the system; // gfxPlatformFontList is an abstract class for the global font list on the system;
// concrete subclasses for each platform implement the actual interface to the system fonts. // concrete subclasses for each platform implement the actual interface to the system fonts.
// This class exists because we cannot rely on the platform font-finding APIs to behave // This class exists because we cannot rely on the platform font-finding APIs to behave
@ -155,6 +202,16 @@ public:
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf, virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontListSizes* aSizes) const; FontListSizes* aSizes) const;
// search for existing cmap that matches the input
// return the input if no match is found
gfxCharacterMap* FindCharMap(gfxCharacterMap *aCmap);
// add a cmap to the shared cmap set
gfxCharacterMap* AddCmap(const gfxCharacterMap *aCharMap);
// remove the cmap from the shared cmap set
void RemoveCmap(const gfxCharacterMap *aCharMap);
protected: protected:
class MemoryReporter class MemoryReporter
: public nsIMemoryMultiReporter : public nsIMemoryMultiReporter
@ -264,6 +321,10 @@ protected:
nsTHashtable<nsStringHashKey> mBadUnderlineFamilyNames; nsTHashtable<nsStringHashKey> mBadUnderlineFamilyNames;
// character map data shared across families
// contains weak ptrs to cmaps shared by font entry objects
nsTHashtable<CharMapHashKey> mSharedCmaps;
// data used as part of the font cmap loading process // data used as part of the font cmap loading process
nsTArray<nsRefPtr<gfxFontFamily> > mFontFamiliesToLoad; nsTArray<nsRefPtr<gfxFontFamily> > mFontFamiliesToLoad;
PRUint32 mStartIndex; PRUint32 mStartIndex;