LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/ports - SkFontHost_cairo.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 188 388 48.5 %
Date: 2017-07-14 16:53:18 Functions: 21 44 47.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /*
       3             :  * Copyright 2012 Mozilla Foundation
       4             :  *
       5             :  * Use of this source code is governed by a BSD-style license that can be
       6             :  * found in the LICENSE file.
       7             :  */
       8             : 
       9             : #include "cairo.h"
      10             : #include "cairo-ft.h"
      11             : 
      12             : #include "SkFontHost_FreeType_common.h"
      13             : 
      14             : #include "SkAdvancedTypefaceMetrics.h"
      15             : #include "SkFDot6.h"
      16             : #include "SkPath.h"
      17             : #include "SkScalerContext.h"
      18             : #include "SkTypefaceCache.h"
      19             : 
      20             : #include <cmath>
      21             : 
      22             : #include <ft2build.h>
      23             : #include FT_FREETYPE_H
      24             : #include FT_OUTLINE_H
      25             : 
      26             : // for FT_GlyphSlot_Embolden
      27             : #ifdef FT_SYNTHESIS_H
      28             : #include FT_SYNTHESIS_H
      29             : #endif
      30             : 
      31             : // for FT_Library_SetLcdFilter
      32             : #ifdef FT_LCD_FILTER_H
      33             : #include FT_LCD_FILTER_H
      34             : #else
      35             : typedef enum FT_LcdFilter_
      36             : {
      37             :     FT_LCD_FILTER_NONE    = 0,
      38             :     FT_LCD_FILTER_DEFAULT = 1,
      39             :     FT_LCD_FILTER_LIGHT   = 2,
      40             :     FT_LCD_FILTER_LEGACY  = 16,
      41             : } FT_LcdFilter;
      42             : #endif
      43             : 
      44             : // If compiling with FreeType before 2.5.0
      45             : #ifndef FT_LOAD_COLOR
      46             : #    define FT_LOAD_COLOR ( 1L << 20 )
      47             : #    define FT_PIXEL_MODE_BGRA 7
      48             : #endif
      49             : 
      50             : #ifndef SK_CAN_USE_DLOPEN
      51             : #define SK_CAN_USE_DLOPEN 1
      52             : #endif
      53             : #if SK_CAN_USE_DLOPEN
      54             : #include <dlfcn.h>
      55             : #endif
      56             : 
      57             : #ifndef SK_FONTHOST_CAIRO_STANDALONE
      58             : #define SK_FONTHOST_CAIRO_STANDALONE 1
      59             : #endif
      60             : 
      61             : static cairo_user_data_key_t kSkTypefaceKey;
      62             : 
      63             : static bool gFontHintingEnabled = true;
      64             : static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr;
      65             : static void (*gGlyphSlotEmbolden)(FT_GlyphSlot) = nullptr;
      66             : 
      67           3 : void SkInitCairoFT(bool fontHintingEnabled)
      68             : {
      69           3 :     gFontHintingEnabled = fontHintingEnabled;
      70             : #if SK_CAN_USE_DLOPEN
      71           3 :     gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
      72           3 :     gGlyphSlotEmbolden = (void (*)(FT_GlyphSlot))dlsym(RTLD_DEFAULT, "FT_GlyphSlot_Embolden");
      73             : #else
      74             :     gSetLcdFilter = &FT_Library_SetLcdFilter;
      75             :     gGlyphSlotEmbolden = &FT_GlyphSlot_Embolden;
      76             : #endif
      77             :     // FT_Library_SetLcdFilter may be provided but have no effect if FreeType
      78             :     // is built without FT_CONFIG_OPTION_SUBPIXEL_RENDERING.
      79           6 :     if (gSetLcdFilter &&
      80           6 :         gSetLcdFilter(nullptr, FT_LCD_FILTER_NONE) == FT_Err_Unimplemented_Feature) {
      81           0 :         gSetLcdFilter = nullptr;
      82             :     }
      83           3 : }
      84             : 
      85             : #ifndef CAIRO_HAS_FC_FONT
      86             : typedef struct _FcPattern FcPattern;
      87             : #endif
      88             : 
      89             : class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
      90             : public:
      91             :     SkScalerContext_CairoFT(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc,
      92             :                             cairo_font_face_t* fontFace, FcPattern* pattern);
      93             :     virtual ~SkScalerContext_CairoFT();
      94             : 
      95           2 :     bool isValid() const {
      96           2 :         return fScaledFont != nullptr;
      97             :     }
      98             : 
      99             : protected:
     100             :     virtual unsigned generateGlyphCount() override;
     101             :     virtual uint16_t generateCharToGlyph(SkUnichar uniChar) override;
     102             :     virtual void generateAdvance(SkGlyph* glyph) override;
     103             :     virtual void generateMetrics(SkGlyph* glyph) override;
     104             :     virtual void generateImage(const SkGlyph& glyph) override;
     105             :     virtual void generatePath(const SkGlyphID glyphID, SkPath* path) override;
     106             :     virtual void generateFontMetrics(SkPaint::FontMetrics* metrics) override;
     107             :     virtual SkUnichar generateGlyphToChar(uint16_t glyph) override;
     108             : 
     109             : private:
     110             :     bool computeShapeMatrix(const SkMatrix& m);
     111             :     void prepareGlyph(FT_GlyphSlot glyph);
     112             :     void fixVerticalLayoutBearing(FT_GlyphSlot glyph);
     113             : 
     114             : #ifdef CAIRO_HAS_FC_FONT
     115             :     void parsePattern(FcPattern* pattern);
     116             : #endif
     117             : 
     118             :     cairo_scaled_font_t* fScaledFont;
     119             :     FT_Int32 fLoadGlyphFlags;
     120             :     FT_LcdFilter fLcdFilter;
     121             :     SkScalar fScaleX;
     122             :     SkScalar fScaleY;
     123             :     SkMatrix fShapeMatrix;
     124             :     FT_Matrix fShapeMatrixFT;
     125             :     bool fHaveShape;
     126             : };
     127             : 
     128             : class CairoLockedFTFace {
     129             : public:
     130         122 :     CairoLockedFTFace(cairo_scaled_font_t* scaledFont)
     131         122 :         : fScaledFont(scaledFont)
     132         122 :         , fFace(cairo_ft_scaled_font_lock_face(scaledFont))
     133         122 :     {}
     134             : 
     135         122 :     ~CairoLockedFTFace()
     136         122 :     {
     137         122 :         cairo_ft_scaled_font_unlock_face(fScaledFont);
     138         122 :     }
     139             : 
     140         122 :     FT_Face getFace()
     141             :     {
     142         122 :         return fFace;
     143             :     }
     144             : 
     145             : private:
     146             :     cairo_scaled_font_t* fScaledFont;
     147             :     FT_Face fFace;
     148             : };
     149             : 
     150         120 : template<typename T> static bool isLCD(const T& rec) {
     151         120 :     return SkMask::kLCD16_Format == rec.fMaskFormat;
     152             : }
     153             : 
     154          21 : static bool bothZero(SkScalar a, SkScalar b) {
     155          21 :     return 0 == a && 0 == b;
     156             : }
     157             : 
     158             : // returns false if there is any non-90-rotation or skew
     159          21 : static bool isAxisAligned(const SkScalerContext::Rec& rec) {
     160          63 :     return 0 == rec.fPreSkewX &&
     161          21 :            (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
     162          21 :             bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
     163             : }
     164             : 
     165             : class SkCairoFTTypeface : public SkTypeface {
     166             : public:
     167           2 :     static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, FT_Face face,
     168             :                                       FcPattern* pattern = nullptr) {
     169           2 :         SkASSERT(fontFace != nullptr);
     170           2 :         SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT);
     171           2 :         SkASSERT(face != nullptr);
     172             : 
     173           2 :         SkFontStyle style(face->style_flags & FT_STYLE_FLAG_BOLD ?
     174             :                               SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight,
     175             :                           SkFontStyle::kNormal_Width,
     176           2 :                           face->style_flags & FT_STYLE_FLAG_ITALIC ?
     177           4 :                               SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
     178             : 
     179           2 :         bool isFixedWidth = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
     180             : 
     181           2 :         return new SkCairoFTTypeface(style, isFixedWidth, fontFace, pattern);
     182             :     }
     183             : 
     184           0 :     virtual SkStreamAsset* onOpenStream(int*) const override { return nullptr; }
     185             : 
     186             :     virtual SkAdvancedTypefaceMetrics*
     187           0 :         onGetAdvancedTypefaceMetrics(PerGlyphInfo,
     188             :                                      const uint32_t*, uint32_t) const override
     189             :     {
     190           0 :         SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n"));
     191           0 :         return nullptr;
     192             :     }
     193             : 
     194           2 :     virtual SkScalerContext* onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const override
     195             :     {
     196             :         SkScalerContext_CairoFT* ctx =
     197           4 :             new SkScalerContext_CairoFT(sk_ref_sp(const_cast<SkCairoFTTypeface*>(this)),
     198           4 :                                         effects, desc, fFontFace, fPattern);
     199           2 :         if (!ctx->isValid()) {
     200           0 :             delete ctx;
     201           0 :             return nullptr;
     202             :         }
     203           2 :         return ctx;
     204             :     }
     205             : 
     206          21 :     virtual void onFilterRec(SkScalerContextRec* rec) const override
     207             :     {
     208             :         // No subpixel AA unless enabled in Fontconfig.
     209          21 :         if (!fPattern && isLCD(*rec)) {
     210           0 :             rec->fMaskFormat = SkMask::kA8_Format;
     211             :         }
     212             : 
     213             :         // rotated text looks bad with hinting, so we disable it as needed
     214          21 :         if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
     215           0 :             rec->setHinting(SkPaint::kNo_Hinting);
     216             :         }
     217             : 
     218             :         // Don't apply any gamma so that we match cairo-ft's results.
     219          21 :         rec->ignorePreBlend();
     220          21 :     }
     221             : 
     222           0 :     virtual int onGetVariationDesignPosition(
     223             :         SkFontArguments::VariationPosition::Coordinate coordinates[],
     224             :         int coordinateCount) const override
     225             :     {
     226           0 :         return -1;
     227             :     }
     228             : 
     229           0 :     virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
     230             :     {
     231           0 :         SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n"));
     232           0 :     }
     233             : 
     234           0 :     virtual int onCharsToGlyphs(void const*, SkTypeface::Encoding, uint16_t*, int) const override
     235             :     {
     236           0 :         return 0;
     237             :     }
     238             : 
     239           0 :     virtual int onCountGlyphs() const override
     240             :     {
     241           0 :         return 0;
     242             :     }
     243             : 
     244           0 :     virtual int onGetUPEM() const override
     245             :     {
     246           0 :         return 0;
     247             :     }
     248             : 
     249           0 :     virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override
     250             :     {
     251           0 :         return nullptr;
     252             :     }
     253             : 
     254           0 :     virtual void onGetFamilyName(SkString* familyName) const override
     255             :     {
     256           0 :         familyName->reset();
     257           0 :     }
     258             : 
     259           0 :     virtual int onGetTableTags(SkFontTableTag*) const override
     260             :     {
     261           0 :         return 0;
     262             :     }
     263             : 
     264           0 :     virtual size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override
     265             :     {
     266           0 :         return 0;
     267             :     }
     268             : 
     269             : private:
     270             : 
     271           2 :     SkCairoFTTypeface(const SkFontStyle& style, bool isFixedWidth,
     272             :                       cairo_font_face_t* fontFace, FcPattern* pattern)
     273           2 :         : SkTypeface(style, isFixedWidth)
     274             :         , fFontFace(fontFace)
     275           2 :         , fPattern(pattern)
     276             :     {
     277           2 :         cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, nullptr);
     278           2 :         cairo_font_face_reference(fFontFace);
     279             : #ifdef CAIRO_HAS_FC_FONT
     280           2 :         if (fPattern) {
     281           2 :             FcPatternReference(fPattern);
     282             :         }
     283             : #endif
     284           2 :     }
     285             : 
     286           0 :     ~SkCairoFTTypeface()
     287           0 :     {
     288           0 :         cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, nullptr, nullptr);
     289           0 :         cairo_font_face_destroy(fFontFace);
     290             : #ifdef CAIRO_HAS_FC_FONT
     291           0 :         if (fPattern) {
     292           0 :             FcPatternDestroy(fPattern);
     293             :         }
     294             : #endif
     295           0 :     }
     296             : 
     297             :     cairo_font_face_t* fFontFace;
     298             :     FcPattern* fPattern;
     299             : };
     300             : 
     301          21 : SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern)
     302             : {
     303          21 :     cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(scaledFont);
     304          21 :     SkASSERT(cairo_font_face_status(fontFace) == CAIRO_STATUS_SUCCESS);
     305             : 
     306          21 :     SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey));
     307          21 :     if (typeface) {
     308          19 :         typeface->ref();
     309             :     } else {
     310           4 :         CairoLockedFTFace faceLock(scaledFont);
     311           2 :         if (FT_Face face = faceLock.getFace()) {
     312           2 :             typeface = SkCairoFTTypeface::CreateTypeface(fontFace, face, pattern);
     313           2 :             SkTypefaceCache::Add(typeface);
     314             :         }
     315             :     }
     316             : 
     317          21 :     return typeface;
     318             : }
     319             : 
     320           0 : SkTypeface* SkCreateTypefaceFromCairoFTFont(cairo_scaled_font_t* scaledFont)
     321             : {
     322           0 :     return SkCreateTypefaceFromCairoFTFontWithFontconfig(scaledFont, nullptr);
     323             : }
     324             : 
     325           2 : SkScalerContext_CairoFT::SkScalerContext_CairoFT(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc,
     326           2 :                                                  cairo_font_face_t* fontFace, FcPattern* pattern)
     327           2 :     : SkScalerContext_FreeType_Base(std::move(typeface), effects, desc)
     328           2 :     , fLcdFilter(FT_LCD_FILTER_NONE)
     329             : {
     330             :     SkMatrix matrix;
     331           2 :     fRec.getSingleMatrix(&matrix);
     332             : 
     333             :     cairo_matrix_t fontMatrix, ctMatrix;
     334           2 :     cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0);
     335           2 :     cairo_matrix_init_identity(&ctMatrix);
     336             : 
     337           2 :     cairo_font_options_t *fontOptions = cairo_font_options_create();
     338           2 :     fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
     339           2 :     cairo_font_options_destroy(fontOptions);
     340             : 
     341           2 :     computeShapeMatrix(matrix);
     342             : 
     343           2 :     fRec.fFlags |= SkScalerContext::kEmbeddedBitmapText_Flag;
     344             : 
     345             : #ifdef CAIRO_HAS_FC_FONT
     346           2 :     if (pattern) {
     347           2 :         parsePattern(pattern);
     348             :     }
     349             : #endif
     350             : 
     351           2 :     FT_Int32 loadFlags = FT_LOAD_DEFAULT;
     352             : 
     353           2 :     if (SkMask::kBW_Format == fRec.fMaskFormat) {
     354           0 :         if (fRec.getHinting() == SkPaint::kNo_Hinting) {
     355           0 :             loadFlags |= FT_LOAD_NO_HINTING;
     356             :         } else {
     357           0 :             loadFlags = FT_LOAD_TARGET_MONO;
     358             :         }
     359           0 :         loadFlags |= FT_LOAD_MONOCHROME;
     360             :     } else {
     361           2 :         switch (fRec.getHinting()) {
     362             :         case SkPaint::kNo_Hinting:
     363           0 :             loadFlags |= FT_LOAD_NO_HINTING;
     364           0 :             break;
     365             :         case SkPaint::kSlight_Hinting:
     366           2 :             loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
     367           2 :             break;
     368             :         case SkPaint::kNormal_Hinting:
     369           0 :             if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
     370           0 :                 loadFlags |= FT_LOAD_FORCE_AUTOHINT;
     371             :             }
     372           0 :             break;
     373             :         case SkPaint::kFull_Hinting:
     374           0 :             if (isLCD(fRec)) {
     375           0 :                 if (fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag) {
     376           0 :                     loadFlags = FT_LOAD_TARGET_LCD_V;
     377             :                 } else {
     378           0 :                     loadFlags = FT_LOAD_TARGET_LCD;
     379             :                 }
     380             :             }
     381           0 :             if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
     382           0 :                 loadFlags |= FT_LOAD_FORCE_AUTOHINT;
     383             :             }
     384           0 :             break;
     385             :         default:
     386           0 :             SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
     387           0 :             break;
     388             :         }
     389             :     }
     390             : 
     391             :     // Disable autohinting to disable hinting even for "tricky" fonts.
     392           2 :     if (!gFontHintingEnabled) {
     393           0 :         loadFlags |= FT_LOAD_NO_AUTOHINT;
     394             :     }
     395             : 
     396           2 :     if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
     397           0 :         loadFlags |= FT_LOAD_NO_BITMAP;
     398             :     }
     399             : 
     400             :     // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
     401             :     // advances, as fontconfig and cairo do.
     402             :     // See http://code.google.com/p/skia/issues/detail?id=222.
     403           2 :     loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
     404             : 
     405           2 :     if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
     406           0 :         loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
     407             :     }
     408             : 
     409           2 :     loadFlags |= FT_LOAD_COLOR;
     410             : 
     411           2 :     fLoadGlyphFlags = loadFlags;
     412           2 : }
     413             : 
     414           0 : SkScalerContext_CairoFT::~SkScalerContext_CairoFT()
     415             : {
     416           0 :     cairo_scaled_font_destroy(fScaledFont);
     417           0 : }
     418             : 
     419             : #ifdef CAIRO_HAS_FC_FONT
     420           2 : void SkScalerContext_CairoFT::parsePattern(FcPattern* pattern)
     421             : {
     422             :     FcBool antialias, autohint, bitmap, embolden, hinting, vertical;
     423             : 
     424           2 :     if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
     425           0 :         fRec.fFlags |= SkScalerContext::kForceAutohinting_Flag;
     426             :     }
     427           2 :     if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
     428           0 :         fRec.fFlags |= SkScalerContext::kEmbolden_Flag;
     429             :     }
     430           2 :     if (FcPatternGetBool(pattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
     431           0 :         fRec.fFlags |= SkScalerContext::kVertical_Flag;
     432             :     }
     433             : 
     434             :     // Match cairo-ft's handling of embeddedbitmap:
     435             :     // If AA is explicitly disabled, leave bitmaps enabled.
     436             :     // Otherwise, disable embedded bitmaps unless explicitly enabled.
     437           2 :     if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &antialias) == FcResultMatch && !antialias) {
     438           0 :         fRec.fMaskFormat = SkMask::kBW_Format;
     439           2 :     } else if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &bitmap) != FcResultMatch || !bitmap) {
     440           0 :         fRec.fFlags &= ~SkScalerContext::kEmbeddedBitmapText_Flag;
     441             :     }
     442             : 
     443           2 :     if (fRec.fMaskFormat != SkMask::kBW_Format) {
     444             :         int rgba;
     445           4 :         if (!isLCD(fRec) ||
     446           2 :             FcPatternGetInteger(pattern, FC_RGBA, 0, &rgba) != FcResultMatch) {
     447           0 :             rgba = FC_RGBA_UNKNOWN;
     448             :         }
     449           2 :         switch (rgba) {
     450             :         case FC_RGBA_RGB:
     451           2 :             break;
     452             :         case FC_RGBA_BGR:
     453           0 :             fRec.fFlags |= SkScalerContext::kLCD_BGROrder_Flag;
     454           0 :             break;
     455             :         case FC_RGBA_VRGB:
     456           0 :             fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag;
     457           0 :             break;
     458             :         case FC_RGBA_VBGR:
     459           0 :             fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag |
     460           0 :                            SkScalerContext::kLCD_BGROrder_Flag;
     461           0 :             break;
     462             :         default:
     463           0 :             fRec.fMaskFormat = SkMask::kA8_Format;
     464           0 :             break;
     465             :         }
     466             : 
     467             :         int filter;
     468           2 :         if (isLCD(fRec)) {
     469           2 :             if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) != FcResultMatch) {
     470           0 :                 filter = FC_LCD_LEGACY;
     471             :             }
     472           2 :             switch (filter) {
     473             :             case FC_LCD_NONE:
     474           0 :                 fLcdFilter = FT_LCD_FILTER_NONE;
     475           0 :                 break;
     476             :             case FC_LCD_DEFAULT:
     477           2 :                 fLcdFilter = FT_LCD_FILTER_DEFAULT;
     478           2 :                 break;
     479             :             case FC_LCD_LIGHT:
     480           0 :                 fLcdFilter = FT_LCD_FILTER_LIGHT;
     481           0 :                 break;
     482             :             case FC_LCD_LEGACY:
     483             :             default:
     484           0 :                 fLcdFilter = FT_LCD_FILTER_LEGACY;
     485           0 :                 break;
     486             :             }
     487             :         }
     488             :     }
     489             : 
     490           2 :     if (fRec.getHinting() != SkPaint::kNo_Hinting) {
     491             :         // Hinting was requested, so check if the fontconfig pattern needs to override it.
     492             :         // If hinting is either explicitly enabled by fontconfig or not configured, try to
     493             :         // parse the hint style. Otherwise, ensure hinting is disabled.
     494             :         int hintstyle;
     495           2 :         if (FcPatternGetBool(pattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
     496           2 :             if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
     497           0 :                 hintstyle = FC_HINT_FULL;
     498             :             }
     499             :         } else {
     500           0 :             hintstyle = FC_HINT_NONE;
     501             :         }
     502           2 :         switch (hintstyle) {
     503             :         case FC_HINT_NONE:
     504           0 :             fRec.setHinting(SkPaint::kNo_Hinting);
     505           0 :             break;
     506             :         case FC_HINT_SLIGHT:
     507           2 :             fRec.setHinting(SkPaint::kSlight_Hinting);
     508           2 :             break;
     509             :         case FC_HINT_MEDIUM:
     510             :         default:
     511           0 :             fRec.setHinting(SkPaint::kNormal_Hinting);
     512           0 :             break;
     513             :         case FC_HINT_FULL:
     514           0 :             fRec.setHinting(SkPaint::kFull_Hinting);
     515           0 :             break;
     516             :         }
     517             :     }
     518           2 : }
     519             : #endif
     520             : 
     521           2 : bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m)
     522             : {
     523             :     // Compute a shape matrix compatible with Cairo's _compute_transform.
     524             :     // Finds major/minor scales and uses them to normalize the transform.
     525           2 :     double scaleX = m.getScaleX();
     526           2 :     double skewX = m.getSkewX();
     527           2 :     double skewY = m.getSkewY();
     528           2 :     double scaleY = m.getScaleY();
     529           2 :     double det = scaleX * scaleY - skewY * skewX;
     530           2 :     if (!std::isfinite(det)) {
     531           0 :         fScaleX = fRec.fTextSize * fRec.fPreScaleX;
     532           0 :         fScaleY = fRec.fTextSize;
     533           0 :         fHaveShape = false;
     534           0 :         return false;
     535             :     }
     536           2 :     double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0;
     537           2 :     double minor = major != 0.0 ? fabs(det) / major : 0.0;
     538             :     // Limit scales to be above 1pt.
     539           2 :     major = SkTMax(major, 1.0);
     540           2 :     minor = SkTMax(minor, 1.0);
     541             : 
     542             :     // If the font is not scalable, then choose the best available size.
     543           4 :     CairoLockedFTFace faceLock(fScaledFont);
     544           2 :     FT_Face face = faceLock.getFace();
     545           2 :     if (face && !FT_IS_SCALABLE(face)) {
     546           0 :         double bestDist = DBL_MAX;
     547           0 :         FT_Int bestSize = -1;
     548           0 :         for (FT_Int i = 0; i < face->num_fixed_sizes; i++) {
     549             :             // Distance is positive if strike is larger than desired size,
     550             :             // or negative if smaller. If previously a found smaller strike,
     551             :             // then prefer a larger strike. Otherwise, minimize distance.
     552           0 :             double dist = face->available_sizes[i].y_ppem / 64.0 - minor;
     553           0 :             if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) {
     554           0 :                 bestDist = dist;
     555           0 :                 bestSize = i;
     556             :             }
     557             :         }
     558           0 :         if (bestSize < 0) {
     559           0 :             fScaleX = fRec.fTextSize * fRec.fPreScaleX;
     560           0 :             fScaleY = fRec.fTextSize;
     561           0 :             fHaveShape = false;
     562           0 :             return false;
     563             :         }
     564           0 :         major = face->available_sizes[bestSize].x_ppem / 64.0;
     565           0 :         minor = face->available_sizes[bestSize].y_ppem / 64.0;
     566           0 :         fHaveShape = true;
     567             :     } else {
     568           2 :         fHaveShape = !m.isScaleTranslate();
     569             :     }
     570             : 
     571           2 :     fScaleX = SkDoubleToScalar(major);
     572           2 :     fScaleY = SkDoubleToScalar(minor);
     573             : 
     574           2 :     if (fHaveShape) {
     575             :         // Normalize the transform and convert to fixed-point.
     576           0 :         fShapeMatrix = m;
     577           0 :         fShapeMatrix.preScale(SkDoubleToScalar(1.0 / major), SkDoubleToScalar(1.0 / minor));
     578             : 
     579           0 :         fShapeMatrixFT.xx = SkScalarToFixed(fShapeMatrix.getScaleX());
     580           0 :         fShapeMatrixFT.yx = SkScalarToFixed(-fShapeMatrix.getSkewY());
     581           0 :         fShapeMatrixFT.xy = SkScalarToFixed(-fShapeMatrix.getSkewX());
     582           0 :         fShapeMatrixFT.yy = SkScalarToFixed(fShapeMatrix.getScaleY());
     583             :     }
     584           2 :     return true;
     585             : }
     586             : 
     587           0 : unsigned SkScalerContext_CairoFT::generateGlyphCount()
     588             : {
     589           0 :     CairoLockedFTFace faceLock(fScaledFont);
     590           0 :     return faceLock.getFace()->num_glyphs;
     591             : }
     592             : 
     593           0 : uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar)
     594             : {
     595           0 :     CairoLockedFTFace faceLock(fScaledFont);
     596           0 :     return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar));
     597             : }
     598             : 
     599           0 : void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph)
     600             : {
     601           0 :     generateMetrics(glyph);
     602           0 : }
     603             : 
     604         118 : void SkScalerContext_CairoFT::prepareGlyph(FT_GlyphSlot glyph)
     605             : {
     606         118 :     if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
     607           0 :         gGlyphSlotEmbolden) {
     608           0 :         gGlyphSlotEmbolden(glyph);
     609             :     }
     610         118 :     if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
     611           0 :         fixVerticalLayoutBearing(glyph);
     612             :     }
     613         118 : }
     614             : 
     615           0 : void SkScalerContext_CairoFT::fixVerticalLayoutBearing(FT_GlyphSlot glyph)
     616             : {
     617             :     FT_Vector vector;
     618           0 :     vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX;
     619           0 :     vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY;
     620           0 :     if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
     621           0 :         if (fHaveShape) {
     622           0 :             FT_Vector_Transform(&vector, &fShapeMatrixFT);
     623             :         }
     624           0 :         FT_Outline_Translate(&glyph->outline, vector.x, vector.y);
     625           0 :     } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
     626           0 :         glyph->bitmap_left += SkFDot6Floor(vector.x);
     627           0 :         glyph->bitmap_top  += SkFDot6Floor(vector.y);
     628             :     }
     629           0 : }
     630             : 
     631          60 : void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
     632             : {
     633          60 :     SkASSERT(fScaledFont != nullptr);
     634             : 
     635          60 :     glyph->zeroMetrics();
     636             : 
     637         120 :     CairoLockedFTFace faceLock(fScaledFont);
     638          60 :     FT_Face face = faceLock.getFace();
     639             : 
     640          60 :     FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
     641          60 :     if (err != 0) {
     642           0 :         return;
     643             :     }
     644             : 
     645          60 :     prepareGlyph(face->glyph);
     646             : 
     647          60 :     switch (face->glyph->format) {
     648             :     case FT_GLYPH_FORMAT_OUTLINE:
     649          60 :         if (!face->glyph->outline.n_contours) {
     650          62 :             break;
     651             :         }
     652             : 
     653             :         FT_BBox bbox;
     654          58 :         FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
     655          58 :         bbox.xMin &= ~63;
     656          58 :         bbox.yMin &= ~63;
     657          58 :         bbox.xMax = (bbox.xMax + 63) & ~63;
     658          58 :         bbox.yMax = (bbox.yMax + 63) & ~63;
     659          58 :         glyph->fWidth  = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
     660          58 :         glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
     661          58 :         glyph->fTop    = -SkToS16(SkFDot6Floor(bbox.yMax));
     662          58 :         glyph->fLeft   = SkToS16(SkFDot6Floor(bbox.xMin));
     663             : 
     664         174 :         if (isLCD(fRec) &&
     665         174 :             gSetLcdFilter &&
     666          58 :             (fLcdFilter == FT_LCD_FILTER_DEFAULT ||
     667           0 :              fLcdFilter == FT_LCD_FILTER_LIGHT)) {
     668          58 :             if (fRec.fFlags & kLCD_Vertical_Flag) {
     669           0 :                 glyph->fTop -= 1;
     670           0 :                 glyph->fHeight += 2;
     671             :             } else {
     672          58 :                 glyph->fLeft -= 1;
     673          58 :                 glyph->fWidth += 2;
     674             :             }
     675             :         }
     676          58 :         break;
     677             :     case FT_GLYPH_FORMAT_BITMAP:
     678           0 :         if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
     679           0 :             glyph->fMaskFormat = SkMask::kARGB32_Format;
     680             :         }
     681             : 
     682           0 :         if (isLCD(fRec)) {
     683           0 :             fRec.fMaskFormat = SkMask::kA8_Format;
     684             :         }
     685             : 
     686           0 :         if (fHaveShape) {
     687             :             // Ensure filtering is preserved when the bitmap is transformed.
     688             :             // Otherwise, the result will look horrifically aliased.
     689           0 :             if (fRec.fMaskFormat == SkMask::kBW_Format) {
     690           0 :                 fRec.fMaskFormat = SkMask::kA8_Format;
     691             :             }
     692             : 
     693             :             // Apply the shape matrix to the glyph's bounding box.
     694             :             SkRect srcRect = SkRect::MakeXYWH(
     695           0 :                 SkIntToScalar(face->glyph->bitmap_left),
     696           0 :                 -SkIntToScalar(face->glyph->bitmap_top),
     697           0 :                 SkIntToScalar(face->glyph->bitmap.width),
     698           0 :                 SkIntToScalar(face->glyph->bitmap.rows));
     699             :             SkRect destRect;
     700           0 :             fShapeMatrix.mapRect(&destRect, srcRect);
     701           0 :             SkIRect glyphRect = destRect.roundOut();
     702           0 :             glyph->fWidth  = SkToU16(glyphRect.width());
     703           0 :             glyph->fHeight = SkToU16(glyphRect.height());
     704           0 :             glyph->fTop    = SkToS16(SkScalarRoundToInt(destRect.fTop));
     705           0 :             glyph->fLeft   = SkToS16(SkScalarRoundToInt(destRect.fLeft));
     706             :         } else {
     707           0 :             glyph->fWidth  = SkToU16(face->glyph->bitmap.width);
     708           0 :             glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
     709           0 :             glyph->fTop    = -SkToS16(face->glyph->bitmap_top);
     710           0 :             glyph->fLeft   = SkToS16(face->glyph->bitmap_left);
     711             :         }
     712           0 :         break;
     713             :     default:
     714           0 :         SkDEBUGFAIL("unknown glyph format");
     715           0 :         return;
     716             :     }
     717             : 
     718          60 :     if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
     719           0 :         glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
     720           0 :         glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y);
     721             :     } else {
     722          60 :         glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
     723          60 :         glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
     724             :     }
     725             : }
     726             : 
     727          58 : void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
     728             : {
     729          58 :     SkASSERT(fScaledFont != nullptr);
     730         116 :     CairoLockedFTFace faceLock(fScaledFont);
     731          58 :     FT_Face face = faceLock.getFace();
     732             : 
     733          58 :     FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags);
     734             : 
     735          58 :     if (err != 0) {
     736           0 :         memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
     737           0 :         return;
     738             :     }
     739             : 
     740          58 :     prepareGlyph(face->glyph);
     741             : 
     742             :     bool useLcdFilter =
     743         116 :         face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
     744         116 :         isLCD(glyph) &&
     745         116 :         gSetLcdFilter;
     746          58 :     if (useLcdFilter) {
     747          58 :         gSetLcdFilter(face->glyph->library, fLcdFilter);
     748             :     }
     749             : 
     750             :     SkMatrix matrix;
     751          58 :     if (face->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
     752           0 :         fHaveShape) {
     753           0 :         matrix = fShapeMatrix;
     754             :     } else {
     755          58 :         matrix.setIdentity();
     756             :     }
     757          58 :     generateGlyphImage(face, glyph, matrix);
     758             : 
     759          58 :     if (useLcdFilter) {
     760          58 :         gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE);
     761             :     }
     762             : }
     763             : 
     764           0 : void SkScalerContext_CairoFT::generatePath(const SkGlyphID glyphID, SkPath* path)
     765             : {
     766           0 :     SkASSERT(fScaledFont != nullptr);
     767           0 :     CairoLockedFTFace faceLock(fScaledFont);
     768           0 :     FT_Face face = faceLock.getFace();
     769             : 
     770           0 :     SkASSERT(path);
     771             : 
     772           0 :     uint32_t flags = fLoadGlyphFlags;
     773           0 :     flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
     774           0 :     flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)
     775             : 
     776           0 :     FT_Error err = FT_Load_Glyph(face, glyphID, flags);
     777             : 
     778           0 :     if (err != 0) {
     779           0 :         path->reset();
     780           0 :         return;
     781             :     }
     782             : 
     783           0 :     prepareGlyph(face->glyph);
     784             : 
     785           0 :     generateGlyphPath(face, path);
     786             : }
     787             : 
     788           2 : void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* metrics)
     789             : {
     790           2 :     if (metrics) {
     791           2 :         memset(metrics, 0, sizeof(SkPaint::FontMetrics));
     792             :     }
     793           2 : }
     794             : 
     795           0 : SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
     796             : {
     797           0 :     SkASSERT(fScaledFont != nullptr);
     798           0 :     CairoLockedFTFace faceLock(fScaledFont);
     799           0 :     FT_Face face = faceLock.getFace();
     800             : 
     801             :     FT_UInt glyphIndex;
     802           0 :     SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex);
     803           0 :     while (glyphIndex != 0) {
     804           0 :         if (glyphIndex == glyph) {
     805           0 :             return charCode;
     806             :         }
     807           0 :         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
     808             :     }
     809             : 
     810           0 :     return 0;
     811             : }
     812             : 
     813             : ///////////////////////////////////////////////////////////////////////////////
     814             : 
     815             : #include "SkFontMgr.h"
     816             : 
     817           0 : sk_sp<SkFontMgr> SkFontMgr::Factory() {
     818             :     // todo
     819           0 :     return nullptr;
     820             : }
     821             : 

Generated by: LCOV version 1.13