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