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 636a871edd
commit 777cd62f11
5 changed files with 82 additions and 27 deletions

View File

@ -692,12 +692,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();
@ -3366,11 +3369,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

@ -510,7 +510,8 @@ public:
mFaceNamesInitialized(false),
mHasStyles(false),
mIsSimpleFamily(false),
mIsBadUnderlineFamily(false)
mIsBadUnderlineFamily(false),
mCharacterMapInitialized(false)
{ }
virtual ~gfxFontFamily() {
@ -583,10 +584,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 = true;
}
bool TestCharacterMap(PRUint32 aCh) {
if (!mCharacterMapInitialized) {
ReadCMAP();
}
return mCharacterMap.test(aCh);
}
void ResetCharacterMap() {
mCharacterMap.reset();
mCharacterMapInitialized = false;
}
// mark this family as being in the "bad" underline offset blacklist
@ -629,12 +648,14 @@ protected:
nsString mName;
nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
gfxSparseBitSet mCharacterMap;
bool mOtherFamilyNamesInitialized;
bool mHasOtherFamilyNames;
bool mFaceNamesInitialized;
bool mHasStyles;
bool mIsSimpleFamily;
bool mIsBadUnderlineFamily;
bool mCharacterMapInitialized;
enum {
// for "simple" families, the faces are stored in mAvailableFonts

View File

@ -315,7 +315,7 @@ gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
prevEndCharCode = endCharCode;
}
aCharacterMap.mBlocks.Compact();
aCharacterMap.Compact();
return NS_OK;
}
@ -395,7 +395,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 = 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

@ -110,10 +110,11 @@ public:
nsRefPtr<gfxFontEntry> fe = aFontEntry;
mAvailableFonts.AppendElement(fe);
aFontEntry->SetFamily(this);
ResetCharacterMap();
}
void ReplaceFontEntry(gfxFontEntry *aOldFontEntry, gfxFontEntry *aNewFontEntry)
{
void ReplaceFontEntry(gfxFontEntry *aOldFontEntry,
gfxFontEntry *aNewFontEntry) {
PRUint32 numFonts = mAvailableFonts.Length();
for (PRUint32 i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
@ -123,22 +124,23 @@ public:
// other reference to it except from its family
mAvailableFonts[i] = aNewFontEntry;
aNewFontEntry->SetFamily(this);
return;
break;
}
}
ResetCharacterMap();
}
void RemoveFontEntry(gfxFontEntry *aFontEntry)
{
void RemoveFontEntry(gfxFontEntry *aFontEntry) {
PRUint32 numFonts = mAvailableFonts.Length();
for (PRUint32 i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
if (fe == aFontEntry) {
aFontEntry->SetFamily(nsnull);
mAvailableFonts.RemoveElementAt(i);
return;
break;
}
}
ResetCharacterMap();
}
// clear family pointer for all entries and remove them from the family;