forked from ports/contrib
322 lines
11 KiB
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).
|
|
|