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 "SkAdvancedTypefaceMetrics.h"
      9 #include "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkDescriptor.h"
     12 #include "SkFontDescriptor.h"
     13 #include "SkGlyph.h"
     14 #include "SkMakeUnique.h"
     15 #include "SkMask.h"
     16 #include "SkPaintPriv.h"
     17 #include "SkScalerContext.h"
     18 #include "SkTestScalerContext.h"
     19 #include "SkTypefaceCache.h"
     20 
     21 SkTestFont::SkTestFont(const SkTestFontData& fontData)
     22     : INHERITED()
     23     , fCharCodes(fontData.fCharCodes)
     24     , fCharCodesCount(fontData.fCharCodes ? fontData.fCharCodesCount : 0)
     25     , fWidths(fontData.fWidths)
     26     , fMetrics(fontData.fMetrics)
     27     , fName(fontData.fName)
     28     , fPaths(nullptr)
     29 {
     30     init(fontData.fPoints, fontData.fVerbs);
     31 #ifdef SK_DEBUG
     32     sk_bzero(fDebugBits, sizeof(fDebugBits));
     33     sk_bzero(fDebugOverage, sizeof(fDebugOverage));
     34 #endif
     35 }
     36 
     37 SkTestFont::~SkTestFont() {
     38     for (unsigned index = 0; index < fCharCodesCount; ++index) {
     39         delete fPaths[index];
     40     }
     41     delete[] fPaths;
     42 }
     43 
     44 #ifdef SK_DEBUG
     45 
     46 #include "SkMutex.h"
     47 SK_DECLARE_STATIC_MUTEX(gUsedCharsMutex);
     48 
     49 #endif
     50 
     51 int SkTestFont::codeToIndex(SkUnichar charCode) const {
     52 #ifdef SK_DEBUG  // detect missing test font data
     53     {
     54         SkAutoMutexAcquire ac(gUsedCharsMutex);
     55         if (charCode >= ' ' && charCode <= '~') {
     56             int bitOffset = charCode - ' ';
     57             fDebugBits[bitOffset >> 3] |= 1 << (bitOffset & 7);
     58         } else {
     59             int index = 0;
     60             while (fDebugOverage[index] != 0 && fDebugOverage[index] != charCode
     61                     && index < (int) sizeof(fDebugOverage)) {
     62                 ++index;
     63             }
     64             SkASSERT(index < (int) sizeof(fDebugOverage));
     65             if (fDebugOverage[index] == 0) {
     66                 fDebugOverage[index] = charCode;
     67             }
     68         }
     69     }
     70 #endif
     71     for (unsigned index = 0; index < fCharCodesCount; ++index) {
     72         if (fCharCodes[index] == (unsigned) charCode) {
     73             return (int) index;
     74         }
     75     }
     76 
     77     SkDEBUGF(("missing '%c' (%d) from %s (weight %d, width %d, slant %d)\n",
     78               (char) charCode, charCode, fDebugName,
     79               fDebugStyle.weight(), fDebugStyle.width(), fDebugStyle.slant()));
     80     return 0;
     81 }
     82 
     83 void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) {
     84     fPaths = new SkPath* [fCharCodesCount];
     85     for (unsigned index = 0; index < fCharCodesCount; ++index) {
     86         SkPath* path = new SkPath;
     87         SkPath::Verb verb;
     88         while ((verb = (SkPath::Verb) *verbs++) != SkPath::kDone_Verb) {
     89             switch (verb) {
     90                 case SkPath::kMove_Verb:
     91                     path->moveTo(pts[0], pts[1]);
     92                     pts += 2;
     93                     break;
     94                 case SkPath::kLine_Verb:
     95                     path->lineTo(pts[0], pts[1]);
     96                     pts += 2;
     97                     break;
     98                 case SkPath::kQuad_Verb:
     99                     path->quadTo(pts[0], pts[1], pts[2], pts[3]);
    100                     pts += 4;
    101                     break;
    102                 case SkPath::kCubic_Verb:
    103                     path->cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
    104                     pts += 6;
    105                     break;
    106                 case SkPath::kClose_Verb:
    107                     path->close();
    108                     break;
    109                 default:
    110                     SkDEBUGFAIL("bad verb");
    111                     return;
    112             }
    113         }
    114         // This should make SkPath::getBounds() queries threadsafe.
    115         path->updateBoundsCache();
    116         fPaths[index] = path;
    117     }
    118 }
    119 
    120 SkTestTypeface::SkTestTypeface(sk_sp<SkTestFont> testFont, const SkFontStyle& style)
    121     : SkTypeface(style, false)
    122     , fTestFont(std::move(testFont)) {
    123 }
    124 
    125 void SkTestTypeface::getAdvance(SkGlyph* glyph) {
    126     // TODO(benjaminwagner): Update users to use floats.
    127     glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyph->getGlyphID()]);
    128     glyph->fAdvanceY = 0;
    129 }
    130 
    131 void SkTestTypeface::getFontMetrics(SkPaint::FontMetrics* metrics) {
    132     *metrics = fTestFont->fMetrics;
    133 }
    134 
    135 void SkTestTypeface::getMetrics(SkGlyph* glyph) {
    136     // TODO(benjaminwagner): Update users to use floats.
    137     glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyph->getGlyphID()]);
    138     glyph->fAdvanceY = 0;
    139 }
    140 
    141 void SkTestTypeface::getPath(SkGlyphID glyph, SkPath* path) {
    142     *path = *fTestFont->fPaths[glyph];
    143 }
    144 
    145 void SkTestTypeface::onFilterRec(SkScalerContextRec* rec) const {
    146     rec->setHinting(SkPaint::kNo_Hinting);
    147 }
    148 
    149 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTestTypeface::onGetAdvancedMetrics() const { // pdf only
    150     std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
    151     info->fFontName.set(fTestFont->fName);
    152     int glyphCount = this->onCountGlyphs();
    153 
    154     SkTDArray<SkUnichar>& toUnicode = info->fGlyphToUnicode;
    155     toUnicode.setCount(glyphCount);
    156     SkASSERT(glyphCount == SkToInt(fTestFont->fCharCodesCount));
    157     for (int gid = 0; gid < glyphCount; ++gid) {
    158         toUnicode[gid] = SkToS32(fTestFont->fCharCodes[gid]);
    159     }
    160     return info;
    161 }
    162 
    163 void SkTestTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
    164     desc->setFamilyName(fTestFont->fName);
    165     desc->setStyle(this->fontStyle());
    166     *isLocal = false;
    167 }
    168 
    169 int SkTestTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
    170                                     uint16_t glyphs[], int glyphCount) const {
    171     SkASSERT(encoding == kUTF32_Encoding);
    172     for (int index = 0; index < glyphCount; ++index) {
    173         SkUnichar ch = ((SkUnichar*) chars)[index];
    174         glyphs[index] = fTestFont->codeToIndex(ch);
    175     }
    176     return glyphCount;
    177 }
    178 
    179 void SkTestTypeface::onGetFamilyName(SkString* familyName) const {
    180     *familyName = fTestFont->fName;
    181 }
    182 
    183 SkTypeface::LocalizedStrings* SkTestTypeface::onCreateFamilyNameIterator() const {
    184     SkString familyName(fTestFont->fName);
    185     SkString language("und"); //undetermined
    186 //SkASSERT(0);  // incomplete
    187     return nullptr;
    188 //     return new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
    189 }
    190 
    191 class SkTestScalerContext : public SkScalerContext {
    192 public:
    193     SkTestScalerContext(sk_sp<SkTestTypeface> face, const SkScalerContextEffects& effects,
    194                         const SkDescriptor* desc)
    195         : SkScalerContext(std::move(face), effects, desc)
    196     {
    197         fRec.getSingleMatrix(&fMatrix);
    198         this->forceGenerateImageFromPath();
    199     }
    200 
    201 protected:
    202     SkTestTypeface* getTestTypeface() const {
    203         return static_cast<SkTestTypeface*>(this->getTypeface());
    204     }
    205 
    206     unsigned generateGlyphCount() override {
    207         return this->getTestTypeface()->onCountGlyphs();
    208     }
    209 
    210     uint16_t generateCharToGlyph(SkUnichar uni) override {
    211         uint16_t glyph;
    212         (void) this->getTestTypeface()->onCharsToGlyphs((const void *) &uni,
    213                                                         SkTypeface::kUTF32_Encoding, &glyph, 1);
    214         return glyph;
    215     }
    216 
    217     void generateAdvance(SkGlyph* glyph) override {
    218         this->getTestTypeface()->getAdvance(glyph);
    219 
    220         const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX),
    221                                                SkFloatToScalar(glyph->fAdvanceY));
    222         glyph->fAdvanceX = SkScalarToFloat(advance.fX);
    223         glyph->fAdvanceY = SkScalarToFloat(advance.fY);
    224     }
    225 
    226     void generateMetrics(SkGlyph* glyph) override {
    227         this->getTestTypeface()->getMetrics(glyph);
    228 
    229         const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX),
    230                                                SkFloatToScalar(glyph->fAdvanceY));
    231         glyph->fAdvanceX = SkScalarToFloat(advance.fX);
    232         glyph->fAdvanceY = SkScalarToFloat(advance.fY);
    233 
    234         SkPath path;
    235         this->getTestTypeface()->getPath(glyph->getGlyphID(), &path);
    236         path.transform(fMatrix);
    237 
    238         SkRect storage;
    239         const SkPaint paint;
    240         const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(),
    241                                                             &storage,
    242                                                             SkPaint::kFill_Style);
    243         SkIRect ibounds;
    244         newBounds.roundOut(&ibounds);
    245         glyph->fLeft = ibounds.fLeft;
    246         glyph->fTop = ibounds.fTop;
    247         glyph->fWidth = ibounds.width();
    248         glyph->fHeight = ibounds.height();
    249     }
    250 
    251     void generateImage(const SkGlyph& glyph) override {
    252         SkPath path;
    253         this->getTestTypeface()->getPath(glyph.getGlyphID(), &path);
    254 
    255         SkBitmap bm;
    256         bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight),
    257                             glyph.fImage, glyph.rowBytes());
    258         bm.eraseColor(0);
    259 
    260         SkCanvas canvas(bm);
    261         canvas.translate(-SkIntToScalar(glyph.fLeft),
    262                             -SkIntToScalar(glyph.fTop));
    263         canvas.concat(fMatrix);
    264         SkPaint paint;
    265         paint.setAntiAlias(true);
    266         canvas.drawPath(path, paint);
    267     }
    268 
    269     void generatePath(SkGlyphID glyph, SkPath* path) override {
    270         this->getTestTypeface()->getPath(glyph, path);
    271         path->transform(fMatrix);
    272     }
    273 
    274     void generateFontMetrics(SkPaint::FontMetrics* metrics) override {
    275         this->getTestTypeface()->getFontMetrics(metrics);
    276         SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY());
    277     }
    278 
    279 private:
    280     SkMatrix         fMatrix;
    281 };
    282 
    283 SkScalerContext* SkTestTypeface::onCreateScalerContext(
    284     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
    285 {
    286     return new SkTestScalerContext(sk_ref_sp(const_cast<SkTestTypeface*>(this)), effects, desc);
    287 }
    288