Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6959e74

Browse files
committed
have predictable cascading sort order
1 parent 61df1f7 commit 6959e74

File tree

2 files changed

+55
-32
lines changed

2 files changed

+55
-32
lines changed

third_party/txt/src/txt/font_collection.cc

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -204,31 +204,39 @@ std::shared_ptr<minikin::FontFamily> FontCollection::FindFontFamilyInManagers(
204204

205205
void FontCollection::SortSkTypefaces(
206206
std::vector<sk_sp<SkTypeface>>& sk_typefaces) {
207-
std::sort(sk_typefaces.begin(), sk_typefaces.end(),
208-
[](const sk_sp<SkTypeface>& a, const sk_sp<SkTypeface>& b) {
209-
SkFontStyle a_style = a->fontStyle();
210-
SkFontStyle b_style = b->fontStyle();
211-
212-
if (a_style.width() != b_style.width()) {
213-
// If a family name query is so generic it ends up bringing in
214-
// fonts of multiple widths (e.g. condensed, expanded), opt to
215-
// be conservative and select the most standard width.
216-
//
217-
// If a specific width is desired, it should be be narrowed down
218-
// via the family name.
219-
//
220-
// The font weights are also sorted lightest to heaviest but
221-
// Flutter APIs have the weight specified to narrow it down
222-
// later. The width ordering here is more consequential since
223-
// TextStyle doesn't have letter width APIs.
224-
return std::abs(a_style.width() - SkFontStyle::kNormal_Width) <
225-
std::abs(b_style.width() - SkFontStyle::kNormal_Width);
226-
} else {
227-
return (a_style.weight() != b_style.weight())
228-
? a_style.weight() < b_style.weight()
229-
: a_style.slant() < b_style.slant();
230-
}
231-
});
207+
std::sort(
208+
sk_typefaces.begin(), sk_typefaces.end(),
209+
[](const sk_sp<SkTypeface>& a, const sk_sp<SkTypeface>& b) {
210+
SkFontStyle a_style = a->fontStyle();
211+
SkFontStyle b_style = b->fontStyle();
212+
213+
int a_delta = std::abs(a_style.width() - SkFontStyle::kNormal_Width);
214+
int b_delta = std::abs(b_style.width() - SkFontStyle::kNormal_Width);
215+
216+
if (a_delta != b_delta) {
217+
// If a family name query is so generic it ends up bringing in fonts
218+
// of multiple widths (e.g. condensed, expanded), opt to be
219+
// conservative and select the most standard width.
220+
//
221+
// If a specific width is desired, it should be be narrowed down via
222+
// the family name.
223+
//
224+
// The font weights are also sorted lightest to heaviest but Flutter
225+
// APIs have the weight specified to narrow it down later. The width
226+
// ordering here is more consequential since TextStyle doesn't have
227+
// letter width APIs.
228+
return a_delta < b_delta;
229+
} else if (a_style.width() != b_style.width()) {
230+
// However, if the 2 fonts are equidistant from the "normal" width,
231+
// just arbitrarily but consistently return the more condensed font.
232+
return a_style.width() < b_style.width();
233+
} else if (a_style.weight() != b_style.weight()) {
234+
return a_style.weight() < b_style.weight();
235+
} else {
236+
return a_style.slant() < b_style.slant();
237+
}
238+
// Use a cascade of conditions so results are consistent each time.
239+
});
232240
}
233241

234242
std::shared_ptr<minikin::FontFamily> FontCollection::CreateMinikinFontFamily(

third_party/txt/tests/font_collection_unittests.cc

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class FontCollectionTest : public ::testing::Test {};
2929
namespace {
3030
// This function does some boilerplate to fill a builder with enough real
3131
// font-like data. Otherwise, detach won't actually build an SkTypeface.
32-
void PopulateUserTypeface(SkCustomTypefaceBuilder* builder) {
32+
void PopulateUserTypefaceBoilerplate(SkCustomTypefaceBuilder* builder) {
3333
constexpr float upem = 200;
3434

3535
{
@@ -75,25 +75,32 @@ TEST(FontCollectionTest, CheckSkTypefacesSorting) {
7575
SkFontStyle::kItalic_Slant));
7676
// For the purpose of this test, we need to fill this to make the SkTypeface
7777
// build but it doesn't matter. We only care about the SkFontStyle.
78-
PopulateUserTypeface(&typefaceBuilder1);
78+
PopulateUserTypefaceBoilerplate(&typefaceBuilder1);
7979
sk_sp<SkTypeface> typeface1{typefaceBuilder1.detach()};
8080

8181
SkCustomTypefaceBuilder typefaceBuilder2;
8282
typefaceBuilder2.setFontStyle(SkFontStyle(SkFontStyle::kLight_Weight,
8383
SkFontStyle::kNormal_Width,
8484
SkFontStyle::kUpright_Slant));
85-
PopulateUserTypeface(&typefaceBuilder2);
85+
PopulateUserTypefaceBoilerplate(&typefaceBuilder2);
8686
sk_sp<SkTypeface> typeface2{typefaceBuilder2.detach()};
8787

8888
SkCustomTypefaceBuilder typefaceBuilder3;
8989
typefaceBuilder3.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight,
9090
SkFontStyle::kNormal_Width,
9191
SkFontStyle::kUpright_Slant));
92-
PopulateUserTypeface(&typefaceBuilder3);
92+
PopulateUserTypefaceBoilerplate(&typefaceBuilder3);
9393
sk_sp<SkTypeface> typeface3{typefaceBuilder3.detach()};
9494

95+
SkCustomTypefaceBuilder typefaceBuilder4;
96+
typefaceBuilder4.setFontStyle(SkFontStyle(SkFontStyle::kThin_Weight,
97+
SkFontStyle::kCondensed_Width,
98+
SkFontStyle::kUpright_Slant));
99+
PopulateUserTypefaceBoilerplate(&typefaceBuilder4);
100+
sk_sp<SkTypeface> typeface4{typefaceBuilder4.detach()};
101+
95102
std::vector<sk_sp<SkTypeface>> candidateTypefaces = {typeface1, typeface2,
96-
typeface3};
103+
typeface3, typeface4};
97104

98105
// This sorts the vector in-place.
99106
txt::FontCollection::SortSkTypefaces(candidateTypefaces);
@@ -103,8 +110,11 @@ TEST(FontCollectionTest, CheckSkTypefacesSorting) {
103110
ASSERT_EQ(candidateTypefaces[0].get(), typeface2.get());
104111
// Then the most normal width font with normal weight.
105112
ASSERT_EQ(candidateTypefaces[1].get(), typeface3.get());
106-
// Then a less normal (expanded) width font.
107-
ASSERT_EQ(candidateTypefaces[2].get(), typeface1.get());
113+
// Then a less normal (condensed) width font.
114+
ASSERT_EQ(candidateTypefaces[2].get(), typeface4.get());
115+
// All things equal, 4 came before 1 because we arbitrarily chose to make the
116+
// narrower font come first.
117+
ASSERT_EQ(candidateTypefaces[3].get(), typeface1.get());
108118

109119
// Double check.
110120
ASSERT_EQ(candidateTypefaces[0]->fontStyle().weight(),
@@ -120,6 +130,11 @@ TEST(FontCollectionTest, CheckSkTypefacesSorting) {
120130
ASSERT_EQ(candidateTypefaces[2]->fontStyle().weight(),
121131
SkFontStyle::kThin_Weight);
122132
ASSERT_EQ(candidateTypefaces[2]->fontStyle().width(),
133+
SkFontStyle::kCondensed_Width);
134+
135+
ASSERT_EQ(candidateTypefaces[3]->fontStyle().weight(),
136+
SkFontStyle::kThin_Weight);
137+
ASSERT_EQ(candidateTypefaces[3]->fontStyle().width(),
123138
SkFontStyle::kExpanded_Width);
124139
}
125140

0 commit comments

Comments
 (0)