static Vector<String> strongAliasesForFamily(const String& family) { RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate()); if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(family.utf8().data()))) return Vector<String>(); FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern); FcDefaultSubstitute(pattern.get()); FcUniquePtr<FcObjectSet> familiesOnly(FcObjectSetBuild(FC_FAMILY, nullptr)); RefPtr<FcPattern> minimal = adoptRef(FcPatternFilter(pattern.get(), familiesOnly.get())); // We really want to match strong (preferred) and same (acceptable) only here. // If a family name was specified, assume that any weak matches after the last strong match // are weak (default) and ignore them. // The reason for is that after substitution the pattern for 'sans-serif' looks like // "wwwwwwwwwwwwwwswww" where there are many weak but preferred names, followed by defaults. // So it is possible to have weakly matching but preferred names. // In aliases, bindings are weak by default, so this is easy and common. // If no family name was specified, we'll probably only get weak matches, but that's ok. int lastStrongId = -1; int numIds = 0; for (int id = 0; ; ++id) { AliasStrength result = strengthOfFirstAlias(*minimal); if (result == AliasStrength::Done) { numIds = id; break; } if (result == AliasStrength::Strong) lastStrongId = id; if (!FcPatternRemove(minimal.get(), FC_FAMILY, 0)) return Vector<String>(); } // If they were all weak, then leave the pattern alone. if (lastStrongId < 0) return Vector<String>(); // Remove everything after the last strong. for (int id = lastStrongId + 1; id < numIds; ++id) { if (!FcPatternRemove(pattern.get(), FC_FAMILY, lastStrongId + 1)) { ASSERT_NOT_REACHED(); return Vector<String>(); } } // Take the resulting pattern and remove everything but the families. minimal = adoptRef(FcPatternFilter(pattern.get(), familiesOnly.get())); // Convert the pattern to a string, and cut out the non-family junk that gets added to the end. char* patternChars = reinterpret_cast<char*>(FcPatternFormat(pattern.get(), reinterpret_cast<const FcChar8*>("%{family}"))); String patternString = String::fromUTF8(patternChars); free(patternChars); Vector<String> results; patternString.split(',', results); return results; }
Vector<String> FontCache::systemFontFamilies() { RefPtr<FcPattern> scalablesOnlyPattern = adoptRef(FcPatternCreate()); FcPatternAddBool(scalablesOnlyPattern.get(), FC_SCALABLE, FcTrue); FcUniquePtr<FcObjectSet> familiesOnly(FcObjectSetBuild(FC_FAMILY, nullptr)); FcUniquePtr<FcFontSet> fontSet(FcFontList(nullptr, scalablesOnlyPattern.get(), familiesOnly.get())); Vector<String> fontFamilies; for (int i = 0; i < fontSet->nfont; i++) { FcPattern* pattern = fontSet->fonts[i]; FcChar8* family = nullptr; FcPatternGetString(pattern, FC_FAMILY, 0, &family); if (family) fontFamilies.appendVector(patternToFamilies(*pattern)); } return fontFamilies; }