1/* 2 * Copyright (C) 2006 Apple Computer, Inc. 3 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 4 * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> 5 * Copyright (C) 2007 Holger Hans Peter Freyther 6 * Copyright (C) 2009, 2010 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 "PlatformString.h" 29#include "FontDescription.h" 30#include <cairo-ft.h> 31#include <cairo.h> 32#include <fontconfig/fcfreetype.h> 33 34#if !PLATFORM(EFL) 35#include <gdk/gdk.h> 36#endif 37 38namespace WebCore { 39 40cairo_subpixel_order_t convertFontConfigSubpixelOrder(int fontConfigOrder) 41{ 42 switch (fontConfigOrder) { 43 case FC_RGBA_RGB: 44 return CAIRO_SUBPIXEL_ORDER_RGB; 45 case FC_RGBA_BGR: 46 return CAIRO_SUBPIXEL_ORDER_BGR; 47 case FC_RGBA_VRGB: 48 return CAIRO_SUBPIXEL_ORDER_VRGB; 49 case FC_RGBA_VBGR: 50 return CAIRO_SUBPIXEL_ORDER_VBGR; 51 case FC_RGBA_NONE: 52 case FC_RGBA_UNKNOWN: 53 return CAIRO_SUBPIXEL_ORDER_DEFAULT; 54 } 55 return CAIRO_SUBPIXEL_ORDER_DEFAULT; 56} 57 58cairo_hint_style_t convertFontConfigHintStyle(int fontConfigStyle) 59{ 60 switch (fontConfigStyle) { 61 case FC_HINT_NONE: 62 return CAIRO_HINT_STYLE_NONE; 63 case FC_HINT_SLIGHT: 64 return CAIRO_HINT_STYLE_SLIGHT; 65 case FC_HINT_MEDIUM: 66 return CAIRO_HINT_STYLE_MEDIUM; 67 case FC_HINT_FULL: 68 return CAIRO_HINT_STYLE_FULL; 69 } 70 return CAIRO_HINT_STYLE_NONE; 71} 72 73void setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t* options, FcPattern* pattern) 74{ 75 FcBool booleanResult; 76 int integerResult; 77 78 if (FcPatternGetInteger(pattern, FC_RGBA, 0, &integerResult) == FcResultMatch) { 79 cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult)); 80 81 // Based on the logic in cairo-ft-font.c in the cairo source, a font with 82 // a subpixel order implies that is uses subpixel antialiasing. 83 if (integerResult != FC_RGBA_NONE) 84 cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL); 85 } 86 87 if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch) { 88 // Only override the anti-aliasing setting if was previously turned off. Otherwise 89 // we'll override the preference which decides between gray anti-aliasing and 90 // subpixel anti-aliasing. 91 if (!booleanResult) 92 cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_NONE); 93 else if (cairo_font_options_get_antialias(options) == CAIRO_ANTIALIAS_NONE) 94 cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); 95 } 96 97 if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &integerResult) == FcResultMatch) 98 cairo_font_options_set_hint_style(options, convertFontConfigHintStyle(integerResult)); 99 if (FcPatternGetBool(pattern, FC_HINTING, 0, &booleanResult) == FcResultMatch && !booleanResult) 100 cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); 101} 102 103static cairo_font_options_t* getDefaultFontOptions() 104{ 105#if PLATFORM(GTK) 106 if (GdkScreen* screen = gdk_screen_get_default()) { 107 const cairo_font_options_t* screenOptions = gdk_screen_get_font_options(screen); 108 if (screenOptions) 109 return cairo_font_options_copy(screenOptions); 110 } 111#endif 112 return cairo_font_options_create(); 113} 114 115FontPlatformData::FontPlatformData(FcPattern* pattern, const FontDescription& fontDescription) 116 : m_pattern(pattern) 117 , m_fallbacks(0) 118 , m_size(fontDescription.computedPixelSize()) 119 , m_syntheticBold(false) 120 , m_syntheticOblique(false) 121 , m_fixedWidth(false) 122 , m_scaledFont(0) 123{ 124 RefPtr<cairo_font_face_t> fontFace = adoptRef(cairo_ft_font_face_create_for_pattern(m_pattern.get())); 125 initializeWithFontFace(fontFace.get()); 126 127 int spacing; 128 if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch && spacing == FC_MONO) 129 m_fixedWidth = true; 130 131 if (fontDescription.weight() >= FontWeightBold) { 132 // The FC_EMBOLDEN property instructs us to fake the boldness of the font. 133 FcBool fontConfigEmbolden; 134 if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &fontConfigEmbolden) == FcResultMatch) 135 m_syntheticBold = fontConfigEmbolden; 136 } 137} 138 139FontPlatformData::FontPlatformData(float size, bool bold, bool italic) 140 : m_fallbacks(0) 141 , m_size(size) 142 , m_syntheticBold(bold) 143 , m_syntheticOblique(italic) 144 , m_fixedWidth(false) 145 , m_scaledFont(0) 146{ 147 // We cannot create a scaled font here. 148} 149 150FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic) 151 : m_fallbacks(0) 152 , m_size(size) 153 , m_syntheticBold(bold) 154 , m_syntheticOblique(italic) 155 , m_scaledFont(0) 156{ 157 initializeWithFontFace(fontFace); 158 159 FT_Face fontConfigFace = cairo_ft_scaled_font_lock_face(m_scaledFont); 160 if (fontConfigFace) { 161 m_fixedWidth = fontConfigFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH; 162 cairo_ft_scaled_font_unlock_face(m_scaledFont); 163 } 164} 165 166FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) 167{ 168 // Check for self-assignment. 169 if (this == &other) 170 return *this; 171 172 m_size = other.m_size; 173 m_syntheticBold = other.m_syntheticBold; 174 m_syntheticOblique = other.m_syntheticOblique; 175 m_fixedWidth = other.m_fixedWidth; 176 m_pattern = other.m_pattern; 177 178 if (m_fallbacks) { 179 FcFontSetDestroy(m_fallbacks); 180 // This will be re-created on demand. 181 m_fallbacks = 0; 182 } 183 184 if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue()) 185 cairo_scaled_font_destroy(m_scaledFont); 186 m_scaledFont = cairo_scaled_font_reference(other.m_scaledFont); 187 188 return *this; 189} 190 191FontPlatformData::FontPlatformData(const FontPlatformData& other) 192 : m_fallbacks(0) 193 , m_scaledFont(0) 194{ 195 *this = other; 196} 197 198FontPlatformData::FontPlatformData(const FontPlatformData& other, float size) 199{ 200 *this = other; 201 202 // We need to reinitialize the instance, because the difference in size 203 // necessitates a new scaled font instance. 204 m_size = size; 205 initializeWithFontFace(cairo_scaled_font_get_font_face(m_scaledFont)); 206} 207 208FontPlatformData::~FontPlatformData() 209{ 210 if (m_fallbacks) { 211 FcFontSetDestroy(m_fallbacks); 212 m_fallbacks = 0; 213 } 214 215 if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue()) 216 cairo_scaled_font_destroy(m_scaledFont); 217} 218 219bool FontPlatformData::isFixedPitch() 220{ 221 return m_fixedWidth; 222} 223 224bool FontPlatformData::operator==(const FontPlatformData& other) const 225{ 226 if (m_pattern == other.m_pattern) 227 return true; 228 if (!m_pattern || !other.m_pattern) 229 return false; 230 return FcPatternEqual(m_pattern.get(), other.m_pattern.get()) 231 && m_scaledFont == other.m_scaledFont && m_size == other.m_size 232 && m_syntheticOblique == other.m_syntheticOblique && m_syntheticBold == other.m_syntheticBold; 233} 234 235#ifndef NDEBUG 236String FontPlatformData::description() const 237{ 238 return String(); 239} 240#endif 241 242void FontPlatformData::initializeWithFontFace(cairo_font_face_t* fontFace) 243{ 244 cairo_font_options_t* options = getDefaultFontOptions(); 245 246 cairo_matrix_t ctm; 247 cairo_matrix_init_identity(&ctm); 248 249 cairo_matrix_t fontMatrix; 250 if (!m_pattern) 251 cairo_matrix_init_scale(&fontMatrix, m_size, m_size); 252 else { 253 setCairoFontOptionsFromFontConfigPattern(options, m_pattern.get()); 254 255 // FontConfig may return a list of transformation matrices with the pattern, for instance, 256 // for fonts that are oblique. We use that to initialize the cairo font matrix. 257 FcMatrix fontConfigMatrix, *tempFontConfigMatrix; 258 FcMatrixInit(&fontConfigMatrix); 259 260 // These matrices may be stacked in the pattern, so it's our job to get them all and multiply them. 261 for (int i = 0; FcPatternGetMatrix(m_pattern.get(), FC_MATRIX, i, &tempFontConfigMatrix) == FcResultMatch; i++) 262 FcMatrixMultiply(&fontConfigMatrix, &fontConfigMatrix, tempFontConfigMatrix); 263 cairo_matrix_init(&fontMatrix, fontConfigMatrix.xx, -fontConfigMatrix.yx, 264 -fontConfigMatrix.xy, fontConfigMatrix.yy, 0, 0); 265 266 // The matrix from FontConfig does not include the scale. 267 cairo_matrix_scale(&fontMatrix, m_size, m_size); 268 } 269 270 m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options); 271 cairo_font_options_destroy(options); 272} 273 274bool FontPlatformData::hasCompatibleCharmap() 275{ 276 if (!m_scaledFont) 277 return false; 278 279 FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont); 280 bool hasCompatibleCharmap = !(FT_Select_Charmap(freeTypeFace, ft_encoding_unicode) 281 && FT_Select_Charmap(freeTypeFace, ft_encoding_symbol) 282 && FT_Select_Charmap(freeTypeFace, ft_encoding_apple_roman)); 283 cairo_ft_scaled_font_unlock_face(m_scaledFont); 284 return hasCompatibleCharmap; 285} 286 287} 288