Loading gfx/thebes/SharedFontList.cpp +111 −19 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; Loading @@ -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 Loading @@ -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; } } Loading @@ -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 Loading @@ -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) { Loading @@ -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; } Loading @@ -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, Loading gfx/thebes/SharedFontList.h +17 −2 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); Loading @@ -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; Loading Loading @@ -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; Loading gfx/thebes/gfxFcPlatformFontList.cpp +24 −4 Original line number Diff line number Diff line Loading @@ -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) != Loading @@ -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, Loading Loading @@ -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). Loading Loading
gfx/thebes/SharedFontList.cpp +111 −19 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; Loading @@ -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 Loading @@ -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; } } Loading @@ -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 Loading @@ -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) { Loading @@ -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; } Loading @@ -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, Loading
gfx/thebes/SharedFontList.h +17 −2 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); Loading @@ -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; Loading Loading @@ -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; Loading
gfx/thebes/gfxFcPlatformFontList.cpp +24 −4 Original line number Diff line number Diff line Loading @@ -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) != Loading @@ -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, Loading Loading @@ -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). Loading