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