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
parent 12b6a3abbd
commit ed5cb19215
10 changed files with 434 additions and 189 deletions

View File

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

View File

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

View File

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

View File

@ -198,6 +198,56 @@ struct THEBES_API gfxFontStyle {
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 {
public:
NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
@ -216,7 +266,6 @@ public:
mCheckedForGraphiteTables(false),
#endif
mHasCmapTable(false),
mCmapInitialized(false),
mUVSOffset(0), mUVSData(nsnull),
mUserFontData(nsnull),
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
@ -259,16 +308,17 @@ public:
#endif
inline bool HasCmapTable() {
if (!mCmapInitialized) {
if (!mCharacterMap) {
ReadCMAP();
NS_ASSERTION(mCharacterMap, "failed to initialize character map");
}
return mHasCmapTable;
}
inline bool HasCharacter(PRUint32 ch) {
if (mCharacterMap.test(ch))
if (mCharacterMap && mCharacterMap->test(ch)) {
return true;
}
return TestCharacterMap(ch);
}
@ -344,8 +394,7 @@ public:
bool mCheckedForGraphiteTables;
#endif
bool mHasCmapTable;
bool mCmapInitialized;
gfxSparseBitSet mCharacterMap;
nsRefPtr<gfxCharacterMap> mCharacterMap;
PRUint32 mUVSOffset;
nsAutoArrayPtr<PRUint8> mUVSData;
gfxUserFontData* mUserFontData;
@ -375,7 +424,6 @@ protected:
mCheckedForGraphiteTables(false),
#endif
mHasCmapTable(false),
mCmapInitialized(false),
mUVSOffset(0), mUVSData(nsnull),
mUserFontData(nsnull),
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
@ -529,7 +577,7 @@ public:
mHasStyles(false),
mIsSimpleFamily(false),
mIsBadUnderlineFamily(false),
mCharacterMapInitialized(false)
mFamilyCharacterMapInitialized(false)
{ }
virtual ~gfxFontFamily() {
@ -607,26 +655,27 @@ public:
PRUint32 i, numFonts = mAvailableFonts.Length();
for (i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
if (!fe) {
// don't try to load cmaps for downloadable fonts not yet loaded
if (!fe || fe->mIsProxy) {
continue;
}
fe->ReadCMAP();
mCharacterMap.Union(fe->mCharacterMap);
mFamilyCharacterMap.Union(*(fe->mCharacterMap));
}
mCharacterMap.Compact();
mCharacterMapInitialized = true;
mFamilyCharacterMap.Compact();
mFamilyCharacterMapInitialized = true;
}
bool TestCharacterMap(PRUint32 aCh) {
if (!mCharacterMapInitialized) {
if (!mFamilyCharacterMapInitialized) {
ReadAllCMAPs();
}
return mCharacterMap.test(aCh);
return mFamilyCharacterMap.test(aCh);
}
void ResetCharacterMap() {
mCharacterMap.reset();
mCharacterMapInitialized = false;
mFamilyCharacterMap.reset();
mFamilyCharacterMapInitialized = false;
}
// mark this family as being in the "bad" underline offset blacklist
@ -675,14 +724,14 @@ protected:
nsString mName;
nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
gfxSparseBitSet mCharacterMap;
bool mOtherFamilyNamesInitialized;
bool mHasOtherFamilyNames;
bool mFaceNamesInitialized;
bool mHasStyles;
bool mIsSimpleFamily;
bool mIsBadUnderlineFamily;
bool mCharacterMapInitialized;
gfxSparseBitSet mFamilyCharacterMap;
bool mOtherFamilyNamesInitialized : 1;
bool mHasOtherFamilyNames : 1;
bool mFaceNamesInitialized : 1;
bool mHasStyles : 1;
bool mIsSimpleFamily : 1;
bool mIsBadUnderlineFamily : 1;
bool mFamilyCharacterMapInitialized : 1;
enum {
// for "simple" families, the faces are stored in mAvailableFonts

View File

@ -58,6 +58,8 @@
#include "nsAutoPtr.h"
#include "nsIStreamBufferAccess.h"
#include "zlib.h"
/* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
#ifdef __MINGW32__
#undef min
@ -87,6 +89,28 @@ public:
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 {
NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
@ -321,6 +345,18 @@ public:
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:
nsTArray< nsAutoPtr<Block> > mBlocks;
};

View File

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

View File

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

View File

@ -189,93 +189,98 @@ nsresult
MacOSFontEntry::ReadCMAP()
{
// attempt this once, if errors occur leave a blank cmap
if (mCmapInitialized) {
if (mCharacterMap) {
return NS_OK;
}
mCmapInitialized = true;
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
nsresult rv;
AutoFallibleTArray<PRUint8,16384> cmap;
if (GetFontTable(kCMAP, cmap) != NS_OK) {
return NS_ERROR_FAILURE;
rv = GetFontTable(kCMAP, cmap);
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
nsresult rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
mCharacterMap, mUVSOffset,
unicodeFont, symbolFont);
if (NS_FAILED(rv)) {
mCharacterMap.reset();
return rv;
}
mHasCmapTable = true;
CGFontRef fontRef = GetFontRef();
if (!fontRef) {
return NS_ERROR_FAILURE;
}
// for layout support, check for the presence of mort/morx and/or
// opentype layout tables
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)) {
mRequiresAAT = true; // prefer CoreText if font has no OTL tables
}
PRUint32 numScripts =
sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
for (PRUint32 s = 0; s < numScripts; s++) {
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.
if (NS_SUCCEEDED(rv)) {
// for layout support, check for the presence of mort/morx and/or
// opentype layout tables
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)) {
mRequiresAAT = true; // prefer CoreText if font has no OTL tables
}
PRUint32 numScripts =
sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
for (PRUint32 s = 0; s < numScripts; s++) {
eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
// check to see if the cmap includes complex script codepoints
if (charmap->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;
}
}
if (omitRange) {
charmap->ClearRange(gScriptsThatRequireShaping[s].rangeStart,
gScriptsThatRequireShaping[s].rangeEnd);
}
}
if (omitRange) {
mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart,
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
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(),
mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of)));
charmap->SizeOfIncludingThis(moz_malloc_size_of),
charmap->mHash, mCharacterMap == charmap ? " new" : ""));
if (LOG_CMAPDATA_ENABLED()) {
char prefix[256];
sprintf(prefix, "(cmapdata) name: %.220s",
NS_ConvertUTF16toUTF8(mName).get());
mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
charmap->Dump(prefix, eGfxLog_cmapdata);
}
#endif

View File

@ -213,10 +213,13 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
gFontListPrefObserver = new gfxFontListPrefObserver();
NS_ADDREF(gFontListPrefObserver);
Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
mSharedCmaps.Init(16);
}
gfxPlatformFontList::~gfxPlatformFontList()
{
mSharedCmaps.Clear();
NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
NS_RELEASE(gFontListPrefObserver);
@ -714,6 +717,41 @@ gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString
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
gfxPlatformFontList::InitLoader()
{
@ -830,6 +868,21 @@ SizeOfStringEntryExcludingThis(nsStringHashKey* aHashEntry,
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
gfxPlatformFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontListSizes* aSizes) const
@ -865,6 +918,10 @@ gfxPlatformFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
aSizes->mFontListSize +=
mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis,
aMallocSizeOf);
aSizes->mFontListSize +=
mSharedCmaps.SizeOfExcludingThis(SizeOfSharedCmapExcludingThis,
aMallocSizeOf, aSizes);
}
void

View File

@ -50,6 +50,53 @@
#include "nsIMemoryReporter.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;
// 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
@ -155,6 +202,16 @@ public:
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
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:
class MemoryReporter
: public nsIMemoryMultiReporter
@ -264,6 +321,10 @@ protected:
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
nsTArray<nsRefPtr<gfxFontFamily> > mFontFamiliesToLoad;
PRUint32 mStartIndex;