mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 710727. Share cmaps across all fonts. r=jkew, a=tracking-firefox
This commit is contained in:
parent
12b6a3abbd
commit
ed5cb19215
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -293,7 +293,6 @@ public:
|
||||
|
||||
gfxWindowsFontType mFontType;
|
||||
bool mForceGDI : 1;
|
||||
bool mUnknownCMAP : 1;
|
||||
|
||||
gfxSparseBitSet mCharset;
|
||||
gfxSparseBitSet mUnicodeRanges;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user