Skip to content

Commit 9f0d8c2

Browse files
Ben WagnerSkia Commit-Bot
authored andcommitted
Add support for fallbackFor in Android parser.
Change-Id: Id328c67b6ad5d76584030f480316425f25979ebf Reviewed-on: https://skia-review.googlesource.com/c/171644 Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Ben Wagner <bungeman@google.com>
1 parent 26d8d77 commit 9f0d8c2

File tree

5 files changed

+135
-58
lines changed

5 files changed

+135
-58
lines changed

resources/fonts/fonts.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
<family name="Em"><font weight="400" style="normal">Em.ttf</font></family>
2525
<family name="HangingS"><font weight="400" style="normal">HangingS.ttf</font></family>
2626
<family name="HintGasp"><font weight="400" style="normal">hintgasp.ttf</font></family>
27-
<family name="RTeallyBigA"><font weight="400" style="normal">ReallyBigA.ttf</font></family>
27+
<family name="ReallyBigA"><font weight="400" style="normal">ReallyBigA.ttf</font></family>
2828
<family name="Spider"><font weight="400" style="normal">SpiderSymbol.ttf</font></family>
29-
<family name="TestTTC0"><font weight="400" style="normal" index="0">test.ttc</font></family>
30-
<family name="TestTTC1"><font weight="400" style="normal" index="1">test.ttc</font></family>
29+
<family>
30+
<font weight="400" style="normal" index="0">test.ttc</font>
31+
<font weight="700" style="normal" index="1" fallbackFor="sans-serif">test.ttc</font>
32+
</family>
3133
<family name="Funkster"><font weight="400" style="normal">Funkster.ttf</font></family>
3234
</familyset>

src/ports/SkFontMgr_android.cpp

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ class SkFontStyleSet_Android : public SkFontStyleSet {
178178
if (family.fNames.count() > 0) {
179179
cannonicalFamilyName = &family.fNames[0];
180180
}
181+
fFallbackFor = family.fFallbackFor;
182+
181183
// TODO? make this lazy
182184
for (int i = 0; i < family.fFonts.count(); ++i) {
183185
const FontFileInfo& fontFile = family.fFonts[i];
@@ -268,6 +270,7 @@ class SkFontStyleSet_Android : public SkFontStyleSet {
268270

269271
private:
270272
SkTArray<sk_sp<SkTypeface_AndroidSystem>> fStyles;
273+
SkString fFallbackFor;
271274

272275
friend struct NameToFamily;
273276
friend class SkFontMgr_Android;
@@ -370,12 +373,16 @@ class SkFontMgr_Android : public SkFontMgr {
370373
}
371374

372375
static sk_sp<SkTypeface_AndroidSystem> find_family_style_character(
376+
const SkString& familyName,
373377
const SkTArray<NameToFamily, true>& fallbackNameToFamilyMap,
374378
const SkFontStyle& style, bool elegant,
375379
const SkString& langTag, SkUnichar character)
376380
{
377381
for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) {
378382
SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
383+
if (familyName != family->fFallbackFor) {
384+
continue;
385+
}
379386
sk_sp<SkTypeface_AndroidSystem> face(family->matchStyle(style));
380387

381388
if (!langTag.isEmpty() &&
@@ -414,28 +421,31 @@ class SkFontMgr_Android : public SkFontMgr {
414421
// As a result, it is not possible to know the variant context from the font alone.
415422
// TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
416423

417-
// The first time match anything elegant, second time anything not elegant.
418-
for (int elegant = 2; elegant --> 0;) {
419-
for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
420-
SkLanguage lang(bcp47[bcp47Index]);
421-
while (!lang.getTag().isEmpty()) {
422-
sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
423-
find_family_style_character(fFallbackNameToFamilyMap,
424-
style, SkToBool(elegant),
425-
lang.getTag(), character);
426-
if (matchingTypeface) {
427-
return matchingTypeface.release();
424+
SkString familyNameString(familyName);
425+
for (const SkString& currentFamilyName : { familyNameString, SkString() }) {
426+
// The first time match anything elegant, second time anything not elegant.
427+
for (int elegant = 2; elegant --> 0;) {
428+
for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
429+
SkLanguage lang(bcp47[bcp47Index]);
430+
while (!lang.getTag().isEmpty()) {
431+
sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
432+
find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
433+
style, SkToBool(elegant),
434+
lang.getTag(), character);
435+
if (matchingTypeface) {
436+
return matchingTypeface.release();
437+
}
438+
439+
lang = lang.getParent();
428440
}
429-
430-
lang = lang.getParent();
431441
}
432-
}
433-
sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
434-
find_family_style_character(fFallbackNameToFamilyMap,
435-
style, SkToBool(elegant),
436-
SkString(), character);
437-
if (matchingTypeface) {
438-
return matchingTypeface.release();
442+
sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
443+
find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
444+
style, SkToBool(elegant),
445+
SkString(), character);
446+
if (matchingTypeface) {
447+
return matchingTypeface.release();
448+
}
439449
}
440450
}
441451
return nullptr;
@@ -521,30 +531,37 @@ class SkFontMgr_Android : public SkFontMgr {
521531
SkTArray<NameToFamily, true> fNameToFamilyMap;
522532
SkTArray<NameToFamily, true> fFallbackNameToFamilyMap;
523533

524-
void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const bool isolated) {
525-
for (int i = 0; i < families.count(); i++) {
526-
FontFamily& family = *families[i];
527-
528-
SkTArray<NameToFamily, true>* nameToFamily = &fNameToFamilyMap;
529-
if (family.fIsFallbackFont) {
530-
nameToFamily = &fFallbackNameToFamilyMap;
534+
void addFamily(FontFamily& family, const bool isolated, int familyIndex) {
535+
SkTArray<NameToFamily, true>* nameToFamily = &fNameToFamilyMap;
536+
if (family.fIsFallbackFont) {
537+
nameToFamily = &fFallbackNameToFamilyMap;
531538

532-
if (0 == family.fNames.count()) {
533-
SkString& fallbackName = family.fNames.push_back();
534-
fallbackName.printf("%.2x##fallback", i);
535-
}
539+
if (0 == family.fNames.count()) {
540+
SkString& fallbackName = family.fNames.push_back();
541+
fallbackName.printf("%.2x##fallback", familyIndex);
536542
}
543+
}
537544

538-
sk_sp<SkFontStyleSet_Android> newSet =
539-
sk_make_sp<SkFontStyleSet_Android>(family, fScanner, isolated);
540-
if (0 == newSet->count()) {
541-
continue;
542-
}
545+
sk_sp<SkFontStyleSet_Android> newSet =
546+
sk_make_sp<SkFontStyleSet_Android>(family, fScanner, isolated);
547+
if (0 == newSet->count()) {
548+
return;
549+
}
543550

544-
for (const SkString& name : family.fNames) {
545-
nameToFamily->emplace_back(NameToFamily{name, newSet.get()});
546-
}
547-
fStyleSets.emplace_back(std::move(newSet));
551+
for (const SkString& name : family.fNames) {
552+
nameToFamily->emplace_back(NameToFamily{name, newSet.get()});
553+
}
554+
fStyleSets.emplace_back(std::move(newSet));
555+
}
556+
void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const bool isolated) {
557+
int familyIndex = 0;
558+
for (FontFamily* family : families) {
559+
addFamily(*family, isolated, familyIndex++);
560+
family->fallbackFamilies.foreach([this, isolated, &familyIndex]
561+
(SkString, std::unique_ptr<FontFamily>* fallbackFamily) {
562+
addFamily(*(*fallbackFamily).get(), isolated, familyIndex++);
563+
}
564+
);
548565
}
549566
}
550567

src/ports/SkFontMgr_android_parser.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ static const TagHandler fontHandler = {
208208
// The character data should be a filename.
209209
FontFileInfo& file = self->fCurrentFamily->fFonts.push_back();
210210
self->fCurrentFontInfo = &file;
211+
SkString fallbackFor;
211212
for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
212213
const char* name = attributes[i];
213214
const char* value = attributes[i+1];
@@ -227,8 +228,27 @@ static const TagHandler fontHandler = {
227228
if (!parse_non_negative_integer(value, &file.fIndex)) {
228229
SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
229230
}
231+
} else if (MEMEQ("fallbackFor", name, nameLen)) {
232+
/** fallbackFor specifies a family fallback and should have been on family. */
233+
fallbackFor = value;
230234
}
231235
}
236+
if (!fallbackFor.isEmpty()) {
237+
std::unique_ptr<FontFamily>* fallbackFamily =
238+
self->fCurrentFamily->fallbackFamilies.find(fallbackFor);
239+
if (!fallbackFamily) {
240+
std::unique_ptr<FontFamily> newFallbackFamily(
241+
new FontFamily(self->fCurrentFamily->fBasePath, true));
242+
fallbackFamily = self->fCurrentFamily->fallbackFamilies.set(
243+
fallbackFor, std::move(newFallbackFamily));
244+
(*fallbackFamily)->fLanguages = self->fCurrentFamily->fLanguages;
245+
(*fallbackFamily)->fVariant = self->fCurrentFamily->fVariant;
246+
(*fallbackFamily)->fOrder = self->fCurrentFamily->fOrder;
247+
(*fallbackFamily)->fFallbackFor = fallbackFor;
248+
}
249+
self->fCurrentFontInfo = &(*fallbackFamily)->fFonts.emplace_back(file);
250+
self->fCurrentFamily->fFonts.pop_back();
251+
}
232252
},
233253
/*end*/[](FamilyData* self, const char* tag) {
234254
trim_string(&self->fCurrentFontInfo->fFileName);

src/ports/SkFontMgr_android_parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "SkString.h"
1313
#include "SkTArray.h"
1414
#include "SkTDArray.h"
15+
#include "SkTHash.h"
1516
#include "SkTypes.h"
1617

1718
#include <climits>
@@ -94,9 +95,11 @@ struct FontFamily {
9495
SkTArray<SkString, true> fNames;
9596
SkTArray<FontFileInfo, true> fFonts;
9697
SkTArray<SkLanguage, true> fLanguages;
98+
SkTHashMap<SkString, std::unique_ptr<FontFamily>> fallbackFamilies;
9799
FontVariant fVariant;
98100
int fOrder; // internal to the parser, not useful to users.
99101
bool fIsFallbackFont;
102+
SkString fFallbackFor;
100103
const SkString fBasePath;
101104
};
102105

tests/FontMgrAndroidParserTest.cpp

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ static bool isDIGIT(int c) {
4040
return ('0' <= c && c <= '9');
4141
}
4242

43-
void ValidateLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* firstExpectedFile,
44-
skiatest::Reporter* reporter) {
43+
static void ValidateLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* firstExpectedFile,
44+
skiatest::Reporter* reporter) {
4545
REPORTER_ASSERT(reporter, fontFamilies[0]->fNames.count() == 5);
4646
REPORTER_ASSERT(reporter, !strcmp(fontFamilies[0]->fNames[0].c_str(), "sans-serif"));
4747
REPORTER_ASSERT(reporter,
@@ -73,7 +73,23 @@ void ValidateLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* firstE
7373
}
7474
}
7575

76-
void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* label) {
76+
static void DumpFiles(const FontFamily& fontFamily) {
77+
for (int j = 0; j < fontFamily.fFonts.count(); ++j) {
78+
const FontFileInfo& ffi = fontFamily.fFonts[j];
79+
SkDebugf(" file (%d) %s#%d", ffi.fWeight, ffi.fFileName.c_str(), ffi.fIndex);
80+
for (const auto& coordinate : ffi.fVariationDesignPosition) {
81+
SkDebugf(" @'%c%c%c%c'=%f",
82+
(coordinate.axis >> 24) & 0xFF,
83+
(coordinate.axis >> 16) & 0xFF,
84+
(coordinate.axis >> 8) & 0xFF,
85+
(coordinate.axis ) & 0xFF,
86+
coordinate.value);
87+
}
88+
SkDebugf("\n");
89+
}
90+
}
91+
92+
static void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* label) {
7793
if (!FLAGS_verboseFontMgr) {
7894
return;
7995
}
@@ -97,19 +113,13 @@ void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* label) {
97113
for (int j = 0; j < fontFamilies[i]->fNames.count(); ++j) {
98114
SkDebugf(" name %s\n", fontFamilies[i]->fNames[j].c_str());
99115
}
100-
for (int j = 0; j < fontFamilies[i]->fFonts.count(); ++j) {
101-
const FontFileInfo& ffi = fontFamilies[i]->fFonts[j];
102-
SkDebugf(" file (%d) %s#%d", ffi.fWeight, ffi.fFileName.c_str(), ffi.fIndex);
103-
for (const auto& coordinate : ffi.fVariationDesignPosition) {
104-
SkDebugf(" @'%c%c%c%c'=%f",
105-
(coordinate.axis >> 24) & 0xFF,
106-
(coordinate.axis >> 16) & 0xFF,
107-
(coordinate.axis >> 8) & 0xFF,
108-
(coordinate.axis ) & 0xFF,
109-
coordinate.value);
116+
DumpFiles(*fontFamilies[i]);
117+
fontFamilies[i]->fallbackFamilies.foreach(
118+
[](SkString, std::unique_ptr<FontFamily>* fallbackFamily) {
119+
SkDebugf(" Fallback for: %s\n", (*fallbackFamily)->fFallbackFor.c_str());
120+
DumpFiles(*(*fallbackFamily).get());
110121
}
111-
SkDebugf("\n");
112-
}
122+
);
113123
}
114124
SkDebugf("\n\n");
115125
}
@@ -340,4 +350,29 @@ DEF_TEST(FontMgrAndroidSystemVariableTypeface, reporter) {
340350
}
341351
}
342352

353+
DEF_TEST(FontMgrAndroidSystemFallbackFor, reporter) {
354+
constexpr char fontsXmlFilename[] = "fonts/fonts.xml";
355+
SkString basePath = GetResourcePath("fonts/");
356+
SkString fontsXml = GetResourcePath(fontsXmlFilename);
357+
358+
if (!sk_exists(fontsXml.c_str())) {
359+
ERRORF(reporter, "file missing: %s\n", fontsXmlFilename);
360+
return;
361+
}
362+
363+
SkFontMgr_Android_CustomFonts custom;
364+
custom.fSystemFontUse = SkFontMgr_Android_CustomFonts::kOnlyCustom;
365+
custom.fBasePath = basePath.c_str();
366+
custom.fFontsXml = fontsXml.c_str();
367+
custom.fFallbackFontsXml = nullptr;
368+
custom.fIsolated = false;
369+
370+
sk_sp<SkFontMgr> fontMgr(SkFontMgr_New_Android(&custom));
371+
// "sans-serif" in "fonts/fonts.xml" is "fonts/Distortable.ttf", which doesn't have a '!'
372+
// but "TestTTC" has a bold font which does have '!' and is marked as fallback for "sans-serif"
373+
// and should take precedence over the same font marked as normal weight next to it.
374+
sk_sp<SkTypeface> typeface(fontMgr->matchFamilyStyleCharacter(
375+
"sans-serif", SkFontStyle(), nullptr, 0, '!'));
343376

377+
REPORTER_ASSERT(reporter, typeface->fontStyle() == SkFontStyle::Bold());
378+
}

0 commit comments

Comments
 (0)