Home | History | Annotate | Download | only in fonts
      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 "SkFontMgr_indirect.h"
      9 
     10 #include "SkDataTable.h"
     11 #include "SkFontStyle.h"
     12 #include "SkOnce.h"
     13 #include "SkStream.h"
     14 #include "SkTSearch.h"
     15 #include "SkTypeface.h"
     16 
     17 class SkData;
     18 class SkString;
     19 
     20 class SkStyleSet_Indirect : public SkFontStyleSet {
     21 public:
     22     /** Takes ownership of the SkRemotableFontIdentitySet. */
     23     SkStyleSet_Indirect(const SkFontMgr_Indirect* owner, int familyIndex,
     24                         SkRemotableFontIdentitySet* data)
     25         : fOwner(SkRef(owner)), fFamilyIndex(familyIndex), fData(data)
     26     { }
     27 
     28     virtual int count() SK_OVERRIDE { return fData->count(); }
     29 
     30     virtual void getStyle(int index, SkFontStyle* fs, SkString* style) SK_OVERRIDE {
     31         if (fs) {
     32             *fs = fData->at(index).fFontStyle;
     33         }
     34         if (style) {
     35             // TODO: is this useful? Current locale?
     36             style->reset();
     37         }
     38     }
     39 
     40     virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
     41         return fOwner->createTypefaceFromFontId(fData->at(index));
     42     }
     43 
     44     virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
     45         if (fFamilyIndex >= 0) {
     46             SkFontIdentity id = fOwner->fProxy->matchIndexStyle(fFamilyIndex, pattern);
     47             return fOwner->createTypefaceFromFontId(id);
     48         }
     49 
     50         // If this SkStyleSet was created via onMatchFamily we would need a call like
     51         // fOwner->fProxy->matchNameStyle(fFamilyName, pattern);
     52         // but would not activate fonts (only consider fonts which would come back from matchName).
     53 
     54         // CSS policy sounds good.
     55         struct Score {
     56             int score;
     57             int index;
     58         };
     59 
     60         // Width has the greatest priority.
     61         // If the value of pattern.width is 5 (normal) or less,
     62         //    narrower width values are checked first, then wider values.
     63         // If the value of pattern.width is greater than 5 (normal),
     64         //    wider values are checked first, followed by narrower values.
     65 
     66         // Italic/Oblique has the next highest priority.
     67         // If italic requested and there is some italic font, use it.
     68         // If oblique requested and there is some oblique font, use it.
     69         // If italic requested and there is some oblique font, use it.
     70         // If oblique requested and there is some italic font, use it.
     71 
     72         // Exact match.
     73         // If pattern.weight < 400, weights below pattern.weight are checked
     74         //   in descending order followed by weights above pattern.weight
     75         //   in ascending order until a match is found.
     76         // If pattern.weight > 500, weights above pattern.weight are checked
     77         //   in ascending order followed by weights below pattern.weight
     78         //   in descending order until a match is found.
     79         // If pattern.weight is 400, 500 is checked first
     80         //   and then the rule for pattern.weight < 400 is used.
     81         // If pattern.weight is 500, 400 is checked first
     82         //   and then the rule for pattern.weight < 400 is used
     83 
     84         Score maxScore = { 0, 0 };
     85         for (int i = 0; i < fData->count(); ++i) {
     86             const SkFontStyle& current = fData->at(i).fFontStyle;
     87             Score currentScore = { 0, i };
     88 
     89             // CSS stretch. (This is the width.)
     90             // This has the highest priority.
     91             if (pattern.width() <= SkFontStyle::kNormal_Width) {
     92                 if (current.width() <= pattern.width()) {
     93                     currentScore.score += 10 - pattern.width() + current.width();
     94                 } else {
     95                     currentScore.score += 10 - current.width();
     96                 }
     97             } else {
     98                 if (current.width() > pattern.width()) {
     99                     currentScore.score += 10 + pattern.width() - current.width();
    100                 } else {
    101                     currentScore.score += current.width();
    102                 }
    103             }
    104             currentScore.score *= 1002;
    105 
    106             // CSS style (italic/oblique)
    107             // Being italic trumps all valid weights which are not italic.
    108             // Note that newer specs differentiate between italic and oblique.
    109             if (pattern.isItalic() && current.isItalic()) {
    110                 currentScore.score += 1001;
    111             }
    112 
    113             // Synthetics (weight/style) [no stretch synthetic?]
    114 
    115             // The 'closer' to the target weight, the higher the score.
    116             // 1000 is the 'heaviest' recognized weight
    117             if (pattern.weight() == current.weight()) {
    118                 currentScore.score += 1000;
    119             } else if (pattern.weight() <= 500) {
    120                 if (pattern.weight() >= 400 && pattern.weight() < 450) {
    121                     if (current.weight() >= 450 && current.weight() <= 500) {
    122                         // Artificially boost the 500 weight.
    123                         // TODO: determine correct number to use.
    124                         currentScore.score += 500;
    125                     }
    126                 }
    127                 if (current.weight() <= pattern.weight()) {
    128                     currentScore.score += 1000 - pattern.weight() + current.weight();
    129                 } else {
    130                     currentScore.score += 1000 - current.weight();
    131                 }
    132             } else if (pattern.weight() > 500) {
    133                 if (current.weight() > pattern.weight()) {
    134                     currentScore.score += 1000 + pattern.weight() - current.weight();
    135                 } else {
    136                     currentScore.score += current.weight();
    137                 }
    138             }
    139 
    140             if (currentScore.score > maxScore.score) {
    141                 maxScore = currentScore;
    142             }
    143         }
    144 
    145         return this->createTypeface(maxScore.index);
    146     }
    147 private:
    148     SkAutoTUnref<const SkFontMgr_Indirect> fOwner;
    149     int fFamilyIndex;
    150     SkAutoTUnref<SkRemotableFontIdentitySet> fData;
    151 };
    152 
    153 void SkFontMgr_Indirect::set_up_family_names(const SkFontMgr_Indirect* self) {
    154     self->fFamilyNames.reset(self->fProxy->getFamilyNames());
    155 }
    156 
    157 int SkFontMgr_Indirect::onCountFamilies() const {
    158     SkOnce(&fFamilyNamesInited, &fFamilyNamesMutex, SkFontMgr_Indirect::set_up_family_names, this);
    159     return fFamilyNames->count();
    160 }
    161 
    162 void SkFontMgr_Indirect::onGetFamilyName(int index, SkString* familyName) const {
    163     SkOnce(&fFamilyNamesInited, &fFamilyNamesMutex, SkFontMgr_Indirect::set_up_family_names, this);
    164     if (index >= fFamilyNames->count()) {
    165         familyName->reset();
    166         return;
    167     }
    168     familyName->set(fFamilyNames->atStr(index));
    169 }
    170 
    171 SkFontStyleSet* SkFontMgr_Indirect::onCreateStyleSet(int index) const {
    172     SkRemotableFontIdentitySet* set = fProxy->getIndex(index);
    173     if (NULL == set) {
    174         return NULL;
    175     }
    176     return SkNEW_ARGS(SkStyleSet_Indirect, (this, index, set));
    177 }
    178 
    179 SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const {
    180     return SkNEW_ARGS(SkStyleSet_Indirect, (this, -1, fProxy->matchName(familyName)));
    181 }
    182 
    183 SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& id) const {
    184     if (id.fDataId == SkFontIdentity::kInvalidDataId) {
    185         return NULL;
    186     }
    187 
    188     SkAutoMutexAcquire ama(fDataCacheMutex);
    189 
    190     SkAutoTUnref<SkTypeface> dataTypeface;
    191     int dataTypefaceIndex = 0;
    192     for (int i = 0; i < fDataCache.count(); ++i) {
    193         const DataEntry& entry = fDataCache[i];
    194         if (entry.fDataId == id.fDataId) {
    195             if (entry.fTtcIndex == id.fTtcIndex &&
    196                 !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref())
    197             {
    198                 return entry.fTypeface;
    199             }
    200             if (dataTypeface.get() == NULL &&
    201                 !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref())
    202             {
    203                 dataTypeface.reset(entry.fTypeface);
    204                 dataTypefaceIndex = entry.fTtcIndex;
    205             }
    206         }
    207 
    208         if (entry.fTypeface->weak_expired()) {
    209             fDataCache.removeShuffle(i);
    210             --i;
    211         }
    212     }
    213 
    214     // No exact match, but did find a data match.
    215     if (dataTypeface.get() != NULL) {
    216         SkAutoTUnref<SkStream> stream(dataTypeface->openStream(NULL));
    217         if (stream.get() != NULL) {
    218             return fImpl->createFromStream(stream.get(), dataTypefaceIndex);
    219         }
    220     }
    221 
    222     // No data match, request data and add entry.
    223     SkAutoTUnref<SkStreamAsset> stream(fProxy->getData(id.fDataId));
    224     if (stream.get() == NULL) {
    225         return NULL;
    226     }
    227 
    228     SkAutoTUnref<SkTypeface> typeface(fImpl->createFromStream(stream, id.fTtcIndex));
    229     if (typeface.get() == NULL) {
    230         return NULL;
    231     }
    232 
    233     DataEntry& newEntry = fDataCache.push_back();
    234     typeface->weak_ref();
    235     newEntry.fDataId = id.fDataId;
    236     newEntry.fTtcIndex = id.fTtcIndex;
    237     newEntry.fTypeface = typeface.get();  // weak reference passed to new entry.
    238 
    239     return typeface.detach();
    240 }
    241 
    242 SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyle(const char familyName[],
    243                                                    const SkFontStyle& fontStyle) const {
    244     SkFontIdentity id = fProxy->matchNameStyle(familyName, fontStyle);
    245     return this->createTypefaceFromFontId(id);
    246 }
    247 
    248 SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
    249                                                             const SkFontStyle& style,
    250                                                             const char bpc47[],
    251                                                             uint32_t character) const {
    252     SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bpc47, character);
    253     return this->createTypefaceFromFontId(id);
    254 }
    255 
    256 SkTypeface* SkFontMgr_Indirect::onMatchFaceStyle(const SkTypeface* familyMember,
    257                                                  const SkFontStyle& fontStyle) const {
    258     SkString familyName;
    259     familyMember->getFamilyName(&familyName);
    260     return this->matchFamilyStyle(familyName.c_str(), fontStyle);
    261 }
    262 
    263 SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStream* stream, int ttcIndex) const {
    264     return fImpl->createFromStream(stream, ttcIndex);
    265 }
    266 
    267 SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const {
    268     return fImpl->createFromFile(path, ttcIndex);
    269 }
    270 
    271 SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const {
    272     return fImpl->createFromData(data, ttcIndex);
    273 }
    274 
    275 SkTypeface* SkFontMgr_Indirect::onLegacyCreateTypeface(const char familyName[],
    276                                                        unsigned styleBits) const {
    277     bool bold = SkToBool(styleBits & SkTypeface::kBold);
    278     bool italic = SkToBool(styleBits & SkTypeface::kItalic);
    279     SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
    280                                          : SkFontStyle::kNormal_Weight,
    281                                     SkFontStyle::kNormal_Width,
    282                                     italic ? SkFontStyle::kItalic_Slant
    283                                            : SkFontStyle::kUpright_Slant);
    284 
    285     SkAutoTUnref<SkTypeface> face(this->matchFamilyStyle(familyName, style));
    286 
    287     if (NULL == face.get()) {
    288         face.reset(this->matchFamilyStyle(NULL, style));
    289     }
    290 
    291     if (NULL == face.get()) {
    292         SkFontIdentity fontId = this->fProxy->matchIndexStyle(0, style);
    293         face.reset(this->createTypefaceFromFontId(fontId));
    294     }
    295 
    296     return face.detach();
    297 }
    298