Index: src/ports/SkFontMgr_android.cpp |
diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp |
index 2bae9ca0e51a62409f61c51839ddccc3c0368316..31b5346a10686a1e0955cfdc1183e3f7ba2f15a8 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, |
+ uint32_t variantStyle) |
: INHERITED(index, style, isFixedPitch, familyName) |
- , fPathName(pathName) { } |
+ , fPathName(pathName) |
+ , fLang(lang) |
+ , fVariantStyle(variantStyle) { } |
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 uint32_t fVariantStyle; |
typedef SkTypeface_Android INHERITED; |
}; |
@@ -120,33 +125,52 @@ 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(); |
+ uint32_t variant = fontFile.fPaintOptions.getFontVariant(); |
+ if (SkPaintOptionsAndroid::kDefault_Variant == variant) { |
+ variant = SkPaintOptionsAndroid::kCompact_Variant | |
+ SkPaintOptionsAndroid::kElegant_Variant; |
+ } |
+ |
+ // 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 +188,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 +199,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 +237,7 @@ private: |
return score; |
} |
- SkTArray<SkAutoTUnref<SkTypeface>, true> fStyles; |
+ SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles; |
friend struct NameToFamily; |
friend class SkFontMgr_Android; |
@@ -273,6 +297,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 +324,54 @@ protected: |
return NULL; |
} |
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], |
+ const SkFontStyle& style, |
+ const char bpc47[], |
+ uint32_t character) const SK_OVERRIDE |
+ { |
+ // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'. |
+ // The variant 'default' means 'compact and elegant'. |
+ // As a result, it is not possible to know the variant context from the font alone. |
+ // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request. |
+ |
+ // For compatibility, try 'elegant' fonts first in fallback. |
+ uint32_t variantMask = SkPaintOptionsAndroid::kElegant_Variant; |
+ |
+ // The first time match anything in the mask, second time anything not in the mask. |
+ for (bool maskMatches = true; maskMatches != false; maskMatches = false) { |
+ SkLanguage lang(bpc47); |
+ // Match against the language, removing a segment each time. |
+ // The last time through the loop, the language will be empty. |
+ // The empty language is special, and matches all languages. |
+ 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->fVariantStyle & variantMask) != maskMatches) { |
+ 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)); |
+ } |
+ 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 +425,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; |
} |
} |
} |