Bug 1714282 - Handle bitmap font sizes in the shared font list on Linux. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D116874
This commit is contained in:
Jonathan Kew 2021-06-06 20:30:14 +00:00
Родитель 72f885fa29
Коммит 2f1aa020c3
3 изменённых файлов: 152 добавлений и 25 удалений

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

@ -11,6 +11,7 @@
#include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentParent.h"
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
#include "mozilla/Unused.h"
#define LOG_FONTLIST(args) \ #define LOG_FONTLIST(args) \
MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
@ -231,34 +232,46 @@ void Family::AddFaces(FontList* aList, const nsTArray<Face::InitData>& aFaces) {
} }
} }
void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle, bool Family::FindAllFacesForStyleInternal(FontList* aList,
nsTArray<Face*>& aFaceList, const gfxFontStyle& aStyle,
bool aIgnoreSizeTolerance) const { nsTArray<Face*>& aFaceList) const {
MOZ_ASSERT(aFaceList.IsEmpty()); MOZ_ASSERT(aFaceList.IsEmpty());
if (!IsInitialized()) { if (!IsInitialized()) {
return; return false;
} }
Pointer* facePtrs = Faces(aList); Pointer* facePtrs = Faces(aList);
if (!facePtrs) { if (!facePtrs) {
return; return false;
} }
// If the family has only one face, we simply return it; no further // Depending on the kind of family, we have to do varying amounts of work
// checking needed. // to figure out what face(s) to use for the requested style properties.
// If the family has only one face, we simply use it; no further style
// checking needed. (However, for bitmap fonts we may still need to check
// whether the size is acceptable.)
if (NumFaces() == 1) { if (NumFaces() == 1) {
MOZ_ASSERT(!facePtrs[0].IsNull()); MOZ_ASSERT(!facePtrs[0].IsNull());
aFaceList.AppendElement(static_cast<Face*>(facePtrs[0].ToPtr(aList))); Face* face = static_cast<Face*>(facePtrs[0].ToPtr(aList));
return; if (face && face->HasValidDescriptor()) {
aFaceList.AppendElement(face);
#ifdef MOZ_WIDGET_GTK
if (face->mSize) {
return true;
}
#endif
}
return false;
} }
// Most families are "simple", having just Regular/Bold/Italic/BoldItalic, // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
// or some subset of these. In this case, we have exactly 4 entries in // or some subset of these. In this case, we have exactly 4 entries in
// mAvailableFonts, stored in the above order; note that some of the entries // mAvailableFonts, stored in the above order; note that some of the entries
// may be nullptr. We can then pick the required entry based on whether the // may be nullptr. We can then pick the required entry based on whether the
// request is for bold or non-bold, italic or non-italic, without running the // request is for bold or non-bold, italic or non-italic, without running
// more complex matching algorithm used for larger families with many weights // the more complex matching algorithm used for larger families with many
// and/or widths. // weights and/or widths.
if (mIsSimple) { if (mIsSimple) {
// Family has no more than the "standard" 4 faces, at fixed indexes; // Family has no more than the "standard" 4 faces, at fixed indexes;
@ -270,15 +283,20 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
uint8_t faceIndex = uint8_t faceIndex =
(wantItalic ? kItalicMask : 0) | (wantBold ? kBoldMask : 0); (wantItalic ? kItalicMask : 0) | (wantBold ? kBoldMask : 0);
// if the desired style is available, return it directly // If the desired style is available, use it directly.
Face* face = static_cast<Face*>(facePtrs[faceIndex].ToPtr(aList)); Face* face = static_cast<Face*>(facePtrs[faceIndex].ToPtr(aList));
if (face && face->HasValidDescriptor()) { if (face && face->HasValidDescriptor()) {
aFaceList.AppendElement(face); aFaceList.AppendElement(face);
return; #ifdef MOZ_WIDGET_GTK
if (face->mSize) {
return true;
}
#endif
return false;
} }
// order to check fallback faces in a simple family, depending on requested // Order to check fallback faces in a simple family, depending on the
// style // requested style.
static const uint8_t simpleFallbacks[4][3] = { static const uint8_t simpleFallbacks[4][3] = {
{kBoldFaceIndex, kItalicFaceIndex, {kBoldFaceIndex, kItalicFaceIndex,
kBoldItalicFaceIndex}, // fallback sequence for Regular kBoldItalicFaceIndex}, // fallback sequence for Regular
@ -294,7 +312,12 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
face = static_cast<Face*>(facePtrs[order[trial]].ToPtr(aList)); face = static_cast<Face*>(facePtrs[order[trial]].ToPtr(aList));
if (face && face->HasValidDescriptor()) { if (face && face->HasValidDescriptor()) {
aFaceList.AppendElement(face); aFaceList.AppendElement(face);
return; #ifdef MOZ_WIDGET_GTK
if (face->mSize) {
return true;
}
#endif
return false;
} }
} }
@ -302,7 +325,7 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
// can happen if we're on a stylo thread and caught the font list being // can happen if we're on a stylo thread and caught the font list being
// updated; in that case we just fail quietly and let font fallback do // updated; in that case we just fail quietly and let font fallback do
// something for the time being. // something for the time being.
return; return false;
} }
// Pick the font(s) that are closest to the desired weight, style, and // Pick the font(s) that are closest to the desired weight, style, and
@ -315,9 +338,11 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
// normal platform fonts with a single font entry for each // normal platform fonts with a single font entry for each
// weight/style/stretch combination, only the last matched font entry will // weight/style/stretch combination, only the last matched font entry will
// be added. // be added.
double minDistance = INFINITY; double minDistance = INFINITY;
Face* matched = nullptr; Face* matched = nullptr;
// Keep track of whether we've included any non-scalable font resources in
// the selected set.
bool anyNonScalable = false;
for (uint32_t i = 0; i < NumFaces(); i++) { for (uint32_t i = 0; i < NumFaces(); i++) {
Face* face = static_cast<Face*>(facePtrs[i].ToPtr(aList)); Face* face = static_cast<Face*>(facePtrs[i].ToPtr(aList));
if (face) { if (face) {
@ -332,6 +357,11 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
} else if (distance == minDistance) { } else if (distance == minDistance) {
if (matched) { if (matched) {
aFaceList.AppendElement(matched); aFaceList.AppendElement(matched);
#ifdef MOZ_WIDGET_GTK
if (matched->mSize) {
anyNonScalable = true;
}
#endif
} }
matched = face; matched = face;
} }
@ -341,7 +371,69 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
MOZ_ASSERT(matched, "didn't match a font within a family"); MOZ_ASSERT(matched, "didn't match a font within a family");
if (matched) { if (matched) {
aFaceList.AppendElement(matched); aFaceList.AppendElement(matched);
#ifdef MOZ_WIDGET_GTK
if (matched->mSize) {
anyNonScalable = true;
} }
#endif
}
return anyNonScalable;
}
void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
nsTArray<Face*>& aFaceList,
bool aIgnoreSizeTolerance) const {
#ifdef MOZ_WIDGET_GTK
bool anyNonScalable =
#else
Unused <<
#endif
FindAllFacesForStyleInternal(aList, aStyle, aFaceList);
#ifdef MOZ_WIDGET_GTK
// aFaceList now contains whatever faces are the best style match for
// the requested style. If specifically-sized bitmap faces are supported,
// we need to additionally filter the list to choose the appropriate size.
//
// It would be slightly more efficient to integrate this directly into the
// face-selection algorithm above, but it's a rare case that doesn't apply
// at all to most font families.
//
// Currently we only support pixel-sized bitmap font faces on Linux/Gtk (i.e.
// when using the gfxFcPlatformFontList implementation), so this filtering is
// not needed on other platforms.
//
// (Note that color-bitmap emoji fonts like Apple Color Emoji or Noto Color
// Emoji don't count here; they package multiple bitmap sizes into a single
// OpenType wrapper, so they appear as a single "scalable" face in our list.)
if (anyNonScalable) {
uint16_t best = 0;
gfxFloat dist = 0.0;
for (const auto& f : aFaceList) {
if (f->mSize == 0) {
// Scalable face; no size distance to compute.
continue;
}
gfxFloat d = fabs(gfxFloat(f->mSize) - aStyle.size);
if (!aIgnoreSizeTolerance && (d * 5.0 > f->mSize)) {
continue; // Too far from the requested size, ignore.
}
// If we haven't found a "best" bitmap size yet, or if this is a better
// match, remember it.
if (!best || d < dist) {
best = f->mSize;
dist = d;
}
}
// Discard all faces except the chosen "best" size; or if no pixel size was
// chosen, all except scalable faces.
// This may eliminate *all* faces in the family, if all were bitmaps and
// none was a good enough size match, in which case we'll fall back to the
// next font-family name.
aFaceList.RemoveElementsBy([=](const auto& e) { return e->mSize != best; });
}
#endif
} }
Face* Family::FindFaceForStyle(FontList* aList, const gfxFontStyle& aStyle, Face* Family::FindFaceForStyle(FontList* aList, const gfxFontStyle& aStyle,

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

@ -157,6 +157,9 @@ struct Face {
nsCString mDescriptor; // descriptor that can be used to instantiate a nsCString mDescriptor; // descriptor that can be used to instantiate a
// platform font reference // platform font reference
uint16_t mIndex; // an index used with descriptor (on some platforms) uint16_t mIndex; // an index used with descriptor (on some platforms)
#ifdef MOZ_WIDGET_GTK
uint16_t mSize; // pixel size if bitmap; zero indicates scalable
#endif
bool mFixedPitch; // is the face fixed-pitch (monospaced)? bool mFixedPitch; // is the face fixed-pitch (monospaced)?
mozilla::WeightRange mWeight; // CSS font-weight value mozilla::WeightRange mWeight; // CSS font-weight value
mozilla::StretchRange mStretch; // CSS font-stretch value mozilla::StretchRange mStretch; // CSS font-stretch value
@ -169,11 +172,15 @@ struct Face {
Face(FontList* aList, const InitData& aData) Face(FontList* aList, const InitData& aData)
: mDescriptor(aList, aData.mDescriptor), : mDescriptor(aList, aData.mDescriptor),
mIndex(aData.mIndex), mIndex(aData.mIndex),
#ifdef MOZ_WIDGET_GTK
mSize(aData.mSize),
#endif
mFixedPitch(aData.mFixedPitch), mFixedPitch(aData.mFixedPitch),
mWeight(aData.mWeight), mWeight(aData.mWeight),
mStretch(aData.mStretch), mStretch(aData.mStretch),
mStyle(aData.mStyle), mStyle(aData.mStyle),
mCharacterMap(Pointer::Null()) {} mCharacterMap(Pointer::Null()) {
}
bool HasValidDescriptor() const { bool HasValidDescriptor() const {
return !mDescriptor.IsNull() && mIndex != uint16_t(-1); return !mDescriptor.IsNull() && mIndex != uint16_t(-1);
@ -183,6 +190,9 @@ struct Face {
String mDescriptor; String mDescriptor;
uint16_t mIndex; uint16_t mIndex;
#ifdef MOZ_WIDGET_GTK
uint16_t mSize;
#endif
bool mFixedPitch; bool mFixedPitch;
mozilla::WeightRange mWeight; mozilla::WeightRange mWeight;
mozilla::StretchRange mStretch; mozilla::StretchRange mStretch;
@ -309,6 +319,11 @@ struct Family {
void SetupFamilyCharMap(FontList* aList); void SetupFamilyCharMap(FontList* aList);
private: private:
// Returns true if there are specifically-sized bitmap faces in the list,
// so size selection still needs to be done. (Currently only on Linux.)
bool FindAllFacesForStyleInternal(FontList* aList, const gfxFontStyle& aStyle,
nsTArray<Face*>& aFaceList) const;
std::atomic<uint32_t> mFaceCount; std::atomic<uint32_t> mFaceCount;
String mKey; String mKey;
String mName; String mName;

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

@ -205,7 +205,8 @@ static FontStretch MapFcWidth(int aFcWidth) {
static void GetFontProperties(FcPattern* aFontPattern, WeightRange* aWeight, static void GetFontProperties(FcPattern* aFontPattern, WeightRange* aWeight,
StretchRange* aStretch, StretchRange* aStretch,
SlantStyleRange* aSlantStyle) { SlantStyleRange* aSlantStyle,
uint16_t* aSize = nullptr) {
// weight // weight
int weight; int weight;
if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) != if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) !=
@ -231,6 +232,24 @@ static void GetFontProperties(FcPattern* aFontPattern, WeightRange* aWeight,
} else if (slant > 0) { } else if (slant > 0) {
*aSlantStyle = SlantStyleRange(FontSlantStyle::Italic()); *aSlantStyle = SlantStyleRange(FontSlantStyle::Italic());
} }
if (aSize) {
// pixel size, or zero if scalable
FcBool scalable;
if (FcPatternGetBool(aFontPattern, FC_SCALABLE, 0, &scalable) ==
FcResultMatch &&
scalable) {
*aSize = 0;
} else {
double size;
if (FcPatternGetDouble(aFontPattern, FC_PIXEL_SIZE, 0, &size) ==
FcResultMatch) {
*aSize = uint16_t(NS_round(size));
} else {
*aSize = 0;
}
}
}
} }
gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsACString& aFaceName, gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsACString& aFaceName,
@ -1667,10 +1686,11 @@ void gfxFcPlatformFontList::InitSharedFontListForPlatform() {
WeightRange weight(FontWeight::Normal()); WeightRange weight(FontWeight::Normal());
StretchRange stretch(FontStretch::Normal()); StretchRange stretch(FontStretch::Normal());
SlantStyleRange style(FontSlantStyle::Normal()); SlantStyleRange style(FontSlantStyle::Normal());
GetFontProperties(aPattern, &weight, &stretch, &style); uint16_t size;
GetFontProperties(aPattern, &weight, &stretch, &style, &size);
auto initData = auto initData = fontlist::Face::InitData{descriptor, 0, size, false,
fontlist::Face::InitData{descriptor, 0, false, weight, stretch, style}; weight, stretch, style};
// Add entries for any other localized family names. (Most fonts only have // Add entries for any other localized family names. (Most fonts only have
// a single family name, so the first call to GetString will usually fail). // a single family name, so the first call to GetString will usually fail).