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/ContentParent.h"
#include "mozilla/Logging.h"
#include "mozilla/Unused.h"
#define LOG_FONTLIST(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,
nsTArray<Face*>& aFaceList,
bool aIgnoreSizeTolerance) const {
bool Family::FindAllFacesForStyleInternal(FontList* aList,
const gfxFontStyle& aStyle,
nsTArray<Face*>& aFaceList) const {
MOZ_ASSERT(aFaceList.IsEmpty());
if (!IsInitialized()) {
return;
return false;
}
Pointer* facePtrs = Faces(aList);
if (!facePtrs) {
return;
return false;
}
// If the family has only one face, we simply return it; no further
// checking needed.
// Depending on the kind of family, we have to do varying amounts of work
// 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) {
MOZ_ASSERT(!facePtrs[0].IsNull());
aFaceList.AppendElement(static_cast<Face*>(facePtrs[0].ToPtr(aList)));
return;
Face* face = static_cast<Face*>(facePtrs[0].ToPtr(aList));
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,
// 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
// 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
// more complex matching algorithm used for larger families with many weights
// and/or widths.
// request is for bold or non-bold, italic or non-italic, without running
// the more complex matching algorithm used for larger families with many
// weights and/or widths.
if (mIsSimple) {
// 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 =
(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));
if (face && face->HasValidDescriptor()) {
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
// style
// Order to check fallback faces in a simple family, depending on the
// requested style.
static const uint8_t simpleFallbacks[4][3] = {
{kBoldFaceIndex, kItalicFaceIndex,
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));
if (face && face->HasValidDescriptor()) {
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
// updated; in that case we just fail quietly and let font fallback do
// something for the time being.
return;
return false;
}
// 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
// weight/style/stretch combination, only the last matched font entry will
// be added.
double minDistance = INFINITY;
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++) {
Face* face = static_cast<Face*>(facePtrs[i].ToPtr(aList));
if (face) {
@ -332,6 +357,11 @@ void Family::FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
} else if (distance == minDistance) {
if (matched) {
aFaceList.AppendElement(matched);
#ifdef MOZ_WIDGET_GTK
if (matched->mSize) {
anyNonScalable = true;
}
#endif
}
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");
if (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,

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

@ -157,7 +157,10 @@ struct Face {
nsCString mDescriptor; // descriptor that can be used to instantiate a
// platform font reference
uint16_t mIndex; // an index used with descriptor (on some platforms)
bool mFixedPitch; // is the face fixed-pitch (monospaced)?
#ifdef MOZ_WIDGET_GTK
uint16_t mSize; // pixel size if bitmap; zero indicates scalable
#endif
bool mFixedPitch; // is the face fixed-pitch (monospaced)?
mozilla::WeightRange mWeight; // CSS font-weight value
mozilla::StretchRange mStretch; // CSS font-stretch value
mozilla::SlantStyleRange mStyle; // CSS font-style value
@ -169,11 +172,15 @@ struct Face {
Face(FontList* aList, const InitData& aData)
: mDescriptor(aList, aData.mDescriptor),
mIndex(aData.mIndex),
#ifdef MOZ_WIDGET_GTK
mSize(aData.mSize),
#endif
mFixedPitch(aData.mFixedPitch),
mWeight(aData.mWeight),
mStretch(aData.mStretch),
mStyle(aData.mStyle),
mCharacterMap(Pointer::Null()) {}
mCharacterMap(Pointer::Null()) {
}
bool HasValidDescriptor() const {
return !mDescriptor.IsNull() && mIndex != uint16_t(-1);
@ -183,6 +190,9 @@ struct Face {
String mDescriptor;
uint16_t mIndex;
#ifdef MOZ_WIDGET_GTK
uint16_t mSize;
#endif
bool mFixedPitch;
mozilla::WeightRange mWeight;
mozilla::StretchRange mStretch;
@ -309,6 +319,11 @@ struct Family {
void SetupFamilyCharMap(FontList* aList);
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;
String mKey;
String mName;

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

@ -205,7 +205,8 @@ static FontStretch MapFcWidth(int aFcWidth) {
static void GetFontProperties(FcPattern* aFontPattern, WeightRange* aWeight,
StretchRange* aStretch,
SlantStyleRange* aSlantStyle) {
SlantStyleRange* aSlantStyle,
uint16_t* aSize = nullptr) {
// weight
int weight;
if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) !=
@ -231,6 +232,24 @@ static void GetFontProperties(FcPattern* aFontPattern, WeightRange* aWeight,
} else if (slant > 0) {
*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,
@ -1667,10 +1686,11 @@ void gfxFcPlatformFontList::InitSharedFontListForPlatform() {
WeightRange weight(FontWeight::Normal());
StretchRange stretch(FontStretch::Normal());
SlantStyleRange style(FontSlantStyle::Normal());
GetFontProperties(aPattern, &weight, &stretch, &style);
uint16_t size;
GetFontProperties(aPattern, &weight, &stretch, &style, &size);
auto initData =
fontlist::Face::InitData{descriptor, 0, false, weight, stretch, style};
auto initData = fontlist::Face::InitData{descriptor, 0, size, false,
weight, stretch, style};
// 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).