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
38 namespace WebCore {
39
convertFontConfigSubpixelOrder(int fontConfigOrder)40 cairo_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
convertFontConfigHintStyle(int fontConfigStyle)58 cairo_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
setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t * options,FcPattern * pattern)73 void 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
getDefaultFontOptions()103 static 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
FontPlatformData(FcPattern * pattern,const FontDescription & fontDescription)115 FontPlatformData::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
FontPlatformData(float size,bool bold,bool italic)139 FontPlatformData::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
FontPlatformData(cairo_font_face_t * fontFace,float size,bool bold,bool italic)150 FontPlatformData::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
operator =(const FontPlatformData & other)166 FontPlatformData& 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
FontPlatformData(const FontPlatformData & other)191 FontPlatformData::FontPlatformData(const FontPlatformData& other)
192 : m_fallbacks(0)
193 , m_scaledFont(0)
194 {
195 *this = other;
196 }
197
FontPlatformData(const FontPlatformData & other,float size)198 FontPlatformData::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
~FontPlatformData()208 FontPlatformData::~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
isFixedPitch()219 bool FontPlatformData::isFixedPitch()
220 {
221 return m_fixedWidth;
222 }
223
operator ==(const FontPlatformData & other) const224 bool 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
description() const236 String FontPlatformData::description() const
237 {
238 return String();
239 }
240 #endif
241
initializeWithFontFace(cairo_font_face_t * fontFace)242 void 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
hasCompatibleCharmap()274 bool 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