contrib/firefox/D116874.diff

322 lines
11 KiB
Diff

diff --git a/gfx/thebes/SharedFontList.h b/gfx/thebes/SharedFontList.h
--- a/gfx/thebes/SharedFontList.h
+++ b/gfx/thebes/SharedFontList.h
@@ -157,7 +157,10 @@
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 @@
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 @@
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 @@
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;
diff --git a/gfx/thebes/SharedFontList.cpp b/gfx/thebes/SharedFontList.cpp
--- a/gfx/thebes/SharedFontList.cpp
+++ b/gfx/thebes/SharedFontList.cpp
@@ -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::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 @@
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 @@
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 @@
// 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 @@
// 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 @@
} 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 @@
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,
diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -205,7 +205,8 @@
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 @@
} 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 @@
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).