Bug 1458301 - Unify font face selection methods to consistently use WeightStyleStretchDistance to evaluate the closeness of an available resource to a requested style. r=jwatt

This commit is contained in:
Jonathan Kew 2018-05-15 14:59:25 +01:00
Родитель d6b8a750aa
Коммит a311568f05
4 изменённых файлов: 61 добавлений и 109 удалений

Просмотреть файл

@ -1524,8 +1524,6 @@ WeightDistance(const gfxFontEntry* aFontEntry, FontWeight aTargetWeight)
return distance;
}
#define MAX_DISTANCE 1.0e20 // >> than any WeightStyleStretchDistance result
static inline double
WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
const gfxFontStyle& aTargetStyle)
@ -1625,7 +1623,7 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
// weight/style/stretch combination, only the last matched font entry will
// be added.
double minDistance = MAX_DISTANCE;
double minDistance = INFINITY;
gfxFontEntry* matched = nullptr;
// iterate in forward order so that faces like 'Bold' are matched before
// matching style distance faces such as 'Bold Outline' (see bug 1185812)
@ -1735,45 +1733,8 @@ void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
aLocalizedName = mName;
}
// metric for how close a given font matches a style
static float
CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
float rank = 0;
if (aStyle) {
// TODO: stretch
// italics
bool wantUpright = aStyle->style.IsNormal();
if (aFontEntry->IsUpright() == wantUpright) {
rank += 5000.0f;
}
// measure of closeness of weight to the desired value
if (aFontEntry->Weight().Min() > aStyle->weight) {
rank += 1000.0f - (aFontEntry->Weight().Min() - aStyle->weight);
} else if (aFontEntry->Weight().Max() < aStyle->weight) {
rank += 1000.0f - (aStyle->weight - aFontEntry->Weight().Max());
} else {
rank += 2000.0f; // the font supports the exact weight wanted
}
} else {
// if no font to match, prefer non-bold, non-italic fonts
if (aFontEntry->IsUpright()) {
rank += 2000.0f;
}
if (aFontEntry->Weight().Min() <= FontWeight(500)) {
rank += 1000.0f;
}
}
return rank;
}
#define RANK_MATCHED_CMAP 10000.0f
void
gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData)
{
if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
// none of the faces in the family support the required char,
@ -1781,81 +1742,72 @@ gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
return;
}
gfxFontEntry *fe =
FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
: gfxFontStyle(),
true);
gfxFontEntry* fe =
FindFontForStyle(aMatchData->mStyle, /*aIgnoreSizeTolerance*/ true);
if (!fe || fe->SkipDuringSystemFallback()) {
return;
}
if (fe && !fe->SkipDuringSystemFallback()) {
float rank = 0;
float distance = INFINITY;
if (fe->HasCharacter(aMatchData->mCh)) {
rank += RANK_MATCHED_CMAP;
aMatchData->mCount++;
if (fe->HasCharacter(aMatchData->mCh)) {
aMatchData->mCount++;
LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
Script script = GetScriptCode(aMatchData->mCh);
MOZ_LOG(log, LogLevel::Debug,\
("(textrun-systemfallback-fonts) char: u+%6.6x "
"unicode-range: %d script: %d match: [%s]\n",
aMatchData->mCh,
unicodeRange, int(script),
NS_ConvertUTF16toUTF8(fe->Name()).get()));
}
// omitting from original windows code -- family name, lang group, pitch
// not available in current FontEntry implementation
rank += CalcStyleMatch(fe, aMatchData->mStyle);
} else if (!fe->IsNormalStyle()) {
// If style/weight/stretch was not Normal, see if we can
// fall back to a next-best face (e.g. Arial Black -> Bold,
// or Arial Narrow -> Regular).
GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
SearchAllFontsForChar(&data);
if (data.mMatchRank >= RANK_MATCHED_CMAP) {
fe = data.mBestMatch;
rank = data.mMatchRank;
} else {
return;
}
} else {
return;
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
Script script = GetScriptCode(aMatchData->mCh);
MOZ_LOG(log, LogLevel::Debug,\
("(textrun-systemfallback-fonts) char: u+%6.6x "
"unicode-range: %d script: %d match: [%s]\n",
aMatchData->mCh,
unicodeRange, int(script),
NS_ConvertUTF16toUTF8(fe->Name()).get()));
}
aMatchData->mCmapsTested++;
// xxx - add whether AAT font with morphing info for specific lang groups
if (rank > aMatchData->mMatchRank
|| (rank == aMatchData->mMatchRank &&
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
{
aMatchData->mBestMatch = fe;
aMatchData->mMatchedFamily = this;
aMatchData->mMatchRank = rank;
distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
} else if (!fe->IsNormalStyle()) {
// If style/weight/stretch was not Normal, see if we can
// fall back to a next-best face (e.g. Arial Black -> Bold,
// or Arial Narrow -> Regular).
GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
SearchAllFontsForChar(&data);
if (isfinite(data.mMatchDistance)) {
fe = data.mBestMatch;
distance = data.mMatchDistance;
}
}
aMatchData->mCmapsTested++;
if (isinf(distance)) {
return;
}
if (distance < aMatchData->mMatchDistance ||
(distance == aMatchData->mMatchDistance &&
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
aMatchData->mBestMatch = fe;
aMatchData->mMatchedFamily = this;
aMatchData->mMatchDistance = distance;
}
}
void
gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData)
{
uint32_t i, numFonts = mAvailableFonts.Length();
for (i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
if (fe && fe->HasCharacter(aMatchData->mCh)) {
float rank = RANK_MATCHED_CMAP;
rank += CalcStyleMatch(fe, aMatchData->mStyle);
if (rank > aMatchData->mMatchRank
|| (rank == aMatchData->mMatchRank &&
float distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
if (distance < aMatchData->mMatchDistance
|| (distance == aMatchData->mMatchDistance &&
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
{
aMatchData->mBestMatch = fe;
aMatchData->mMatchedFamily = this;
aMatchData->mMatchRank = rank;
aMatchData->mMatchDistance = distance;
}
}
}

Просмотреть файл

@ -24,6 +24,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include <math.h>
typedef struct gr_face gr_face;
@ -690,20 +691,19 @@ gfxFontEntry::SupportsBold()
// used when iterating over all fonts looking for a match for a given character
struct GlobalFontMatch {
GlobalFontMatch(const uint32_t aCharacter,
const gfxFontStyle *aStyle) :
mCh(aCharacter), mStyle(aStyle),
mMatchRank(0.0f), mCount(0), mCmapsTested(0)
const gfxFontStyle& aStyle) :
mStyle(aStyle), mCh(aCharacter),
mCount(0), mCmapsTested(0), mMatchDistance(INFINITY)
{
}
RefPtr<gfxFontEntry> mBestMatch; // current best match
RefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
const gfxFontStyle& mStyle; // style to match
const uint32_t mCh; // codepoint to be matched
const gfxFontStyle* mStyle; // style to match
float mMatchRank; // metric indicating closest match
RefPtr<gfxFontEntry> mBestMatch; // current best match
RefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
uint32_t mCount; // number of fonts matched
uint32_t mCmapsTested; // number of cmaps tested
float mMatchDistance; // metric indicating closest match
};
class gfxFontFamily {
@ -786,10 +786,10 @@ public:
// checks for a matching font within the family
// used as part of the font fallback process
void FindFontForChar(GlobalFontMatch *aMatchData);
void FindFontForChar(GlobalFontMatch* aMatchData);
// checks all fonts for a matching font within the family
void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
void SearchAllFontsForChar(GlobalFontMatch* aMatchData);
// read in other family names, if any, and use functor to add each into cache
virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);

Просмотреть файл

@ -682,7 +682,7 @@ gfxPlatformFontList::CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
// If style/weight/stretch was not Normal, see if we can
// fall back to a next-best face (e.g. Arial Black -> Bold,
// or Arial Narrow -> Regular).
GlobalFontMatch data(aCh, aMatchStyle);
GlobalFontMatch data(aCh, *aMatchStyle);
fallback->SearchAllFontsForChar(&data);
if (data.mBestMatch) {
*aMatchedFamily = fallback;
@ -715,7 +715,7 @@ gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
}
// otherwise, try to find it among local fonts
GlobalFontMatch data(aCh, aMatchStyle);
GlobalFontMatch data(aCh, *aMatchStyle);
// iterate over all font families to find a font that support the character
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {

Просмотреть файл

@ -2799,7 +2799,7 @@ gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
gfxFont*
gfxFontGroup::FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
{
GlobalFontMatch data(aCh, &mStyle);
GlobalFontMatch data(aCh, mStyle);
aFamily->SearchAllFontsForChar(&data);
gfxFontEntry* fe = data.mBestMatch;
if (!fe) {