Home | History | Annotate | Download | only in gtk
      1 /*
      2  * Copyright (C) 2006 Apple Computer, Inc.
      3  * Copyright (C) 2006 Michael Emmel mike.emmel (at) gmail.com
      4  * Copyright (C) 2007, 2008 Alp Toker <alp (at) atoker.com>
      5  * Copyright (C) 2007 Holger Hans Peter Freyther
      6  * Copyright (C) 2009 Igalia S.L.
      7  * All rights reserved.
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 #include "FontPlatformData.h"
     27 
     28 #include "CString.h"
     29 #include "PlatformString.h"
     30 #include "FontDescription.h"
     31 
     32 #include <cairo-ft.h>
     33 #include <cairo.h>
     34 #include <fontconfig/fcfreetype.h>
     35 #include <gtk/gtk.h>
     36 
     37 namespace WebCore {
     38 
     39 FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
     40     : m_pattern(0)
     41     , m_fallbacks(0)
     42     , m_size(fontDescription.computedPixelSize())
     43     , m_syntheticBold(false)
     44     , m_syntheticOblique(false)
     45     , m_scaledFont(0)
     46 {
     47     FontPlatformData::init();
     48 
     49     CString familyNameString = familyName.string().utf8();
     50     const char* fcfamily = familyNameString.data();
     51     int fcslant = FC_SLANT_ROMAN;
     52     // FIXME: Map all FontWeight values to fontconfig weights.
     53     int fcweight = FC_WEIGHT_NORMAL;
     54     double fcsize = fontDescription.computedPixelSize();
     55     if (fontDescription.italic())
     56         fcslant = FC_SLANT_ITALIC;
     57     if (fontDescription.weight() >= FontWeight600)
     58         fcweight = FC_WEIGHT_BOLD;
     59 
     60     int type = fontDescription.genericFamily();
     61 
     62     FcPattern* pattern = FcPatternCreate();
     63     cairo_font_face_t* fontFace;
     64     static const cairo_font_options_t* defaultOptions = cairo_font_options_create();
     65     const cairo_font_options_t* options = NULL;
     66     cairo_matrix_t fontMatrix;
     67 
     68     if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily)))
     69         goto freePattern;
     70 
     71     switch (type) {
     72     case FontDescription::SerifFamily:
     73         fcfamily = "serif";
     74         break;
     75     case FontDescription::SansSerifFamily:
     76         fcfamily = "sans-serif";
     77         break;
     78     case FontDescription::MonospaceFamily:
     79         fcfamily = "monospace";
     80         break;
     81     case FontDescription::StandardFamily:
     82         fcfamily = "sans-serif";
     83         break;
     84     case FontDescription::NoFamily:
     85     default:
     86         fcfamily = NULL;
     87         break;
     88     }
     89 
     90     if (fcfamily && !FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily)))
     91         goto freePattern;
     92     if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight))
     93         goto freePattern;
     94     if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant))
     95         goto freePattern;
     96     if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fcsize))
     97         goto freePattern;
     98 
     99     FcConfigSubstitute(NULL, pattern, FcMatchPattern);
    100     FcDefaultSubstitute(pattern);
    101 
    102     FcResult fcresult;
    103     m_pattern = FcFontMatch(NULL, pattern, &fcresult);
    104     // FIXME: should we set some default font?
    105     if (!m_pattern)
    106         goto freePattern;
    107     fontFace = cairo_ft_font_face_create_for_pattern(m_pattern);
    108     cairo_matrix_t ctm;
    109     cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize());
    110     cairo_matrix_init_identity(&ctm);
    111 
    112     if (GdkScreen* screen = gdk_screen_get_default())
    113         options = gdk_screen_get_font_options(screen);
    114 
    115     // gdk_screen_get_font_options() returns NULL if no default options are
    116     // set, so we always have to check.
    117     if (!options)
    118         options = defaultOptions;
    119 
    120     m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
    121     cairo_font_face_destroy(fontFace);
    122 
    123 freePattern:
    124     FcPatternDestroy(pattern);
    125 }
    126 
    127 FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
    128     : m_pattern(0)
    129     , m_fallbacks(0)
    130     , m_size(size)
    131     , m_syntheticBold(bold)
    132     , m_syntheticOblique(italic)
    133     , m_scaledFont(0)
    134 {
    135 }
    136 
    137 FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic)
    138     : m_pattern(0)
    139     , m_fallbacks(0)
    140     , m_size(size)
    141     , m_syntheticBold(bold)
    142     , m_syntheticOblique(italic)
    143     , m_scaledFont(0)
    144 {
    145     cairo_matrix_t fontMatrix;
    146     cairo_matrix_init_scale(&fontMatrix, size, size);
    147     cairo_matrix_t ctm;
    148     cairo_matrix_init_identity(&ctm);
    149     static const cairo_font_options_t* defaultOptions = cairo_font_options_create();
    150     const cairo_font_options_t* options = NULL;
    151 
    152     if (GdkScreen* screen = gdk_screen_get_default())
    153         options = gdk_screen_get_font_options(screen);
    154 
    155     // gdk_screen_get_font_options() returns NULL if no default options are
    156     // set, so we always have to check.
    157     if (!options)
    158         options = defaultOptions;
    159 
    160     m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
    161 }
    162 
    163 FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
    164 {
    165     // Check for self-assignment.
    166     if (this == &other)
    167         return *this;
    168 
    169     m_size = other.m_size;
    170     m_syntheticBold = other.m_syntheticBold;
    171     m_syntheticOblique = other.m_syntheticOblique;
    172 
    173     if (other.m_scaledFont)
    174         cairo_scaled_font_reference(other.m_scaledFont);
    175     if (m_scaledFont)
    176         cairo_scaled_font_destroy(m_scaledFont);
    177     m_scaledFont = other.m_scaledFont;
    178 
    179     if (other.m_pattern)
    180         FcPatternReference(other.m_pattern);
    181     if (m_pattern)
    182         FcPatternDestroy(m_pattern);
    183     m_pattern = other.m_pattern;
    184 
    185     if (m_fallbacks) {
    186         FcFontSetDestroy(m_fallbacks);
    187         // This will be re-created on demand.
    188         m_fallbacks = 0;
    189     }
    190 
    191     return *this;
    192 }
    193 
    194 FontPlatformData::FontPlatformData(const FontPlatformData& other)
    195     : m_pattern(0)
    196     , m_fallbacks(0)
    197     , m_scaledFont(0)
    198 {
    199     *this = other;
    200 }
    201 
    202 bool FontPlatformData::init()
    203 {
    204     static bool initialized = false;
    205     if (initialized)
    206         return true;
    207     if (!FcInit()) {
    208         fprintf(stderr, "Can't init font config library\n");
    209         return false;
    210     }
    211     initialized = true;
    212     return true;
    213 }
    214 
    215 FontPlatformData::~FontPlatformData()
    216 {
    217     if (m_pattern && ((FcPattern*)-1 != m_pattern)) {
    218         FcPatternDestroy(m_pattern);
    219         m_pattern = 0;
    220     }
    221 
    222     if (m_fallbacks) {
    223         FcFontSetDestroy(m_fallbacks);
    224         m_fallbacks = 0;
    225     }
    226 
    227     if (m_scaledFont)
    228         cairo_scaled_font_destroy(m_scaledFont);
    229 }
    230 
    231 bool FontPlatformData::isFixedPitch()
    232 {
    233     // TODO: Support isFixedPitch() for custom fonts.
    234     if (!m_pattern)
    235         return false;
    236 
    237     int spacing;
    238     if (FcPatternGetInteger(m_pattern, FC_SPACING, 0, &spacing) == FcResultMatch)
    239         return spacing == FC_MONO;
    240     return false;
    241 }
    242 
    243 bool FontPlatformData::operator==(const FontPlatformData& other) const
    244 {
    245     if (m_pattern == other.m_pattern)
    246         return true;
    247     if (m_pattern == 0 || m_pattern == reinterpret_cast<FcPattern*>(-1)
    248             || other.m_pattern == 0 || other.m_pattern == reinterpret_cast<FcPattern*>(-1))
    249         return false;
    250     return FcPatternEqual(m_pattern, other.m_pattern);
    251 }
    252 
    253 #ifndef NDEBUG
    254 String FontPlatformData::description() const
    255 {
    256     return String();
    257 }
    258 #endif
    259 
    260 }
    261