Home | History | Annotate | Download | only in ports
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkTypes.h"
      9 
     10 #include "SkData.h"
     11 #include "SkFixed.h"
     12 #include "SkFontDescriptor.h"
     13 #include "SkFontHost_FreeType_common.h"
     14 #include "SkFontMgr.h"
     15 #include "SkFontMgr_android.h"
     16 #include "SkFontMgr_android_parser.h"
     17 #include "SkFontStyle.h"
     18 #include "SkOSFile.h"
     19 #include "SkPaint.h"
     20 #include "SkRefCnt.h"
     21 #include "SkString.h"
     22 #include "SkStream.h"
     23 #include "SkTArray.h"
     24 #include "SkTDArray.h"
     25 #include "SkTSearch.h"
     26 #include "SkTemplates.h"
     27 #include "SkTypefaceCache.h"
     28 
     29 #include <limits>
     30 
     31 class SkData;
     32 
     33 class SkTypeface_Android : public SkTypeface_FreeType {
     34 public:
     35     SkTypeface_Android(const SkFontStyle& style,
     36                        bool isFixedPitch,
     37                        const SkString& familyName)
     38         : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
     39         , fFamilyName(familyName)
     40         { }
     41 
     42 protected:
     43     void onGetFamilyName(SkString* familyName) const override {
     44         *familyName = fFamilyName;
     45     }
     46 
     47     SkString fFamilyName;
     48 
     49 private:
     50     typedef SkTypeface_FreeType INHERITED;
     51 };
     52 
     53 class SkTypeface_AndroidSystem : public SkTypeface_Android {
     54 public:
     55     SkTypeface_AndroidSystem(const SkString& pathName,
     56                              const bool cacheFontFiles,
     57                              int index,
     58                              const SkFixed* axes, int axesCount,
     59                              const SkFontStyle& style,
     60                              bool isFixedPitch,
     61                              const SkString& familyName,
     62                              const SkLanguage& lang,
     63                              FontVariant variantStyle)
     64         : INHERITED(style, isFixedPitch, familyName)
     65         , fPathName(pathName)
     66         , fIndex(index)
     67         , fAxes(axes, axesCount)
     68         , fLang(lang)
     69         , fVariantStyle(variantStyle)
     70         , fFile(cacheFontFiles ? sk_fopen(fPathName.c_str(), kRead_SkFILE_Flag) : nullptr) {
     71         if (cacheFontFiles) {
     72             SkASSERT(fFile);
     73         }
     74     }
     75 
     76     SkStreamAsset* createStream() const {
     77         if (fFile) {
     78             SkData* data = SkData::NewFromFILE(fFile);
     79             return data ? new SkMemoryStream(data) : nullptr;
     80         }
     81         return SkStream::NewFromFile(fPathName.c_str());
     82     }
     83 
     84     virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
     85         SkASSERT(desc);
     86         SkASSERT(serialize);
     87         desc->setFamilyName(fFamilyName.c_str());
     88         *serialize = false;
     89     }
     90     SkStreamAsset* onOpenStream(int* ttcIndex) const override {
     91         *ttcIndex = fIndex;
     92         return this->createStream();
     93     }
     94     SkFontData* onCreateFontData() const override {
     95         return new SkFontData(this->createStream(), fIndex, fAxes.begin(), fAxes.count());
     96     }
     97 
     98     const SkString fPathName;
     99     int fIndex;
    100     const SkSTArray<4, SkFixed, true> fAxes;
    101     const SkLanguage fLang;
    102     const FontVariant fVariantStyle;
    103     SkAutoTCallVProc<FILE, sk_fclose> fFile;
    104 
    105     typedef SkTypeface_Android INHERITED;
    106 };
    107 
    108 class SkTypeface_AndroidStream : public SkTypeface_Android {
    109 public:
    110     SkTypeface_AndroidStream(SkFontData* data,
    111                              const SkFontStyle& style,
    112                              bool isFixedPitch,
    113                              const SkString& familyName)
    114         : INHERITED(style, isFixedPitch, familyName)
    115         , fData(data)
    116     { }
    117 
    118     virtual void onGetFontDescriptor(SkFontDescriptor* desc,
    119                                      bool* serialize) const override {
    120         SkASSERT(desc);
    121         SkASSERT(serialize);
    122         desc->setFamilyName(fFamilyName.c_str());
    123         *serialize = true;
    124     }
    125 
    126     SkStreamAsset* onOpenStream(int* ttcIndex) const override {
    127         *ttcIndex = fData->getIndex();
    128         return fData->duplicateStream();
    129     }
    130 
    131     SkFontData* onCreateFontData() const override {
    132         return new SkFontData(*fData.get());
    133     }
    134 
    135 private:
    136     const SkAutoTDelete<const SkFontData> fData;
    137     typedef SkTypeface_Android INHERITED;
    138 };
    139 
    140 class SkFontStyleSet_Android : public SkFontStyleSet {
    141     typedef SkTypeface_FreeType::Scanner Scanner;
    142 
    143 public:
    144     explicit SkFontStyleSet_Android(const FontFamily& family, const Scanner& scanner,
    145                                     const bool cacheFontFiles) {
    146         const SkString* cannonicalFamilyName = nullptr;
    147         if (family.fNames.count() > 0) {
    148             cannonicalFamilyName = &family.fNames[0];
    149         }
    150         // TODO? make this lazy
    151         for (int i = 0; i < family.fFonts.count(); ++i) {
    152             const FontFileInfo& fontFile = family.fFonts[i];
    153 
    154             SkString pathName(family.fBasePath);
    155             pathName.append(fontFile.fFileName);
    156 
    157             SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(pathName.c_str()));
    158             if (!stream.get()) {
    159                 SkDEBUGF(("Requested font file %s does not exist or cannot be opened.\n",
    160                           pathName.c_str()));
    161                 continue;
    162             }
    163 
    164             const int ttcIndex = fontFile.fIndex;
    165             SkString familyName;
    166             SkFontStyle style;
    167             bool isFixedWidth;
    168             Scanner::AxisDefinitions axisDefinitions;
    169             if (!scanner.scanFont(stream.get(), ttcIndex,
    170                                   &familyName, &style, &isFixedWidth, &axisDefinitions))
    171             {
    172                 SkDEBUGF(("Requested font file %s exists, but is not a valid font.\n",
    173                           pathName.c_str()));
    174                 continue;
    175             }
    176 
    177             int weight = fontFile.fWeight != 0 ? fontFile.fWeight : style.weight();
    178             SkFontStyle::Slant slant = style.slant();
    179             switch (fontFile.fStyle) {
    180                 case FontFileInfo::Style::kAuto: slant = style.slant(); break;
    181                 case FontFileInfo::Style::kNormal: slant = SkFontStyle::kUpright_Slant; break;
    182                 case FontFileInfo::Style::kItalic: slant = SkFontStyle::kItalic_Slant; break;
    183                 default: SkASSERT(false); break;
    184             }
    185             style = SkFontStyle(weight, style.width(), slant);
    186 
    187             const SkLanguage& lang = family.fLanguage;
    188             uint32_t variant = family.fVariant;
    189             if (kDefault_FontVariant == variant) {
    190                 variant = kCompact_FontVariant | kElegant_FontVariant;
    191             }
    192 
    193             // The first specified family name overrides the family name found in the font.
    194             // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
    195             // all of the specified family names in addition to the names found in the font.
    196             if (cannonicalFamilyName != nullptr) {
    197                 familyName = *cannonicalFamilyName;
    198             }
    199 
    200             SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
    201             Scanner::computeAxisValues(axisDefinitions,
    202                                        fontFile.fAxes.begin(), fontFile.fAxes.count(),
    203                                        axisValues, familyName);
    204 
    205             fStyles.push_back().reset(new SkTypeface_AndroidSystem(
    206                     pathName, cacheFontFiles, ttcIndex, axisValues.get(), axisDefinitions.count(),
    207                     style, isFixedWidth, familyName, lang, variant));
    208         }
    209     }
    210 
    211     int count() override {
    212         return fStyles.count();
    213     }
    214     void getStyle(int index, SkFontStyle* style, SkString* name) override {
    215         if (index < 0 || fStyles.count() <= index) {
    216             return;
    217         }
    218         if (style) {
    219             *style = this->style(index);
    220         }
    221         if (name) {
    222             name->reset();
    223         }
    224     }
    225     SkTypeface_AndroidSystem* createTypeface(int index) override {
    226         if (index < 0 || fStyles.count() <= index) {
    227             return nullptr;
    228         }
    229         return SkRef(fStyles[index].get());
    230     }
    231 
    232     /** Find the typeface in this style set that most closely matches the given pattern.
    233      *  TODO: consider replacing with SkStyleSet_Indirect::matchStyle();
    234      *  this simpler version using match_score() passes all our tests.
    235      */
    236     SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) override {
    237         if (0 == fStyles.count()) {
    238             return nullptr;
    239         }
    240         SkTypeface_AndroidSystem* closest = fStyles[0];
    241         int minScore = std::numeric_limits<int>::max();
    242         for (int i = 0; i < fStyles.count(); ++i) {
    243             SkFontStyle style = this->style(i);
    244             int score = match_score(pattern, style);
    245             if (score < minScore) {
    246                 closest = fStyles[i];
    247                 minScore = score;
    248             }
    249         }
    250         return SkRef(closest);
    251     }
    252 
    253 private:
    254     SkFontStyle style(int index) {
    255         return fStyles[index]->fontStyle();
    256     }
    257     static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
    258         int score = 0;
    259         score += SkTAbs((pattern.width() - candidate.width()) * 100);
    260         score += SkTAbs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
    261         score += SkTAbs(pattern.weight() - candidate.weight());
    262         return score;
    263     }
    264 
    265     SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles;
    266 
    267     friend struct NameToFamily;
    268     friend class SkFontMgr_Android;
    269 
    270     typedef SkFontStyleSet INHERITED;
    271 };
    272 
    273 /** On Android a single family can have many names, but our API assumes unique names.
    274  *  Map names to the back end so that all names for a given family refer to the same
    275  *  (non-replicated) set of typefaces.
    276  *  SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
    277  */
    278 struct NameToFamily {
    279     SkString name;
    280     SkFontStyleSet_Android* styleSet;
    281 };
    282 
    283 class SkFontMgr_Android : public SkFontMgr {
    284 public:
    285     SkFontMgr_Android(const SkFontMgr_Android_CustomFonts* custom) {
    286         SkTDArray<FontFamily*> families;
    287         if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem != custom->fSystemFontUse) {
    288             SkString base(custom->fBasePath);
    289             SkFontMgr_Android_Parser::GetCustomFontFamilies(
    290                 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
    291         }
    292         if (!custom ||
    293             (custom && SkFontMgr_Android_CustomFonts::kOnlyCustom != custom->fSystemFontUse))
    294         {
    295             SkFontMgr_Android_Parser::GetSystemFontFamilies(families);
    296         }
    297         if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem == custom->fSystemFontUse) {
    298             SkString base(custom->fBasePath);
    299             SkFontMgr_Android_Parser::GetCustomFontFamilies(
    300                 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
    301         }
    302         this->buildNameToFamilyMap(families, custom ? custom->fIsolated : false);
    303         this->findDefaultFont();
    304         families.deleteAll();
    305     }
    306 
    307 protected:
    308     /** Returns not how many families we have, but how many unique names
    309      *  exist among the families.
    310      */
    311     int onCountFamilies() const override {
    312         return fNameToFamilyMap.count();
    313     }
    314 
    315     void onGetFamilyName(int index, SkString* familyName) const override {
    316         if (index < 0 || fNameToFamilyMap.count() <= index) {
    317             familyName->reset();
    318             return;
    319         }
    320         familyName->set(fNameToFamilyMap[index].name);
    321     }
    322 
    323     SkFontStyleSet* onCreateStyleSet(int index) const override {
    324         if (index < 0 || fNameToFamilyMap.count() <= index) {
    325             return nullptr;
    326         }
    327         return SkRef(fNameToFamilyMap[index].styleSet);
    328     }
    329 
    330     SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
    331         if (!familyName) {
    332             return nullptr;
    333         }
    334         SkAutoAsciiToLC tolc(familyName);
    335         for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
    336             if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
    337                 return SkRef(fNameToFamilyMap[i].styleSet);
    338             }
    339         }
    340         // TODO: eventually we should not need to name fallback families.
    341         for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
    342             if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
    343                 return SkRef(fFallbackNameToFamilyMap[i].styleSet);
    344             }
    345         }
    346         return nullptr;
    347     }
    348 
    349     virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
    350                                            const SkFontStyle& style) const override {
    351         SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
    352         return sset->matchStyle(style);
    353     }
    354 
    355     virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
    356                                          const SkFontStyle& style) const override {
    357         for (int i = 0; i < fFontStyleSets.count(); ++i) {
    358             for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
    359                 if (fFontStyleSets[i]->fStyles[j] == typeface) {
    360                     return fFontStyleSets[i]->matchStyle(style);
    361                 }
    362             }
    363         }
    364         return nullptr;
    365     }
    366 
    367     static SkTypeface_AndroidSystem* find_family_style_character(
    368             const SkTDArray<NameToFamily>& fallbackNameToFamilyMap,
    369             const SkFontStyle& style, bool elegant,
    370             const SkString& langTag, SkUnichar character)
    371     {
    372         for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) {
    373             SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
    374             SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
    375 
    376             if (!langTag.isEmpty() && !face->fLang.getTag().startsWith(langTag.c_str())) {
    377                 continue;
    378             }
    379 
    380             if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
    381                 continue;
    382             }
    383 
    384             SkPaint paint;
    385             paint.setTypeface(face);
    386             paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
    387 
    388             uint16_t glyphID;
    389             paint.textToGlyphs(&character, sizeof(character), &glyphID);
    390             if (glyphID != 0) {
    391                 return face.detach();
    392             }
    393         }
    394         return nullptr;
    395     }
    396 
    397     virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
    398                                                     const SkFontStyle& style,
    399                                                     const char* bcp47[],
    400                                                     int bcp47Count,
    401                                                     SkUnichar character) const override
    402     {
    403         // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
    404         // The variant 'default' means 'compact and elegant'.
    405         // As a result, it is not possible to know the variant context from the font alone.
    406         // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
    407 
    408         // The first time match anything elegant, second time anything not elegant.
    409         for (int elegant = 2; elegant --> 0;) {
    410             for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
    411                 SkLanguage lang(bcp47[bcp47Index]);
    412                 while (!lang.getTag().isEmpty()) {
    413                     SkTypeface_AndroidSystem* matchingTypeface =
    414                         find_family_style_character(fFallbackNameToFamilyMap,
    415                                                     style, SkToBool(elegant),
    416                                                     lang.getTag(), character);
    417                     if (matchingTypeface) {
    418                         return matchingTypeface;
    419                     }
    420 
    421                     lang = lang.getParent();
    422                 }
    423             }
    424             SkTypeface_AndroidSystem* matchingTypeface =
    425                 find_family_style_character(fFallbackNameToFamilyMap,
    426                                             style, SkToBool(elegant),
    427                                             SkString(), character);
    428             if (matchingTypeface) {
    429                 return matchingTypeface;
    430             }
    431         }
    432         return nullptr;
    433     }
    434 
    435     SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
    436         return this->createFromStream(new SkMemoryStream(data), ttcIndex);
    437     }
    438 
    439     SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
    440         SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path));
    441         return stream.get() ? this->createFromStream(stream.detach(), ttcIndex) : nullptr;
    442     }
    443 
    444     SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
    445         SkAutoTDelete<SkStreamAsset> stream(bareStream);
    446         bool isFixedPitch;
    447         SkFontStyle style;
    448         SkString name;
    449         if (!fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch, nullptr)) {
    450             return nullptr;
    451         }
    452         SkFontData* data(new SkFontData(stream.detach(), ttcIndex, nullptr, 0));
    453         return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
    454     }
    455 
    456     SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
    457         using Scanner = SkTypeface_FreeType::Scanner;
    458         SkAutoTDelete<SkStreamAsset> stream(s);
    459         bool isFixedPitch;
    460         SkFontStyle style;
    461         SkString name;
    462         Scanner::AxisDefinitions axisDefinitions;
    463         if (!fScanner.scanFont(stream, params.getCollectionIndex(), &name, &style, &isFixedPitch,
    464                                &axisDefinitions))
    465         {
    466             return nullptr;
    467         }
    468 
    469         int paramAxisCount;
    470         const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
    471         SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
    472         Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
    473 
    474         SkFontData* data(new SkFontData(stream.detach(), params.getCollectionIndex(),
    475                                         axisValues.get(), axisDefinitions.count()));
    476         return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
    477     }
    478 
    479     SkTypeface* onCreateFromFontData(SkFontData* data) const override {
    480         SkStreamAsset* stream(data->getStream());
    481         bool isFixedPitch;
    482         SkFontStyle style;
    483         SkString name;
    484         if (!fScanner.scanFont(stream, data->getIndex(), &name, &style, &isFixedPitch, nullptr)) {
    485             return nullptr;
    486         }
    487         return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
    488     }
    489 
    490 
    491     virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
    492                                                unsigned styleBits) const override {
    493         SkFontStyle style = SkFontStyle(styleBits);
    494 
    495         if (familyName) {
    496             // On Android, we must return nullptr when we can't find the requested
    497             // named typeface so that the system/app can provide their own recovery
    498             // mechanism. On other platforms we'd provide a typeface from the
    499             // default family instead.
    500             return this->onMatchFamilyStyle(familyName, style);
    501         }
    502         return fDefaultFamily->matchStyle(style);
    503     }
    504 
    505 
    506 private:
    507 
    508     SkTypeface_FreeType::Scanner fScanner;
    509 
    510     SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
    511     SkFontStyleSet* fDefaultFamily;
    512     SkTypeface* fDefaultTypeface;
    513 
    514     SkTDArray<NameToFamily> fNameToFamilyMap;
    515     SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
    516 
    517     void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const bool isolated) {
    518         for (int i = 0; i < families.count(); i++) {
    519             FontFamily& family = *families[i];
    520 
    521             SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
    522             if (family.fIsFallbackFont) {
    523                 nameToFamily = &fFallbackNameToFamilyMap;
    524 
    525                 if (0 == family.fNames.count()) {
    526                     SkString& fallbackName = family.fNames.push_back();
    527                     fallbackName.printf("%.2x##fallback", i);
    528                 }
    529             }
    530 
    531             SkFontStyleSet_Android* newSet = new SkFontStyleSet_Android(family, fScanner, isolated);
    532             if (0 == newSet->count()) {
    533                 delete newSet;
    534                 continue;
    535             }
    536             fFontStyleSets.push_back().reset(newSet);
    537 
    538             for (int j = 0; j < family.fNames.count(); j++) {
    539                 NameToFamily* nextEntry = nameToFamily->append();
    540                 new (&nextEntry->name) SkString(family.fNames[j]);
    541                 nextEntry->styleSet = newSet;
    542             }
    543         }
    544     }
    545 
    546     void findDefaultFont() {
    547         SkASSERT(!fFontStyleSets.empty());
    548 
    549         static const char* gDefaultNames[] = { "sans-serif" };
    550         for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
    551             SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
    552             if (nullptr == set) {
    553                 continue;
    554             }
    555             SkTypeface* tf = set->matchStyle(SkFontStyle());
    556             if (nullptr == tf) {
    557                 continue;
    558             }
    559             fDefaultFamily = set;
    560             fDefaultTypeface = tf;
    561             break;
    562         }
    563         if (nullptr == fDefaultTypeface) {
    564             fDefaultFamily = fFontStyleSets[0];
    565             fDefaultTypeface = fDefaultFamily->createTypeface(0);
    566         }
    567         SkASSERT(fDefaultFamily);
    568         SkASSERT(fDefaultTypeface);
    569     }
    570 
    571     typedef SkFontMgr INHERITED;
    572 };
    573 
    574 #ifdef SK_DEBUG
    575 static char const * const gSystemFontUseStrings[] = {
    576     "OnlyCustom", "PreferCustom", "PreferSystem"
    577 };
    578 #endif
    579 SkFontMgr* SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) {
    580     if (custom) {
    581         SkASSERT(0 <= custom->fSystemFontUse);
    582         SkASSERT(custom->fSystemFontUse < SK_ARRAY_COUNT(gSystemFontUseStrings));
    583         SkDEBUGF(("SystemFontUse: %s BasePath: %s Fonts: %s FallbackFonts: %s\n",
    584                   gSystemFontUseStrings[custom->fSystemFontUse],
    585                   custom->fBasePath,
    586                   custom->fFontsXml,
    587                   custom->fFallbackFontsXml));
    588     }
    589 
    590     return new SkFontMgr_Android(custom);
    591 }
    592