Bug 998869 part 1 - build fontlist more lazily (non-linux). r=jfkthame

This commit is contained in:
John Daggett 2014-09-25 12:16:52 +09:00
parent 2a28d6d5eb
commit 938b6ce42d
2 changed files with 189 additions and 79 deletions

View File

@ -1627,11 +1627,7 @@ gfxFontGroup::BuildFontList()
gfxFontEntry *fe = defaultFamily->FindFontForStyle(mStyle,
needsBold);
if (fe) {
nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
needsBold);
if (font) {
mFonts.AppendElement(FamilyFace(defaultFamily, font));
}
mFonts.AppendElement(FamilyFace(defaultFamily, fe, needsBold));
}
}
@ -1648,12 +1644,7 @@ gfxFontGroup::BuildFontList()
gfxFontEntry *fe = families[i]->FindFontForStyle(mStyle,
needsBold);
if (fe) {
nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
needsBold);
if (font) {
mFonts.AppendElement(FamilyFace(families[i], font));
break;
}
mFonts.AppendElement(FamilyFace(families[i], fe, needsBold));
}
}
}
@ -1670,18 +1661,19 @@ gfxFontGroup::BuildFontList()
}
}
if (!mStyle.systemFont) {
uint32_t count = mFonts.Length();
for (uint32_t i = 0; i < count; ++i) {
gfxFont* font = mFonts[i].Font();
if (font->GetFontEntry()->mIsBadUnderlineFont) {
gfxFloat first = mFonts[0].Font()->GetMetrics().underlineOffset;
gfxFloat bad = font->GetMetrics().underlineOffset;
mUnderlineOffset = std::min(first, bad);
break;
}
}
}
// xxx comment this out for now
// if (!mStyle.systemFont) {
// uint32_t count = mFonts.Length();
// for (uint32_t i = 0; i < count; ++i) {
// gfxFont* font = mFonts[i].Font();
// if (font->GetFontEntry()->mIsBadUnderlineFont) {
// gfxFloat first = mFonts[0].Font()->GetMetrics().underlineOffset;
// gfxFloat bad = font->GetMetrics().underlineOffset;
// mUnderlineOffset = std::min(first, bad);
// break;
// }
// }
// }
#endif
}
@ -1730,10 +1722,7 @@ gfxFontGroup::FindPlatformFont(const nsAString& aName,
// add to the font group, unless it's already there
if (fe && !HasFont(fe)) {
nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
if (font) {
mFonts.AppendElement(FamilyFace(family, font));
}
mFonts.AppendElement(FamilyFace(family, fe, needsBold));
}
}
@ -1742,8 +1731,9 @@ gfxFontGroup::HasFont(const gfxFontEntry *aFontEntry)
{
uint32_t count = mFonts.Length();
for (uint32_t i = 0; i < count; ++i) {
if (mFonts[i].Font()->GetFontEntry() == aFontEntry)
if (mFonts[i].FontEntry() == aFontEntry) {
return true;
}
}
return false;
}
@ -2376,24 +2366,27 @@ gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
}
already_AddRefed<gfxFont>
gfxFontGroup::TryAllFamilyMembers(gfxFontFamily* aFamily, uint32_t aCh)
gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
{
NS_ASSERTION(mStyle.style != NS_FONT_STYLE_NORMAL,
"should only be called in the italic/oblique case");
if (!aFamily->TestCharacterMap(aCh)) {
return nullptr;
}
// Note that we don't need the actual runScript in matchData for
// gfxFontFamily::SearchAllFontsForChar, it's only used for the
// system-fallback case. So we can just set it to 0 here.
GlobalFontMatch matchData(aCh, 0, &mStyle);
aFamily->SearchAllFontsForChar(&matchData);
gfxFontEntry *fe = matchData.mBestMatch;
if (!fe) {
gfxFontStyle regularStyle = mStyle;
regularStyle.style = NS_FONT_STYLE_NORMAL;
bool needsBold;
gfxFontEntry *fe = aFamily->FindFontForStyle(regularStyle, needsBold);
if (!fe->HasCharacter(aCh)) {
return nullptr;
}
bool needsBold = mStyle.weight >= 600 && !fe->IsBold();
nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
if (!font->Valid()) {
return nullptr;
}
return font.forget();
}
@ -2410,18 +2403,24 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
bool isVarSelector = gfxFontUtils::IsVarSelector(aCh);
if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
nsRefPtr<gfxFont> firstFont = mFonts[0].Font();
nsRefPtr<gfxFont> firstFont = GetFontAt(0);
if (firstFont->HasCharacter(aCh)) {
*aMatchType = gfxTextRange::kFontGroup;
return firstFont.forget();
}
// It's possible that another font in the family (e.g. regular face,
// where the requested style was italic) will support the character
nsRefPtr<gfxFont> font = TryAllFamilyMembers(mFonts[0].Family(), aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
// If italic, test the regular face to see if it supports the character.
// Only do this for platform fonts, not userfonts.
if (mStyle.style != NS_FONT_STYLE_NORMAL &&
!firstFont->GetFontEntry()->IsUserFont()) {
nsRefPtr<gfxFont> font =
FindNonItalicFaceForChar(mFonts[0].Family(), aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
}
}
// we don't need to check the first font again below
++nextIndex;
}
@ -2461,16 +2460,30 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
// 1. check remaining fonts in the font group
uint32_t fontListLength = FontListLength();
for (uint32_t i = nextIndex; i < fontListLength; i++) {
nsRefPtr<gfxFont> font = mFonts[i].Font();
if (font->HasCharacter(aCh)) {
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
nsRefPtr<gfxFont> font;
// test the font entry, build font if needed
gfxFontEntry *fe = mFonts[i].FontEntry();
if (fe->HasCharacter(aCh)) {
font = mFonts[i].Font();
if (!font) {
font = fe->FindOrMakeFont(&mStyle, mFonts[i].NeedsBold());
mFonts[i].SetFont(font);
}
if (font->Valid()) {
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
}
}
font = TryAllFamilyMembers(mFonts[i].Family(), aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
// If italic, test the regular face to see if it supports the character.
// Only do this for platform fonts, not userfonts.
if (mStyle.style != NS_FONT_STYLE_NORMAL && !fe->IsUserFont()) {
font = FindNonItalicFaceForChar(mFonts[i].Family(), aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
}
}
}

View File

@ -723,27 +723,6 @@ private:
class gfxFontGroup : public gfxTextRunFactory {
public:
class FamilyFace {
public:
FamilyFace() { }
FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
: mFamily(aFamily), mFont(aFont)
{
NS_ASSERTION(aFont, "font pointer must not be null");
NS_ASSERTION(!aFamily ||
aFamily->ContainsFace(aFont->GetFontEntry()),
"font is not a member of the given family");
}
gfxFontFamily* Family() const { return mFamily.get(); }
gfxFont* Font() const { return mFont.get(); }
private:
nsRefPtr<gfxFontFamily> mFamily;
nsRefPtr<gfxFont> mFont;
};
static void Shutdown(); // platform must call this to release the languageAtomService
gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
@ -760,10 +739,17 @@ public:
NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
"Whoever was caching this font group should have "
"called UpdateFontList on it");
NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(),
NS_ASSERTION(mFonts.Length() > uint32_t(i) &&
(mFonts[i].Font() || mFonts[i].FontEntry()),
"Requesting a font index that doesn't exist");
return mFonts[i].Font();
nsRefPtr<gfxFont> font = mFonts[i].Font();
if (!font) {
gfxFontEntry *fe = mFonts[i].FontEntry();
font = fe->FindOrMakeFont(&mStyle, mFonts[i].NeedsBold());
mFonts[i].SetFont(font);
}
return font.get();
}
// Returns the first font in the font-group that has an OpenType MATH table,
@ -913,6 +899,116 @@ public:
nsTArray<nsString>& aGenericFamilies);
protected:
class FamilyFace {
public:
FamilyFace() : mFamily(nullptr), mFontEntry(nullptr),
mNeedsBold(false), mFontCreated(false)
{ }
FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
: mFamily(aFamily), mNeedsBold(false), mFontCreated(true)
{
NS_ASSERTION(aFont, "font pointer must not be null");
NS_ASSERTION(!aFamily ||
aFamily->ContainsFace(aFont->GetFontEntry()),
"font is not a member of the given family");
mFont = aFont;
NS_ADDREF(aFont);
}
FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry,
bool aNeedsBold)
: mFamily(aFamily), mNeedsBold(aNeedsBold), mFontCreated(false)
{
NS_ASSERTION(aFontEntry, "font entry pointer must not be null");
NS_ASSERTION(!aFamily ||
aFamily->ContainsFace(aFontEntry),
"font is not a member of the given family");
mFontEntry = aFontEntry;
NS_ADDREF(aFontEntry);
}
FamilyFace(const FamilyFace& aOtherFamilyFace)
: mFamily(aOtherFamilyFace.mFamily),
mNeedsBold(aOtherFamilyFace.mNeedsBold),
mFontCreated(aOtherFamilyFace.mFontCreated)
{
if (mFontCreated) {
mFont = aOtherFamilyFace.mFont;
NS_ADDREF(mFont);
} else {
mFontEntry = aOtherFamilyFace.mFontEntry;
NS_IF_ADDREF(mFontEntry);
}
}
~FamilyFace()
{
if (mFontCreated) {
NS_RELEASE(mFont);
} else {
NS_IF_RELEASE(mFontEntry);
}
}
FamilyFace& operator=(const FamilyFace& aOther)
{
if (mFontCreated) {
NS_RELEASE(mFont);
} else {
NS_IF_RELEASE(mFontEntry);
}
mFamily = aOther.mFamily;
mNeedsBold = aOther.mNeedsBold;
mFontCreated = aOther.mFontCreated;
if (mFontCreated) {
mFont = aOther.mFont;
NS_ADDREF(mFont);
} else {
mFontEntry = aOther.mFontEntry;
NS_IF_ADDREF(mFontEntry);
}
return *this;
}
gfxFontFamily* Family() const { return mFamily.get(); }
gfxFont* Font() const {
return mFontCreated ? mFont : nullptr;
}
gfxFontEntry* FontEntry() const {
return mFontCreated ? mFont->GetFontEntry() : mFontEntry;
}
bool NeedsBold() const { return mNeedsBold; }
void SetFont(gfxFont* aFont)
{
NS_ASSERTION(aFont, "font pointer must not be null");
NS_ADDREF(aFont);
if (mFontCreated) {
NS_RELEASE(mFont);
} else {
NS_IF_RELEASE(mFontEntry);
}
mFont = aFont;
mFontCreated = true;
}
private:
nsRefPtr<gfxFontFamily> mFamily;
// either a font or a font entry exists
union {
gfxFont* mFont;
gfxFontEntry* mFontEntry;
};
bool mNeedsBold : 1;
bool mFontCreated : 1;
};
mozilla::FontFamilyList mFamilyList;
gfxFontStyle mStyle;
nsTArray<FamilyFace> mFonts;
@ -975,10 +1071,11 @@ protected:
int32_t aRunScript);
// Helper for font-matching:
// see if aCh is supported in any of the faces from aFamily;
// if so return the best style match, else return null.
already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily,
uint32_t aCh);
// When matching the italic case, allow use of the regular face
// if it supports a character but the italic one doesn't.
// Return null if regular face doesn't support aCh
already_AddRefed<gfxFont>
FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh);
// helper methods for looking up fonts