Chromium Code Reviews| Index: src/ports/SkFontMgr_android.cpp |
| diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp |
| index 2bae9ca0e51a62409f61c51839ddccc3c0368316..616ff22076b9ad32bf0938bbc28605e88e7ec31a 100644 |
| --- a/src/ports/SkFontMgr_android.cpp |
| +++ b/src/ports/SkFontMgr_android.cpp |
| @@ -59,9 +59,13 @@ public: |
| int index, |
| Style style, |
| bool isFixedPitch, |
| - const SkString familyName) |
| + const SkString familyName, |
| + const SkLanguage& lang, |
| + SkPaintOptionsAndroid::FontVariant variant) |
| : INHERITED(index, style, isFixedPitch, familyName) |
| - , fPathName(pathName) { } |
| + , fPathName(pathName) |
| + , fLang(lang) |
| + , fVariant(variant) { } |
| virtual void onGetFontDescriptor(SkFontDescriptor* desc, |
| bool* serialize) const SK_OVERRIDE { |
| @@ -76,8 +80,9 @@ public: |
| return SkStream::NewFromFile(fPathName.c_str()); |
| } |
| -private: |
| - SkString fPathName; |
| + const SkString fPathName; |
| + const SkLanguage fLang; |
| + const SkPaintOptionsAndroid::FontVariant fVariant; |
| typedef SkTypeface_Android INHERITED; |
| }; |
| @@ -120,33 +125,48 @@ void get_path_for_sys_fonts(SkString* full, const SkString& name) { |
| class SkFontStyleSet_Android : public SkFontStyleSet { |
| public: |
| - explicit SkFontStyleSet_Android(FontFamily* family) { |
| + explicit SkFontStyleSet_Android(const FontFamily& family) { |
| + const SkString* cannonicalFamilyName = NULL; |
| + if (family.fNames.count() > 0) { |
| + cannonicalFamilyName = &family.fNames[0]; |
| + } |
| // TODO? make this lazy |
| - for (int i = 0; i < family->fFontFiles.count(); ++i) { |
| - const SkString& fileName = family->fFontFiles[i].fFileName; |
| + for (int i = 0; i < family.fFontFiles.count(); ++i) { |
| + const FontFileInfo& fontFile = family.fFontFiles[i]; |
| SkString pathName; |
| - get_path_for_sys_fonts(&pathName, fileName); |
| + get_path_for_sys_fonts(&pathName, fontFile.fFileName); |
| SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str())); |
| if (!stream.get()) { |
| - DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, fileName.c_str())); |
| + DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, pathName.c_str())); |
| continue; |
| } |
| - const int ttcIndex = family->fFontFiles[i].fIndex; |
| - SkString fontName; |
| + const int ttcIndex = fontFile.fIndex; |
| + SkString familyName; |
| SkTypeface::Style style; |
| bool isFixedWidth; |
| if (!SkTypeface_FreeType::ScanFont(stream.get(), ttcIndex, |
| - &fontName, &style, &isFixedWidth)) { |
| - DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, fileName.c_str())); |
| + &familyName, &style, &isFixedWidth)) { |
| + DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, pathName.c_str())); |
| continue; |
| } |
| + const SkLanguage& lang = fontFile.fPaintOptions.getLanguage(); |
| + SkPaintOptionsAndroid::FontVariant variant = fontFile.fPaintOptions.getFontVariant(); |
| + |
| + // The first specified family name overrides the family name found in the font. |
| + // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return |
| + // all of the specified family names in addition to the names found in the font. |
| + if (cannonicalFamilyName != NULL) { |
| + familyName = *cannonicalFamilyName; |
| + } |
| + |
| fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem, |
| (pathName, ttcIndex, |
| - style, isFixedWidth, fontName))); |
| + style, isFixedWidth, familyName, |
| + lang, variant))); |
| } |
| } |
| @@ -164,7 +184,7 @@ public: |
| name->reset(); |
| } |
| } |
| - virtual SkTypeface* createTypeface(int index) SK_OVERRIDE { |
| + virtual SkTypeface_AndroidSystem* createTypeface(int index) SK_OVERRIDE { |
| if (index < 0 || fStyles.count() <= index) { |
| return NULL; |
| } |
| @@ -175,11 +195,11 @@ public: |
| * TODO: consider replacing with SkStyleSet_Indirect::matchStyle(); |
| * this simpler version using match_score() passes all our tests. |
| */ |
| - virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { |
| + virtual SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { |
| if (0 == fStyles.count()) { |
| return NULL; |
| } |
| - SkTypeface* closest = fStyles[0]; |
| + SkTypeface_AndroidSystem* closest = fStyles[0]; |
| int minScore = std::numeric_limits<int>::max(); |
| for (int i = 0; i < fStyles.count(); ++i) { |
| SkFontStyle style = this->style(i); |
| @@ -213,7 +233,7 @@ private: |
| return score; |
| } |
| - SkTArray<SkAutoTUnref<SkTypeface>, true> fStyles; |
| + SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles; |
| friend struct NameToFamily; |
| friend class SkFontMgr_Android; |
| @@ -273,6 +293,12 @@ protected: |
| return SkRef(fNameToFamilyMap[i].styleSet); |
| } |
| } |
| + // TODO: eventually we should not need to name fallback families. |
| + for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) { |
| + if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) { |
| + return SkRef(fFallbackNameToFamilyMap[i].styleSet); |
| + } |
| + } |
| return NULL; |
| } |
| @@ -294,6 +320,60 @@ protected: |
| return NULL; |
| } |
| + virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], |
| + const SkFontStyle& style, |
| + const char bpc47[], |
| + uint32_t character) const SK_OVERRIDE |
| + { |
| + // If the familyName maps to a family, then match the style and get the variant. |
| + // Otherwise "elegant" unless the family name ends in "compact". |
| + bool isCompact = false; |
| + if (familyName) { |
| + size_t familyNameLen = strlen(familyName); |
| + static const char compactLiteral[] = "compact"; |
| + static const size_t compactLiteralLen = SK_ARRAY_COUNT(compactLiteral); |
| + if (compactLiteralLen <= familyNameLen) { |
|
djsollen
2014/08/01 20:24:04
should this be < or would a font with the name "co
bungeman-skia
2014/08/04 19:24:20
So, when I wrote this I was under the impression f
|
| + const char* familyNameEnd = familyName + familyNameLen - compactLiteralLen; |
| + isCompact = SkToBool(strcmp(familyNameEnd, compactLiteral)); |
| + } |
| + } |
| + |
| + uint32_t ignoredVariantMask = SkPaintOptionsAndroid::kCompact_Variant; |
| + if (isCompact) { |
| + ignoredVariantMask = ~SkPaintOptionsAndroid::kCompact_Variant; |
| + } |
| + |
| + for (int i = 0; i < 2; ++i, ignoredVariantMask = ~ignoredVariantMask) { |
|
djsollen
2014/08/01 20:24:04
document that the second time through the loop loo
bungeman-skia
2014/08/04 19:24:20
Changed the logic to make this more obvious and ad
|
| + SkLanguage lang(bpc47); |
| + do { |
| + const SkString& langTag = lang.getTag(); |
| + for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) { |
| + SkFontStyleSet_Android* family = fFallbackNameToFamilyMap[i].styleSet; |
| + SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style)); |
| + |
| + if (!langTag.isEmpty() && langTag != face->fLang.getTag()) { |
| + continue; |
| + } |
| + |
| + if (SkToBool(face->fVariant & ignoredVariantMask)) { |
| + continue; |
| + } |
| + |
| + SkPaint paint; |
| + paint.setTypeface(face); |
| + paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
| + |
| + uint16_t glyphID; |
| + paint.textToGlyphs(&character, sizeof(character), &glyphID); |
| + if (glyphID != 0) { |
| + return face.detach(); |
| + } |
| + } |
| + } while (!lang.getTag().isEmpty() && (lang = lang.getParent(), true)); |
|
djsollen
2014/08/01 20:24:04
At first glance it is not clear that the last run
bungeman-skia
2014/08/04 19:24:20
Documented.
|
| + } |
| + return NULL; |
| + } |
| + |
| virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE { |
| SkAutoTUnref<SkStream> stream(new SkMemoryStream(data)); |
| return this->createFromStream(stream, ttcIndex); |
| @@ -347,15 +427,33 @@ private: |
| SkTypeface* fDefaultTypeface; |
| SkTDArray<NameToFamily> fNameToFamilyMap; |
| + SkTDArray<NameToFamily> fFallbackNameToFamilyMap; |
| void buildNameToFamilyMap(SkTDArray<FontFamily*> families) { |
| for (int i = 0; i < families.count(); i++) { |
| - fFontStyleSets.push_back().reset( |
| - SkNEW_ARGS(SkFontStyleSet_Android, (families[i]))); |
| - for (int j = 0; j < families[i]->fNames.count(); j++) { |
| - NameToFamily* nextEntry = fNameToFamilyMap.append(); |
| - SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (families[i]->fNames[j])); |
| - nextEntry->styleSet = fFontStyleSets.back().get(); |
| + FontFamily& family = *families[i]; |
| + |
| + SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap; |
| + if (family.fIsFallbackFont) { |
| + nameToFamily = &fFallbackNameToFamilyMap; |
| + |
| + if (0 == family.fNames.count()) { |
| + SkString& fallbackName = family.fNames.push_back(); |
| + fallbackName.printf("%.2x##fallback", i); |
| + } |
| + } |
| + |
| + SkFontStyleSet_Android* newSet = SkNEW_ARGS(SkFontStyleSet_Android, (family)); |
| + if (0 == newSet->count()) { |
| + SkDELETE(newSet); |
| + continue; |
| + } |
| + fFontStyleSets.push_back().reset(newSet); |
| + |
| + for (int j = 0; j < family.fNames.count(); j++) { |
| + NameToFamily* nextEntry = nameToFamily->append(); |
| + SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j])); |
| + nextEntry->styleSet = newSet; |
| } |
| } |
| } |