Revert bug 19975, now that gcc 4.7 is required.
[WebKit-https.git] / Source / WebCore / platform / graphics / freetype / FontPlatformDataFreeType.cpp
1 /*
2  * Copyright (C) 2006 Apple 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 "FontDescription.h"
29 #include "RefPtrCairo.h"
30 #include <cairo-ft.h>
31 #include <cairo.h>
32 #include <fontconfig/fcfreetype.h>
33 #include <ft2build.h>
34 #include FT_TRUETYPE_TABLES_H
35 #include <wtf/MathExtras.h>
36 #include <wtf/text/WTFString.h>
37
38 #if !PLATFORM(EFL)
39 #include <gdk/gdk.h>
40 #endif
41
42 namespace WebCore {
43
44 cairo_subpixel_order_t convertFontConfigSubpixelOrder(int fontConfigOrder)
45 {
46     switch (fontConfigOrder) {
47     case FC_RGBA_RGB:
48         return CAIRO_SUBPIXEL_ORDER_RGB;
49     case FC_RGBA_BGR:
50         return CAIRO_SUBPIXEL_ORDER_BGR;
51     case FC_RGBA_VRGB:
52         return CAIRO_SUBPIXEL_ORDER_VRGB;
53     case FC_RGBA_VBGR:
54         return CAIRO_SUBPIXEL_ORDER_VBGR;
55     case FC_RGBA_NONE:
56     case FC_RGBA_UNKNOWN:
57         return CAIRO_SUBPIXEL_ORDER_DEFAULT;
58     }
59     return CAIRO_SUBPIXEL_ORDER_DEFAULT;
60 }
61
62 cairo_hint_style_t convertFontConfigHintStyle(int fontConfigStyle)
63 {
64     switch (fontConfigStyle) {
65     case FC_HINT_NONE:
66         return CAIRO_HINT_STYLE_NONE;
67     case FC_HINT_SLIGHT:
68         return CAIRO_HINT_STYLE_SLIGHT;
69     case FC_HINT_MEDIUM:
70         return CAIRO_HINT_STYLE_MEDIUM;
71     case FC_HINT_FULL:
72         return CAIRO_HINT_STYLE_FULL;
73     }
74     return CAIRO_HINT_STYLE_NONE;
75 }
76
77 void setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t* options, FcPattern* pattern)
78 {
79     FcBool booleanResult;
80     int integerResult;
81
82     if (FcPatternGetInteger(pattern, FC_RGBA, 0, &integerResult) == FcResultMatch) {
83         cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult));
84
85         // Based on the logic in cairo-ft-font.c in the cairo source, a font with
86         // a subpixel order implies that is uses subpixel antialiasing.
87         if (integerResult != FC_RGBA_NONE)
88             cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL);
89     }
90
91     if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch) {
92         // Only override the anti-aliasing setting if was previously turned off. Otherwise
93         // we'll override the preference which decides between gray anti-aliasing and
94         // subpixel anti-aliasing.
95         if (!booleanResult)
96             cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_NONE);
97         else if (cairo_font_options_get_antialias(options) == CAIRO_ANTIALIAS_NONE)
98             cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
99     }
100
101     if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &integerResult) == FcResultMatch)
102         cairo_font_options_set_hint_style(options, convertFontConfigHintStyle(integerResult));
103     if (FcPatternGetBool(pattern, FC_HINTING, 0, &booleanResult) == FcResultMatch && !booleanResult)
104         cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
105 }
106
107 static cairo_font_options_t* getDefaultCairoFontOptions()
108 {
109 #if PLATFORM(GTK)
110     if (GdkScreen* screen = gdk_screen_get_default()) {
111         const cairo_font_options_t* screenOptions = gdk_screen_get_font_options(screen);
112         if (screenOptions)
113             return cairo_font_options_copy(screenOptions);
114     }
115 #endif
116     return cairo_font_options_create();
117 }
118
119 static FcPattern* getDefaultFontconfigOptions()
120 {
121     // Get some generic default settings from fontconfig for web fonts. Strategy
122     // from Behdad Esfahbod in https://code.google.com/p/chromium/issues/detail?id=173207#c35
123     // For web fonts, the hint style is overridden in FontCustomPlatformData::FontCustomPlatformData
124     // so Fontconfig will not affect the hint style, but it may disable hinting completely.
125     static FcPattern* pattern = nullptr;
126     static std::once_flag flag;
127     std::call_once(flag, [](FcPattern*) {
128         pattern = FcPatternCreate();
129         FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
130         FcDefaultSubstitute(pattern);
131         FcPatternDel(pattern, FC_FAMILY);
132         FcConfigSubstitute(nullptr, pattern, FcMatchFont);
133     }, pattern);
134     return pattern;
135 }
136
137 static void rotateCairoMatrixForVerticalOrientation(cairo_matrix_t* matrix)
138 {
139     // The resulting transformation matrix for vertical glyphs (V) is a
140     // combination of rotation (R) and translation (T) applied on the
141     // horizontal matrix (H). V = H . R . T, where R rotates by -90 degrees
142     // and T translates by font size towards y axis.
143     cairo_matrix_rotate(matrix, -piOverTwoDouble);
144     cairo_matrix_translate(matrix, 0.0, 1.0);
145 }
146
147 FontPlatformData::FontPlatformData(FcPattern* pattern, const FontDescription& fontDescription)
148     : m_pattern(pattern)
149     , m_fallbacks(nullptr)
150     , m_size(fontDescription.computedPixelSize())
151     , m_syntheticBold(false)
152     , m_syntheticOblique(false)
153     , m_fixedWidth(false)
154     , m_scaledFont(nullptr)
155     , m_orientation(fontDescription.orientation())
156 {
157     RefPtr<cairo_font_face_t> fontFace = adoptRef(cairo_ft_font_face_create_for_pattern(m_pattern.get()));
158     initializeWithFontFace(fontFace.get(), fontDescription);
159
160     int spacing;
161     if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch && spacing == FC_MONO)
162         m_fixedWidth = true;
163
164     if (fontDescription.weight() >= FontWeightBold) {
165         // The FC_EMBOLDEN property instructs us to fake the boldness of the font.
166         FcBool fontConfigEmbolden = FcFalse;
167         if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &fontConfigEmbolden) == FcResultMatch)
168             m_syntheticBold = fontConfigEmbolden;
169
170         // Fallback fonts may not have FC_EMBOLDEN activated even though it's necessary.
171         int weight = 0;
172         if (!m_syntheticBold && FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) == FcResultMatch)
173             m_syntheticBold = m_syntheticBold || weight < FC_WEIGHT_DEMIBOLD;
174     }
175 }
176
177 FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
178     : m_fallbacks(nullptr)
179     , m_size(size)
180     , m_syntheticBold(bold)
181     , m_syntheticOblique(italic)
182     , m_fixedWidth(false)
183     , m_scaledFont(nullptr)
184     , m_orientation(Horizontal)
185 {
186     // We cannot create a scaled font here.
187 }
188
189 FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic, FontOrientation orientation)
190     : m_fallbacks(nullptr)
191     , m_size(size)
192     , m_syntheticBold(bold)
193     , m_syntheticOblique(italic)
194     , m_fixedWidth(false)
195     , m_scaledFont(nullptr)
196     , m_orientation(orientation)
197 {
198     initializeWithFontFace(fontFace);
199
200     FT_Face fontConfigFace = cairo_ft_scaled_font_lock_face(m_scaledFont);
201     if (fontConfigFace) {
202         m_fixedWidth = fontConfigFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
203         cairo_ft_scaled_font_unlock_face(m_scaledFont);
204     }
205 }
206
207 FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
208 {
209     // Check for self-assignment.
210     if (this == &other)
211         return *this;
212
213     m_size = other.m_size;
214     m_syntheticBold = other.m_syntheticBold;
215     m_syntheticOblique = other.m_syntheticOblique;
216     m_fixedWidth = other.m_fixedWidth;
217     m_pattern = other.m_pattern;
218     m_orientation = other.m_orientation;
219     m_horizontalOrientationMatrix = other.m_horizontalOrientationMatrix;
220
221     if (m_fallbacks) {
222         FcFontSetDestroy(m_fallbacks);
223         // This will be re-created on demand.
224         m_fallbacks = nullptr;
225     }
226
227     if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue())
228         cairo_scaled_font_destroy(m_scaledFont);
229     m_scaledFont = cairo_scaled_font_reference(other.m_scaledFont);
230
231     m_harfBuzzFace = other.m_harfBuzzFace;
232
233     return *this;
234 }
235
236 FontPlatformData::FontPlatformData(const FontPlatformData& other)
237     : m_fallbacks(nullptr)
238     , m_scaledFont(nullptr)
239     , m_harfBuzzFace(other.m_harfBuzzFace)
240 {
241     *this = other;
242 }
243
244 FontPlatformData::FontPlatformData(const FontPlatformData& other, float size)
245     : m_fallbacks(nullptr)
246     , m_scaledFont(nullptr)
247     , m_harfBuzzFace(other.m_harfBuzzFace)
248 {
249     *this = other;
250
251     // We need to reinitialize the instance, because the difference in size 
252     // necessitates a new scaled font instance.
253     m_size = size;
254     initializeWithFontFace(cairo_scaled_font_get_font_face(m_scaledFont));
255 }
256
257 FontPlatformData::~FontPlatformData()
258 {
259     if (m_fallbacks) {
260         FcFontSetDestroy(m_fallbacks);
261         m_fallbacks = nullptr;
262     }
263
264     if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue())
265         cairo_scaled_font_destroy(m_scaledFont);
266 }
267
268 HarfBuzzFace* FontPlatformData::harfBuzzFace() const
269 {
270     if (!m_harfBuzzFace)
271         m_harfBuzzFace = HarfBuzzFace::create(const_cast<FontPlatformData*>(this), hash());
272
273     return m_harfBuzzFace.get();
274 }
275
276 bool FontPlatformData::isFixedPitch()
277 {
278     return m_fixedWidth;
279 }
280
281 bool FontPlatformData::operator==(const FontPlatformData& other) const
282 {
283     // FcPatternEqual does not support null pointers as arguments.
284     if ((m_pattern && !other.m_pattern)
285         || (!m_pattern && other.m_pattern)
286         || (m_pattern != other.m_pattern && !FcPatternEqual(m_pattern.get(), other.m_pattern.get())))
287         return false;
288
289     return m_scaledFont == other.m_scaledFont
290         && m_size == other.m_size
291         && m_syntheticOblique == other.m_syntheticOblique
292         && m_orientation == other.m_orientation
293         && m_syntheticBold == other.m_syntheticBold; 
294 }
295
296 #ifndef NDEBUG
297 String FontPlatformData::description() const
298 {
299     return String();
300 }
301 #endif
302
303 void FontPlatformData::initializeWithFontFace(cairo_font_face_t* fontFace, const FontDescription& fontDescription)
304 {
305     cairo_font_options_t* options = getDefaultCairoFontOptions();
306     FcPattern* optionsPattern = m_pattern ? m_pattern.get() : getDefaultFontconfigOptions();
307     setCairoFontOptionsFromFontConfigPattern(options, optionsPattern);
308
309     cairo_matrix_t ctm;
310     cairo_matrix_init_identity(&ctm);
311
312     // Scaling a font with width zero size leads to a failed cairo_scaled_font_t instantiations.
313     // Instead we scale we scale the font to a very tiny size and just abort rendering later on.
314     float realSize = m_size ? m_size : 1;
315
316     // FontConfig may return a list of transformation matrices with the pattern, for instance,
317     // for fonts that are oblique. We use that to initialize the cairo font matrix.
318     cairo_matrix_t fontMatrix;
319     FcMatrix fontConfigMatrix, *tempFontConfigMatrix;
320     FcMatrixInit(&fontConfigMatrix);
321
322     // These matrices may be stacked in the pattern, so it's our job to get them all and multiply them.
323     for (int i = 0; FcPatternGetMatrix(m_pattern.get(), FC_MATRIX, i, &tempFontConfigMatrix) == FcResultMatch; i++)
324         FcMatrixMultiply(&fontConfigMatrix, &fontConfigMatrix, tempFontConfigMatrix);
325     cairo_matrix_init(&fontMatrix, fontConfigMatrix.xx, -fontConfigMatrix.yx,
326         -fontConfigMatrix.xy, fontConfigMatrix.yy, 0, 0);
327
328     // We requested an italic font, but Fontconfig gave us one that was neither oblique nor italic.
329     int actualFontSlant;
330     if (fontDescription.italic() && FcPatternGetInteger(m_pattern.get(), FC_SLANT, 0, &actualFontSlant) == FcResultMatch)
331         m_syntheticOblique = actualFontSlant == FC_SLANT_ROMAN;
332
333     // The matrix from FontConfig does not include the scale. 
334     cairo_matrix_scale(&fontMatrix, realSize, realSize);
335
336     if (syntheticOblique()) {
337         static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
338         cairo_matrix_t skew = {1, 0, syntheticObliqueSkew, 1, 0, 0};
339         cairo_matrix_multiply(&fontMatrix, &skew, &fontMatrix);
340     }
341
342     m_horizontalOrientationMatrix = fontMatrix;
343     if (m_orientation == Vertical)
344         rotateCairoMatrixForVerticalOrientation(&fontMatrix);
345
346     m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
347     cairo_font_options_destroy(options);
348 }
349
350 bool FontPlatformData::hasCompatibleCharmap()
351 {
352     ASSERT(m_scaledFont);
353     FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont);
354     bool hasCompatibleCharmap = !(FT_Select_Charmap(freeTypeFace, ft_encoding_unicode)
355                                 && FT_Select_Charmap(freeTypeFace, ft_encoding_symbol)
356                                 && FT_Select_Charmap(freeTypeFace, ft_encoding_apple_roman));
357     cairo_ft_scaled_font_unlock_face(m_scaledFont);
358     return hasCompatibleCharmap;
359 }
360
361 PassRefPtr<OpenTypeVerticalData> FontPlatformData::verticalData() const
362 {
363     ASSERT(hash());
364     return FontCache::singleton().getVerticalData(String::number(hash()), *this);
365 }
366
367 PassRefPtr<SharedBuffer> FontPlatformData::openTypeTable(uint32_t table) const
368 {
369     FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont);
370     if (!freeTypeFace)
371         return nullptr;
372
373     FT_ULong tableSize = 0;
374     // Tag bytes need to be reversed because OT_MAKE_TAG uses big-endian order.
375     uint32_t tag = FT_MAKE_TAG((table & 0xff), (table & 0xff00) >> 8, (table & 0xff0000) >> 16, table >> 24);
376     if (FT_Load_Sfnt_Table(freeTypeFace, tag, 0, 0, &tableSize))
377         return nullptr;
378
379     RefPtr<SharedBuffer> buffer = SharedBuffer::create(tableSize);
380     FT_ULong expectedTableSize = tableSize;
381     if (buffer->size() != tableSize)
382         return nullptr;
383
384     FT_Error error = FT_Load_Sfnt_Table(freeTypeFace, tag, 0, reinterpret_cast<FT_Byte*>(const_cast<char*>(buffer->data())), &tableSize);
385     if (error || tableSize != expectedTableSize)
386         return nullptr;
387
388     cairo_ft_scaled_font_unlock_face(m_scaledFont);
389
390     return buffer.release();
391 }
392
393 void FontPlatformData::setOrientation(FontOrientation orientation)
394 {
395     ASSERT(m_scaledFont);
396
397     if (!m_scaledFont || (m_orientation == orientation))
398         return;
399
400     cairo_matrix_t transformationMatrix;
401     cairo_matrix_init_identity(&transformationMatrix);
402
403     cairo_matrix_t fontMatrix;
404     cairo_scaled_font_get_font_matrix(m_scaledFont, &fontMatrix);
405
406     cairo_font_options_t* options = getDefaultCairoFontOptions();
407
408     // In case of vertical orientation, rotate the transformation matrix.
409     // Otherwise restore the horizontal orientation matrix.
410     if (orientation == Vertical)
411         rotateCairoMatrixForVerticalOrientation(&fontMatrix);
412     else
413         fontMatrix = m_horizontalOrientationMatrix;
414
415     cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(m_scaledFont);
416     cairo_scaled_font_destroy(m_scaledFont);
417     m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &transformationMatrix, options);
418     cairo_font_options_destroy(options);
419     m_orientation = orientation;
420 }
421
422 }