[FreeType] Add initial implementation of variation fonts
[WebKit-https.git] / Source / WebCore / platform / graphics / freetype / FontCustomPlatformDataFreeType.cpp
1 /*
2  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
3  * Copyright (C) 2010 Igalia S.L.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "FontCustomPlatformData.h"
24
25 #include "CairoUtilities.h"
26 #include "FontCacheFreeType.h"
27 #include "FontDescription.h"
28 #include "FontPlatformData.h"
29 #include "SharedBuffer.h"
30 #include <cairo-ft.h>
31 #include <cairo.h>
32 #include <ft2build.h>
33 #include FT_MODULE_H
34
35 namespace WebCore {
36
37 static void releaseCustomFontData(void* data)
38 {
39     static_cast<SharedBuffer*>(data)->deref();
40 }
41
42 static cairo_user_data_key_t freeTypeFaceKey;
43
44 FontCustomPlatformData::FontCustomPlatformData(FT_Face freeTypeFace, SharedBuffer& buffer)
45     : m_fontFace(adoptRef(cairo_ft_font_face_create_for_ft_face(freeTypeFace, FT_LOAD_DEFAULT)))
46 {
47     buffer.ref(); // This is balanced by the buffer->deref() in releaseCustomFontData.
48     static cairo_user_data_key_t bufferKey;
49     cairo_font_face_set_user_data(m_fontFace.get(), &bufferKey, &buffer,
50          static_cast<cairo_destroy_func_t>(releaseCustomFontData));
51
52     // Cairo doesn't do FreeType reference counting, so we need to ensure that when
53     // this cairo_font_face_t is destroyed, it cleans up the FreeType face as well.
54     cairo_font_face_set_user_data(m_fontFace.get(), &freeTypeFaceKey, freeTypeFace,
55         reinterpret_cast<cairo_destroy_func_t>(reinterpret_cast<void(*)(void)>(FT_Done_Face)));
56 }
57
58 static FcPattern* defaultFontconfigOptions()
59 {
60     // Get some generic default settings from fontconfig for web fonts. Strategy
61     // from Behdad Esfahbod in https://code.google.com/p/chromium/issues/detail?id=173207#c35
62     // For web fonts, the hint style is overridden in FontCustomPlatformData::FontCustomPlatformData
63     // so Fontconfig will not affect the hint style, but it may disable hinting completely.
64     static FcPattern* pattern = nullptr;
65     static std::once_flag flag;
66     std::call_once(flag, [](FcPattern*) {
67         pattern = FcPatternCreate();
68         FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
69         cairo_ft_font_options_substitute(getDefaultCairoFontOptions(), pattern);
70         FcDefaultSubstitute(pattern);
71         FcPatternDel(pattern, FC_FAMILY);
72         FcConfigSubstitute(nullptr, pattern, FcMatchFont);
73     }, pattern);
74     return pattern;
75 }
76
77 FontPlatformData FontCustomPlatformData::fontPlatformData(const FontDescription& description, bool bold, bool italic, const FontFeatureSettings&, const FontVariantSettings&, FontSelectionSpecifiedCapabilities)
78 {
79     auto* freeTypeFace = static_cast<FT_Face>(cairo_font_face_get_user_data(m_fontFace.get(), &freeTypeFaceKey));
80     ASSERT(freeTypeFace);
81     RefPtr<FcPattern> pattern = defaultFontconfigOptions();
82 #if ENABLE(VARIATION_FONTS)
83     auto variants = buildVariationSettings(freeTypeFace, description);
84     if (!variants.isEmpty()) {
85         pattern = adoptRef(FcPatternDuplicate(pattern.get()));
86         FcPatternAddString(pattern.get(), FC_FONT_VARIATIONS, reinterpret_cast<const FcChar8*>(variants.utf8().data()));
87     }
88 #endif
89     return FontPlatformData(m_fontFace.get(), pattern.get(), description.computedPixelSize(), freeTypeFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH, bold, italic, description.orientation());
90 }
91
92 static bool initializeFreeTypeLibrary(FT_Library& library)
93 {
94     // https://www.freetype.org/freetype2/docs/design/design-4.html
95     // https://lists.nongnu.org/archive/html/freetype-devel/2004-10/msg00022.html
96
97     FT_Memory memory = bitwise_cast<FT_Memory>(ft_smalloc(sizeof(*memory)));
98     if (!memory)
99         return false;
100
101     memory->user = nullptr;
102     memory->alloc = [](FT_Memory, long size) -> void* {
103         return fastMalloc(size);
104     };
105     memory->free = [](FT_Memory, void* block) -> void {
106         fastFree(block);
107     };
108     memory->realloc = [](FT_Memory, long, long newSize, void* block) -> void* {
109         return fastRealloc(block, newSize);
110     };
111
112     if (FT_New_Library(memory, &library)) {
113         ft_sfree(memory);
114         return false;
115     }
116
117     FT_Add_Default_Modules(library);
118     return true;
119 }
120
121 std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer, const String&)
122 {
123     static FT_Library library;
124     if (!library && !initializeFreeTypeLibrary(library)) {
125         library = nullptr;
126         return nullptr;
127     }
128
129     FT_Face freeTypeFace;
130     if (FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer.data()), buffer.size(), 0, &freeTypeFace))
131         return nullptr;
132     return std::make_unique<FontCustomPlatformData>(freeTypeFace, buffer);
133 }
134
135 bool FontCustomPlatformData::supportsFormat(const String& format)
136 {
137     return equalLettersIgnoringASCIICase(format, "truetype")
138         || equalLettersIgnoringASCIICase(format, "opentype")
139 #if USE(WOFF2)
140         || equalLettersIgnoringASCIICase(format, "woff2")
141 #if ENABLE(VARIATION_FONTS)
142         || equalLettersIgnoringASCIICase(format, "woff2-variations")
143 #endif
144 #endif
145 #if ENABLE(VARIATION_FONTS)
146         || equalLettersIgnoringASCIICase(format, "woff-variations")
147         || equalLettersIgnoringASCIICase(format, "truetype-variations")
148         || equalLettersIgnoringASCIICase(format, "opentype-variations")
149 #endif
150         || equalLettersIgnoringASCIICase(format, "woff");
151 }
152
153 }