зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
72f885fa29
Коммит
2f1aa020c3
|
@ -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,6 +157,9 @@ 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)
|
||||
#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
|
||||
|
@ -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).
|
||||
|
|
Загрузка…
Ссылка в новой задаче