LCOV - code coverage report
Current view: top level - gfx/2d - ScaledFontFontconfig.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 13 167 7.8 %
Date: 2017-07-14 16:53:18 Functions: 4 13 30.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "ScaledFontFontconfig.h"
       7             : #include "UnscaledFontFreeType.h"
       8             : #include "Logging.h"
       9             : 
      10             : #ifdef USE_SKIA
      11             : #include "skia/include/ports/SkTypeface_cairo.h"
      12             : #endif
      13             : 
      14             : #include <fontconfig/fcfreetype.h>
      15             : 
      16             : namespace mozilla {
      17             : namespace gfx {
      18             : 
      19             : // On Linux and Android our "platform" font is a cairo_scaled_font_t and we use
      20             : // an SkFontHost implementation that allows Skia to render using this.
      21             : // This is mainly because FT_Face is not good for sharing between libraries, which
      22             : // is a requirement when we consider runtime switchable backends and so on
      23          21 : ScaledFontFontconfig::ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont,
      24             :                                            FcPattern* aPattern,
      25             :                                            const RefPtr<UnscaledFont>& aUnscaledFont,
      26          21 :                                            Float aSize)
      27             :   : ScaledFontBase(aUnscaledFont, aSize),
      28          21 :     mPattern(aPattern)
      29             : {
      30          21 :   SetCairoScaledFont(aScaledFont);
      31          21 :   FcPatternReference(aPattern);
      32          21 : }
      33             : 
      34          63 : ScaledFontFontconfig::~ScaledFontFontconfig()
      35             : {
      36          21 :   FcPatternDestroy(mPattern);
      37          63 : }
      38             : 
      39             : #ifdef USE_SKIA
      40          21 : SkTypeface* ScaledFontFontconfig::GetSkTypeface()
      41             : {
      42          21 :   if (!mTypeface) {
      43          21 :     mTypeface = SkCreateTypefaceFromCairoFTFontWithFontconfig(mScaledFont, mPattern);
      44             :   }
      45             : 
      46          21 :   return mTypeface;
      47             : }
      48             : #endif
      49             : 
      50           0 : ScaledFontFontconfig::InstanceData::InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern)
      51             :   : mFlags(0)
      52             :   , mHintStyle(FC_HINT_NONE)
      53             :   , mSubpixelOrder(FC_RGBA_UNKNOWN)
      54           0 :   , mLcdFilter(FC_LCD_LEGACY)
      55             : {
      56             :   // Record relevant Fontconfig properties into instance data.
      57             :   FcBool autohint;
      58           0 :   if (FcPatternGetBool(aPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
      59           0 :     mFlags |= AUTOHINT;
      60             :   }
      61             :   FcBool bitmap;
      62           0 :   if (FcPatternGetBool(aPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
      63           0 :     mFlags |= EMBEDDED_BITMAP;
      64             :   }
      65             :   FcBool embolden;
      66           0 :   if (FcPatternGetBool(aPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
      67           0 :     mFlags |= EMBOLDEN;
      68             :   }
      69             :   FcBool vertical;
      70           0 :   if (FcPatternGetBool(aPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
      71           0 :     mFlags |= VERTICAL_LAYOUT;
      72             :   }
      73             : 
      74             :   FcBool antialias;
      75           0 :   if (FcPatternGetBool(aPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) {
      76           0 :     mFlags |= ANTIALIAS;
      77             : 
      78             :     // Only record subpixel order and lcd filtering if antialiasing is enabled.
      79             :     int rgba;
      80           0 :     if (FcPatternGetInteger(aPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
      81           0 :       mSubpixelOrder = rgba;
      82             :     }
      83             :     int filter;
      84           0 :     if (FcPatternGetInteger(aPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
      85           0 :       mLcdFilter = filter;
      86             :     }
      87             :   }
      88             : 
      89           0 :   cairo_font_options_t* fontOptions = cairo_font_options_create();
      90           0 :   cairo_scaled_font_get_font_options(aScaledFont, fontOptions);
      91             :   // For printer fonts, Cairo hint metrics and hinting will be disabled.
      92             :   // For other fonts, allow hint metrics and hinting.
      93           0 :   if (cairo_font_options_get_hint_metrics(fontOptions) != CAIRO_HINT_METRICS_OFF) {
      94           0 :     mFlags |= HINT_METRICS;
      95             : 
      96             :     FcBool hinting;
      97           0 :     if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
      98             :       int hintstyle;
      99           0 :       if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
     100           0 :         hintstyle = FC_HINT_FULL;
     101             :       }
     102           0 :       mHintStyle = hintstyle;
     103             :     }
     104             :   }
     105           0 :   cairo_font_options_destroy(fontOptions);
     106             : 
     107             :   // Some fonts supply an adjusted size or otherwise use the font matrix for italicization.
     108             :   // Record the scale and the skew to accomodate both of these cases.
     109             :   cairo_matrix_t fontMatrix;
     110           0 :   cairo_scaled_font_get_font_matrix(aScaledFont, &fontMatrix);
     111           0 :   mScale = Float(fontMatrix.xx);
     112           0 :   mSkew = Float(fontMatrix.xy);
     113           0 : }
     114             : 
     115             : void
     116           0 : ScaledFontFontconfig::InstanceData::SetupPattern(FcPattern* aPattern) const
     117             : {
     118           0 :   if (mFlags & AUTOHINT) {
     119           0 :     FcPatternAddBool(aPattern, FC_AUTOHINT, FcTrue);
     120             :   }
     121           0 :   if (mFlags & EMBEDDED_BITMAP) {
     122           0 :     FcPatternAddBool(aPattern, FC_EMBEDDED_BITMAP, FcTrue);
     123             :   }
     124           0 :   if (mFlags & EMBOLDEN) {
     125           0 :     FcPatternAddBool(aPattern, FC_EMBOLDEN, FcTrue);
     126             :   }
     127           0 :   if (mFlags & VERTICAL_LAYOUT) {
     128           0 :     FcPatternAddBool(aPattern, FC_VERTICAL_LAYOUT, FcTrue);
     129             :   }
     130             : 
     131           0 :   if (mFlags & ANTIALIAS) {
     132           0 :     FcPatternAddBool(aPattern, FC_ANTIALIAS, FcTrue);
     133           0 :     if (mSubpixelOrder != FC_RGBA_UNKNOWN) {
     134           0 :       FcPatternAddInteger(aPattern, FC_RGBA, mSubpixelOrder);
     135             :     }
     136           0 :     if (mLcdFilter != FC_LCD_LEGACY) {
     137           0 :       FcPatternAddInteger(aPattern, FC_LCD_FILTER, mLcdFilter);
     138             :     }
     139             :   } else {
     140           0 :     FcPatternAddBool(aPattern, FC_ANTIALIAS, FcFalse);
     141             :   }
     142             : 
     143           0 :   if (mHintStyle) {
     144           0 :     FcPatternAddBool(aPattern, FC_HINTING, FcTrue);
     145           0 :     FcPatternAddInteger(aPattern, FC_HINT_STYLE, mHintStyle);
     146             :   } else {
     147           0 :     FcPatternAddBool(aPattern, FC_HINTING, FcFalse);
     148             :   }
     149           0 : }
     150             : 
     151             : void
     152           0 : ScaledFontFontconfig::InstanceData::SetupFontOptions(cairo_font_options_t* aFontOptions) const
     153             : {
     154             :   // Try to build a sane initial set of Cairo font options based on the Fontconfig
     155             :   // pattern.
     156           0 :   if (mFlags & HINT_METRICS) {
     157             :     // For regular (non-printer) fonts, enable hint metrics as well as hinting
     158             :     // and (possibly subpixel) antialiasing.
     159           0 :     cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON);
     160             : 
     161             :     cairo_hint_style_t hinting;
     162           0 :     switch (mHintStyle) {
     163             :     case FC_HINT_NONE:
     164           0 :       hinting = CAIRO_HINT_STYLE_NONE;
     165           0 :       break;
     166             :     case FC_HINT_SLIGHT:
     167           0 :       hinting = CAIRO_HINT_STYLE_SLIGHT;
     168           0 :       break;
     169             :     case FC_HINT_MEDIUM:
     170             :     default:
     171           0 :       hinting = CAIRO_HINT_STYLE_MEDIUM;
     172           0 :       break;
     173             :     case FC_HINT_FULL:
     174           0 :       hinting = CAIRO_HINT_STYLE_FULL;
     175           0 :       break;
     176             :     }
     177           0 :     cairo_font_options_set_hint_style(aFontOptions, hinting);
     178             : 
     179           0 :     if (mFlags & ANTIALIAS) {
     180           0 :       cairo_subpixel_order_t subpixel = CAIRO_SUBPIXEL_ORDER_DEFAULT;
     181           0 :       switch (mSubpixelOrder) {
     182             :       case FC_RGBA_RGB:
     183           0 :         subpixel = CAIRO_SUBPIXEL_ORDER_RGB;
     184           0 :         break;
     185             :       case FC_RGBA_BGR:
     186           0 :         subpixel = CAIRO_SUBPIXEL_ORDER_BGR;
     187           0 :         break;
     188             :       case FC_RGBA_VRGB:
     189           0 :         subpixel = CAIRO_SUBPIXEL_ORDER_VRGB;
     190           0 :         break;
     191             :       case FC_RGBA_VBGR:
     192           0 :         subpixel = CAIRO_SUBPIXEL_ORDER_VBGR;
     193           0 :         break;
     194             :       default:
     195           0 :         break;
     196             :       }
     197           0 :       if (subpixel != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
     198           0 :         cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
     199           0 :         cairo_font_options_set_subpixel_order(aFontOptions, subpixel);
     200             :       } else {
     201           0 :         cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_GRAY);
     202             :       }
     203             :     } else {
     204           0 :       cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_NONE);
     205             :     }
     206             :   } else {
     207             :     // For printer fonts, disable hint metrics and hinting. Don't allow subpixel
     208             :     // antialiasing.
     209           0 :     cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF);
     210           0 :     cairo_font_options_set_hint_style(aFontOptions, CAIRO_HINT_STYLE_NONE);
     211           0 :     cairo_font_options_set_antialias(aFontOptions,
     212           0 :       mFlags & ANTIALIAS ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
     213             :   }
     214           0 : }
     215             : 
     216             : void
     217           0 : ScaledFontFontconfig::InstanceData::SetupFontMatrix(cairo_matrix_t* aFontMatrix) const
     218             : {
     219             :   // Build a font matrix that will reproduce a possibly adjusted size
     220             :   // and any italics/skew. This is just the concatenation of a simple
     221             :   // scale matrix with a matrix that skews on the X axis.
     222           0 :   cairo_matrix_init(aFontMatrix, mScale, 0, mSkew, mScale, 0, 0);
     223           0 : }
     224             : 
     225             : bool
     226           0 : ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
     227             : {
     228           0 :   InstanceData instance(GetCairoScaledFont(), mPattern);
     229             : 
     230           0 :   aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance), aBaton);
     231           0 :   return true;
     232             : }
     233             : 
     234             : already_AddRefed<ScaledFont>
     235           0 : UnscaledFontFontconfig::CreateScaledFont(Float aGlyphSize,
     236             :                                          const uint8_t* aInstanceData,
     237             :                                          uint32_t aInstanceDataLength)
     238             : {
     239           0 :   if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) {
     240           0 :     gfxWarning() << "Fontconfig scaled font instance data is truncated.";
     241           0 :     return nullptr;
     242             :   }
     243             :   const ScaledFontFontconfig::InstanceData *instanceData =
     244           0 :     reinterpret_cast<const ScaledFontFontconfig::InstanceData*>(aInstanceData);
     245             :   return ScaledFontFontconfig::CreateFromInstanceData(*instanceData, this, aGlyphSize,
     246           0 :                                                       mNativeFontResource.get());
     247             : }
     248             : 
     249             : static cairo_user_data_key_t sNativeFontResourceKey;
     250             : 
     251             : static void
     252           0 : ReleaseNativeFontResource(void* aData)
     253             : {
     254           0 :   static_cast<NativeFontResource*>(aData)->Release();
     255           0 : }
     256             : 
     257             : already_AddRefed<ScaledFont>
     258           0 : ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData,
     259             :                                              UnscaledFontFontconfig* aUnscaledFont,
     260             :                                              Float aSize,
     261             :                                              NativeFontResource* aNativeFontResource)
     262             : {
     263           0 :   FcPattern* pattern = FcPatternCreate();
     264           0 :   if (!pattern) {
     265           0 :     gfxWarning() << "Failing initializing Fontconfig pattern for scaled font";
     266           0 :     return nullptr;
     267             :   }
     268           0 :   if (aUnscaledFont->GetFace()) {
     269           0 :     FcPatternAddFTFace(pattern, FC_FT_FACE, aUnscaledFont->GetFace());
     270             :   } else {
     271           0 :     FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(aUnscaledFont->GetFile()));
     272           0 :     FcPatternAddInteger(pattern, FC_INDEX, aUnscaledFont->GetIndex());
     273             :   }
     274           0 :   FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize);
     275           0 :   aInstanceData.SetupPattern(pattern);
     276             : 
     277           0 :   cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern);
     278           0 :   if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) {
     279           0 :     gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern";
     280           0 :     FcPatternDestroy(pattern);
     281           0 :     return nullptr;
     282             :   }
     283             : 
     284           0 :   if (aNativeFontResource) {
     285             :     // Bug 1362117 - Cairo may keep the font face alive after the owning NativeFontResource
     286             :     // was freed. To prevent this, we must bind the NativeFontResource to the font face so that
     287             :     // it stays alive at least as long as the font face.
     288           0 :     if (cairo_font_face_set_user_data(font,
     289             :                                       &sNativeFontResourceKey,
     290             :                                       aNativeFontResource,
     291             :                                       ReleaseNativeFontResource) != CAIRO_STATUS_SUCCESS) {
     292           0 :       gfxWarning() << "Failed binding NativeFontResource to Cairo font face";
     293           0 :       cairo_font_face_destroy(font);
     294           0 :       FcPatternDestroy(pattern);
     295           0 :       return nullptr;
     296             :     }
     297           0 :     aNativeFontResource->AddRef();
     298             :   }
     299             : 
     300             :   cairo_matrix_t sizeMatrix;
     301           0 :   aInstanceData.SetupFontMatrix(&sizeMatrix);
     302             : 
     303             :   cairo_matrix_t identityMatrix;
     304           0 :   cairo_matrix_init_identity(&identityMatrix);
     305             : 
     306           0 :   cairo_font_options_t *fontOptions = cairo_font_options_create();
     307           0 :   aInstanceData.SetupFontOptions(fontOptions);
     308             : 
     309             :   cairo_scaled_font_t* cairoScaledFont =
     310           0 :     cairo_scaled_font_create(font, &sizeMatrix, &identityMatrix, fontOptions);
     311             : 
     312           0 :   cairo_font_options_destroy(fontOptions);
     313           0 :   cairo_font_face_destroy(font);
     314             : 
     315           0 :   if (cairo_scaled_font_status(cairoScaledFont) != CAIRO_STATUS_SUCCESS) {
     316           0 :     gfxWarning() << "Failed creating Cairo scaled font for font face";
     317           0 :     FcPatternDestroy(pattern);
     318           0 :     return nullptr;
     319             :   }
     320             : 
     321             :   RefPtr<ScaledFontFontconfig> scaledFont =
     322           0 :     new ScaledFontFontconfig(cairoScaledFont, pattern, aUnscaledFont, aSize);
     323             : 
     324           0 :   cairo_scaled_font_destroy(cairoScaledFont);
     325           0 :   FcPatternDestroy(pattern);
     326             : 
     327           0 :   return scaledFont.forget();
     328             : }
     329             : 
     330             : already_AddRefed<UnscaledFont>
     331           0 : UnscaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength)
     332             : {
     333           0 :   if (aDataLength < sizeof(FontDescriptor)) {
     334           0 :     gfxWarning() << "Fontconfig font descriptor is truncated.";
     335           0 :     return nullptr;
     336             :   }
     337           0 :   const FontDescriptor* desc = reinterpret_cast<const FontDescriptor*>(aData);
     338           0 :   if (desc->mPathLength < 1 ||
     339           0 :       desc->mPathLength > aDataLength - sizeof(FontDescriptor)) {
     340           0 :     gfxWarning() << "Pathname in Fontconfig font descriptor has invalid size.";
     341           0 :     return nullptr;
     342             :   }
     343           0 :   const char* path = reinterpret_cast<const char*>(aData + sizeof(FontDescriptor));
     344           0 :   if (path[desc->mPathLength - 1] != '\0') {
     345           0 :     gfxWarning() << "Pathname in Fontconfig font descriptor is not terminated.";
     346           0 :     return nullptr;
     347             :   }
     348             : 
     349           0 :   RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(path, desc->mIndex);
     350           0 :   return unscaledFont.forget();
     351             : }
     352             : 
     353             : } // namespace gfx
     354             : } // namespace mozilla

Generated by: LCOV version 1.13