From 3468d6f6ed6c0427941af341b2209277cc4425ed Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 9 Aug 2011 09:06:01 +0100 Subject: [PATCH] bug 668813 pt 2 - maintain a character coverage map for gfxFontFamily. r=jdaggett --- gfx/thebes/gfxFont.cpp | 16 +++++++------- gfx/thebes/gfxFont.h | 31 +++++++++++++++++++++----- gfx/thebes/gfxFontUtils.cpp | 4 ++-- gfx/thebes/gfxFontUtils.h | 44 ++++++++++++++++++++++++++++++++----- gfx/thebes/gfxUserFontSet.h | 10 ++++++--- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 46ea71bc405..ac28b38f8b0 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -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; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 3a8b1e19fdf..a62c02ba0d0 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -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 > 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 diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp index 456d404bb5e..6f453910b6a 100644 --- a/gfx/thebes/gfxFontUtils.cpp +++ b/gfx/thebes/gfxFontUtils.cpp @@ -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; } diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h index c3c542bd9df..6e3132dd2b9 100644 --- a/gfx/thebes/gfxFontUtils.h +++ b/gfx/thebes/gfxFontUtils.h @@ -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 *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(mBlocks[i]->mBits); + const PRUint32 *src = + reinterpret_cast(aBitset.mBlocks[i]->mBits); + for (PRUint32 j = 0; j < BLOCK_SIZE / 4; ++j) { + dst[j] |= src[j]; + } + } + } + + void Compact() { + mBlocks.Compact(); + } + +private: nsTArray< nsAutoPtr > mBlocks; }; diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 4455263e478..2fe08207949 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -106,10 +106,12 @@ public: virtual ~gfxMixedFontFamily() { } - void AddFontEntry(gfxFontEntry *aFontEntry) { + void AddFontEntry(gfxFontEntry *aFontEntry) + { nsRefPtr 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