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) 2007 Pioneer Research Center USA, Inc.
      7  * Copyright (C) 2009 Igalia S.L.
      8  * All rights reserved.
      9  *
     10  * This library is free software; you can redistribute it and/or
     11  * modify it under the terms of the GNU Library General Public
     12  * License as published by the Free Software Foundation; either
     13  * version 2 of the License, or (at your option) any later version.
     14  *
     15  * This library is distributed in the hope that it will be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18  * Library General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU Library General Public License
     21  * along with this library; see the file COPYING.LIB.  If not, write to
     22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     23  * Boston, MA 02110-1301, USA.
     24  */
     25 #include "config.h"
     26 #include "FontPlatformData.h"
     27 
     28 #include "CString.h"
     29 #include "PlatformString.h"
     30 #include "FontDescription.h"
     31 #include <cairo.h>
     32 #include <assert.h>
     33 
     34 #include <pango/pango.h>
     35 #include <pango/pangocairo.h>
     36 
     37 // Use cairo-ft i a recent enough Pango version isn't available
     38 #if !PANGO_VERSION_CHECK(1,18,0)
     39 #include <cairo-ft.h>
     40 #include <pango/pangofc-fontmap.h>
     41 #endif
     42 #include <gtk/gtk.h>
     43 
     44 namespace WebCore {
     45 
     46 PangoFontMap* FontPlatformData::m_fontMap = 0;
     47 GHashTable* FontPlatformData::m_hashTable = 0;
     48 
     49 FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
     50     : m_context(0)
     51     , m_font(0)
     52     , m_size(fontDescription.computedSize())
     53     , m_syntheticBold(false)
     54     , m_syntheticOblique(false)
     55     , m_scaledFont(0)
     56 {
     57     FontPlatformData::init();
     58 
     59     CString stored_family = familyName.string().utf8();
     60     char const* families[] = {
     61       stored_family.data(),
     62       NULL
     63     };
     64 
     65     switch (fontDescription.genericFamily()) {
     66     case FontDescription::SerifFamily:
     67         families[1] = "serif";
     68         break;
     69     case FontDescription::SansSerifFamily:
     70         families[1] = "sans";
     71         break;
     72     case FontDescription::MonospaceFamily:
     73         families[1] = "monospace";
     74         break;
     75     case FontDescription::NoFamily:
     76     case FontDescription::StandardFamily:
     77     default:
     78         families[1] = "sans";
     79         break;
     80     }
     81 
     82     PangoFontDescription* description = pango_font_description_new();
     83     pango_font_description_set_absolute_size(description, fontDescription.computedSize() * PANGO_SCALE);
     84 
     85     // FIXME: Map all FontWeight values to Pango font weights.
     86     if (fontDescription.weight() >= FontWeight600)
     87         pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
     88     if (fontDescription.italic())
     89         pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
     90 
     91 #if PANGO_VERSION_CHECK(1,21,5)   // deprecated in 1.21
     92     m_context = pango_font_map_create_context(m_fontMap);
     93 #else
     94     m_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(m_fontMap));
     95 #endif
     96     for (unsigned int i = 0; !m_font && i < G_N_ELEMENTS(families); i++) {
     97         pango_font_description_set_family(description, families[i]);
     98         pango_context_set_font_description(m_context, description);
     99         m_font = pango_font_map_load_font(m_fontMap, m_context, description);
    100     }
    101 
    102 #if PANGO_VERSION_CHECK(1,18,0)
    103     if (m_font)
    104         m_scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(m_font)));
    105 #else
    106     // This compatibility code for older versions of Pango is not well-tested.
    107     if (m_font) {
    108         PangoFcFont* fcfont = PANGO_FC_FONT(m_font);
    109         cairo_font_face_t* face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern);
    110         double size;
    111         if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
    112             size = 12.0;
    113         cairo_matrix_t fontMatrix;
    114         cairo_matrix_init_scale(&fontMatrix, size, size);
    115         cairo_font_options_t* fontOptions;
    116         if (pango_cairo_context_get_font_options(m_context))
    117             fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context));
    118         else
    119             fontOptions = cairo_font_options_create();
    120         cairo_matrix_t ctm;
    121         cairo_matrix_init_identity(&ctm);
    122         m_scaledFont = cairo_scaled_font_create(face, &fontMatrix, &ctm, fontOptions);
    123         cairo_font_options_destroy(fontOptions);
    124         cairo_font_face_destroy(face);
    125     }
    126 #endif
    127     pango_font_description_free(description);
    128 }
    129 
    130 FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
    131     : m_context(0)
    132     , m_font(0)
    133     , m_size(size)
    134     , m_syntheticBold(bold)
    135     , m_syntheticOblique(italic)
    136     , m_scaledFont(0)
    137 {
    138 }
    139 
    140 FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic)
    141     : m_context(0)
    142     , m_font(0)
    143     , m_size(size)
    144     , m_syntheticBold(bold)
    145     , m_syntheticOblique(italic)
    146     , m_scaledFont(0)
    147 {
    148     cairo_matrix_t fontMatrix;
    149     cairo_matrix_init_scale(&fontMatrix, size, size);
    150     cairo_matrix_t ctm;
    151     cairo_matrix_init_identity(&ctm);
    152     cairo_font_options_t* options = cairo_font_options_create();
    153 
    154     // We force antialiasing and disable hinting to provide consistent
    155     // typographic qualities for custom fonts on all platforms.
    156     cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
    157     cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
    158 
    159     m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
    160     cairo_font_options_destroy(options);
    161 }
    162 
    163 bool FontPlatformData::init()
    164 {
    165     static bool initialized = false;
    166     if (initialized)
    167         return true;
    168     initialized = true;
    169 
    170     if (!m_fontMap)
    171         m_fontMap = pango_cairo_font_map_get_default();
    172     if (!m_hashTable) {
    173         PangoFontFamily** families = 0;
    174         int n_families = 0;
    175 
    176         m_hashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
    177 
    178         pango_font_map_list_families(m_fontMap, &families, &n_families);
    179 
    180         for (int family = 0; family < n_families; family++)
    181                 g_hash_table_insert(m_hashTable,
    182                                     g_strdup(pango_font_family_get_name(families[family])),
    183                                     g_object_ref(families[family]));
    184 
    185         g_free(families);
    186     }
    187 
    188     return true;
    189 }
    190 
    191 FontPlatformData::~FontPlatformData()
    192 {
    193     if (m_font && m_font != reinterpret_cast<PangoFont*>(-1)) {
    194         g_object_unref(m_font);
    195         m_font = 0;
    196     }
    197 
    198     if (m_context) {
    199         g_object_unref(m_context);
    200         m_context = 0;
    201     }
    202 
    203     if (m_scaledFont) {
    204         cairo_scaled_font_destroy(m_scaledFont);
    205         m_scaledFont = 0;
    206     }
    207 }
    208 
    209 bool FontPlatformData::isFixedPitch()
    210 {
    211     PangoFontDescription* description = pango_font_describe_with_absolute_size(m_font);
    212     PangoFontFamily* family = reinterpret_cast<PangoFontFamily*>(g_hash_table_lookup(m_hashTable, pango_font_description_get_family(description)));
    213     pango_font_description_free(description);
    214     return pango_font_family_is_monospace(family);
    215 }
    216 
    217 FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
    218 {
    219     // Check for self-assignment.
    220     if (this == &other)
    221         return *this;
    222 
    223     m_size = other.m_size;
    224     m_syntheticBold = other.m_syntheticBold;
    225     m_syntheticOblique = other.m_syntheticOblique;
    226 
    227     if (other.m_scaledFont)
    228         cairo_scaled_font_reference(other.m_scaledFont);
    229     if (m_scaledFont)
    230         cairo_scaled_font_destroy(m_scaledFont);
    231     m_scaledFont = other.m_scaledFont;
    232 
    233     if (other.m_font)
    234         g_object_ref(other.m_font);
    235     if (m_font)
    236         g_object_unref(m_font);
    237     m_font = other.m_font;
    238 
    239     if (other.m_context)
    240         g_object_ref(other.m_context);
    241     if (m_context)
    242         g_object_unref(m_context);
    243     m_context = other.m_context;
    244 
    245     return *this;
    246 }
    247 
    248 FontPlatformData::FontPlatformData(const FontPlatformData& other)
    249     : m_context(0)
    250     , m_font(0)
    251     , m_scaledFont(0)
    252 {
    253     *this = other;
    254 }
    255 
    256 bool FontPlatformData::operator==(const FontPlatformData& other) const
    257 {
    258     if (m_font == other.m_font)
    259         return true;
    260     if (m_font == 0 || m_font == reinterpret_cast<PangoFont*>(-1)
    261         || other.m_font == 0 || other.m_font == reinterpret_cast<PangoFont*>(-1))
    262         return false;
    263     PangoFontDescription* thisDesc = pango_font_describe(m_font);
    264     PangoFontDescription* otherDesc = pango_font_describe(other.m_font);
    265     bool result = pango_font_description_equal(thisDesc, otherDesc);
    266     pango_font_description_free(otherDesc);
    267     pango_font_description_free(thisDesc);
    268     return result;
    269 }
    270 
    271 #ifndef NDEBUG
    272 String FontPlatformData::description() const
    273 {
    274     return String();
    275 }
    276 #endif
    277 
    278 }
    279