bug 668813 pt 2 - maintain a character coverage map for gfxFontFamily. r=jdaggett

This commit is contained in:
Jonathan Kew 2011-08-09 09:06:01 +01:00
parent cf6ef49886
commit 3468d6f6ed
5 changed files with 81 additions and 24 deletions

View File

@ -651,12 +651,15 @@ void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
void
gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
{
if (!mHasStyles)
if (!mHasStyles) {
FindStyleVariations();
}
// xxx - optimization point - keep a bit vector with the union of supported unicode ranges
// by all fonts for this family and bail immediately if the character is not in any of
// this family's cmaps
if (!TestCharacterMap(aMatchData->mCh)) {
// none of the faces in the family support the required char,
// so bail out immediately
return;
}
// iterate over fonts
PRUint32 numFonts = mAvailableFonts.Length();
@ -2611,11 +2614,8 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
return font.forget();
}
// check other faces of the family
// XXX optimization point: give the family a charmap that is the union
// of the char maps of all its faces, so we can quickly test whether
// it's worth doing this search
gfxFontFamily *family = font->GetFontEntry()->Family();
if (family) {
if (family && family->TestCharacterMap(aCh)) {
FontSearch matchData(aCh, font);
family->FindFontForChar(&matchData);
gfxFontEntry *fe = matchData.mBestMatch;

View File

@ -482,7 +482,8 @@ public:
mFaceNamesInitialized(PR_FALSE),
mHasStyles(PR_FALSE),
mIsSimpleFamily(PR_FALSE),
mIsBadUnderlineFamily(PR_FALSE)
mIsBadUnderlineFamily(PR_FALSE),
mCharacterMapInitialized(PR_FALSE)
{ }
virtual ~gfxFontFamily() { }
@ -544,10 +545,28 @@ public:
// read in cmaps for all the faces
void ReadCMAP() {
PRUint32 i, numFonts = mAvailableFonts.Length();
// called from RunLoader BEFORE CheckForSimpleFamily so that there cannot
// be any NULL entries in mAvailableFonts
for (i = 0; i < numFonts; i++)
mAvailableFonts[i]->ReadCMAP();
for (i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
if (!fe) {
continue;
}
fe->ReadCMAP();
mCharacterMap.Union(fe->mCharacterMap);
}
mCharacterMap.Compact();
mCharacterMapInitialized = PR_TRUE;
}
PRBool TestCharacterMap(PRUint32 aCh) {
if (!mCharacterMapInitialized) {
ReadCMAP();
}
return mCharacterMap.test(aCh);
}
void ResetCharacterMap() {
mCharacterMap.reset();
mCharacterMapInitialized = PR_FALSE;
}
// mark this family as being in the "bad" underline offset blacklist
@ -590,12 +609,14 @@ protected:
nsString mName;
nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
gfxSparseBitSet mCharacterMap;
PRPackedBool mOtherFamilyNamesInitialized;
PRPackedBool mHasOtherFamilyNames;
PRPackedBool mFaceNamesInitialized;
PRPackedBool mHasStyles;
PRPackedBool mIsSimpleFamily;
PRPackedBool mIsBadUnderlineFamily;
PRPackedBool mCharacterMapInitialized;
enum {
// for "simple" families, the faces are stored in mAvailableFonts

View File

@ -313,7 +313,7 @@ gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
prevEndCharCode = endCharCode;
}
aCharacterMap.mBlocks.Compact();
aCharacterMap.Compact();
return NS_OK;
}
@ -391,7 +391,7 @@ gfxFontUtils::ReadCMAPTableFormat4(const PRUint8 *aBuf, PRUint32 aLength,
}
}
aCharacterMap.mBlocks.Compact();
aCharacterMap.Compact();
return NS_OK;
}

View File

@ -165,8 +165,6 @@ public:
Block *block = mBlocks[blockIndex];
if (!block) {
block = new Block;
if (NS_UNLIKELY(!block)) // OOM
return;
mBlocks[blockIndex] = block;
}
block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
@ -201,9 +199,6 @@ public:
fullBlock = PR_TRUE;
block = new Block(fullBlock ? 0xFF : 0);
if (NS_UNLIKELY(!block)) // OOM
return;
mBlocks[i] = block;
if (fullBlock)
@ -279,7 +274,44 @@ public:
for (i = 0; i < mBlocks.Length(); i++)
mBlocks[i] = nsnull;
}
// set this bitset to the union of its current contents and another
void Union(const gfxSparseBitSet& aBitset) {
// ensure mBlocks is large enough
PRUint32 blockCount = aBitset.mBlocks.Length();
if (blockCount > mBlocks.Length()) {
PRUint32 needed = blockCount - mBlocks.Length();
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(needed);
if (NS_UNLIKELY(!blocks)) { // OOM
return;
}
}
// for each block that may be present in aBitset...
for (PRUint32 i = 0; i < blockCount; ++i) {
// if it is missing (implicitly empty), just skip
if (!aBitset.mBlocks[i]) {
continue;
}
// if the block is missing in this set, just copy the other
if (!mBlocks[i]) {
mBlocks[i] = new Block(*aBitset.mBlocks[i]);
continue;
}
// else set existing block to the union of both
PRUint32 *dst = reinterpret_cast<PRUint32*>(mBlocks[i]->mBits);
const PRUint32 *src =
reinterpret_cast<const PRUint32*>(aBitset.mBlocks[i]->mBits);
for (PRUint32 j = 0; j < BLOCK_SIZE / 4; ++j) {
dst[j] |= src[j];
}
}
}
void Compact() {
mBlocks.Compact();
}
private:
nsTArray< nsAutoPtr<Block> > mBlocks;
};

View File

@ -106,10 +106,12 @@ public:
virtual ~gfxMixedFontFamily() { }
void AddFontEntry(gfxFontEntry *aFontEntry) {
void AddFontEntry(gfxFontEntry *aFontEntry)
{
nsRefPtr<gfxFontEntry> fe = aFontEntry;
mAvailableFonts.AppendElement(fe);
aFontEntry->SetFamily(this);
ResetCharacterMap();
}
void ReplaceFontEntry(gfxFontEntry *aOldFontEntry, gfxFontEntry *aNewFontEntry)
@ -123,9 +125,10 @@ public:
// other reference to it except from its family
mAvailableFonts[i] = aNewFontEntry;
aNewFontEntry->SetFamily(this);
return;
break;
}
}
ResetCharacterMap();
}
void RemoveFontEntry(gfxFontEntry *aFontEntry)
@ -136,9 +139,10 @@ public:
if (fe == aFontEntry) {
aFontEntry->SetFamily(nsnull);
mAvailableFonts.RemoveElementAt(i);
return;
break;
}
}
ResetCharacterMap();
}
// temp method to determine if all proxies are loaded