no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / gfx / 2d / UnscaledFontFreeType.cpp
blob97af653ed62713eb95ef50f2a982422615d19cba
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "UnscaledFontFreeType.h"
8 #include "NativeFontResourceFreeType.h"
9 #include "ScaledFontFreeType.h"
10 #include "Logging.h"
11 #include "StackArray.h"
13 #include FT_MULTIPLE_MASTERS_H
14 #include FT_TRUETYPE_TABLES_H
16 #include <dlfcn.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
23 namespace mozilla::gfx {
25 bool UnscaledFontFreeType::GetFontFileData(FontFileDataOutput aDataCallback,
26 void* aBaton) {
27 if (!mFile.empty()) {
28 int fd = open(mFile.c_str(), O_RDONLY);
29 if (fd < 0) {
30 return false;
32 struct stat buf;
33 if (fstat(fd, &buf) < 0 ||
34 // Don't erroneously read directories as files.
35 !S_ISREG(buf.st_mode) ||
36 // Verify the file size fits in a uint32_t.
37 buf.st_size <= 0 || off_t(uint32_t(buf.st_size)) != buf.st_size) {
38 close(fd);
39 return false;
41 uint32_t length = buf.st_size;
42 uint8_t* fontData = reinterpret_cast<uint8_t*>(
43 mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0));
44 close(fd);
45 if (fontData == MAP_FAILED) {
46 return false;
48 aDataCallback(fontData, length, mIndex, aBaton);
49 munmap(fontData, length);
50 return true;
53 bool success = false;
54 FT_ULong length = 0;
55 // Request the SFNT file. This may not always succeed for all font types.
56 if (FT_Load_Sfnt_Table(mFace->GetFace(), 0, 0, nullptr, &length) ==
57 FT_Err_Ok) {
58 uint8_t* fontData = new uint8_t[length];
59 if (FT_Load_Sfnt_Table(mFace->GetFace(), 0, 0, fontData, &length) ==
60 FT_Err_Ok) {
61 aDataCallback(fontData, length, 0, aBaton);
62 success = true;
64 delete[] fontData;
66 return success;
69 bool UnscaledFontFreeType::GetFontDescriptor(FontDescriptorOutput aCb,
70 void* aBaton) {
71 if (mFile.empty()) {
72 return false;
75 aCb(reinterpret_cast<const uint8_t*>(mFile.data()), mFile.size(), mIndex,
76 aBaton);
77 return true;
80 RefPtr<SharedFTFace> UnscaledFontFreeType::InitFace() {
81 if (mFace) {
82 return mFace;
84 if (mFile.empty()) {
85 return nullptr;
87 mFace = Factory::NewSharedFTFace(nullptr, mFile.c_str(), mIndex);
88 if (!mFace) {
89 gfxWarning() << "Failed initializing FreeType face from filename";
90 return nullptr;
92 return mFace;
95 void UnscaledFontFreeType::GetVariationSettingsFromFace(
96 std::vector<FontVariation>* aVariations, FT_Face aFace) {
97 if (!aFace || !(aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
98 return;
101 typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
102 typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
103 typedef FT_Error (*GetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
104 #if MOZ_TREE_FREETYPE
105 GetVarFunc getVar = &FT_Get_MM_Var;
106 DoneVarFunc doneVar = &FT_Done_MM_Var;
107 GetVarDesignCoordsFunc getCoords = &FT_Get_Var_Design_Coordinates;
108 #else
109 static GetVarFunc getVar;
110 static DoneVarFunc doneVar;
111 static GetVarDesignCoordsFunc getCoords;
112 static bool firstTime = true;
113 if (firstTime) {
114 firstTime = false;
115 getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
116 doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
117 getCoords = (GetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT,
118 "FT_Get_Var_Design_Coordinates");
120 if (!getVar || !getCoords) {
121 return;
123 #endif
125 FT_MM_Var* mmVar = nullptr;
126 if ((*getVar)(aFace, &mmVar) == FT_Err_Ok) {
127 aVariations->reserve(mmVar->num_axis);
128 StackArray<FT_Fixed, 32> coords(mmVar->num_axis);
129 if ((*getCoords)(aFace, mmVar->num_axis, coords.data()) == FT_Err_Ok) {
130 bool changed = false;
131 for (uint32_t i = 0; i < mmVar->num_axis; i++) {
132 if (coords[i] != mmVar->axis[i].def) {
133 changed = true;
135 aVariations->push_back(FontVariation{uint32_t(mmVar->axis[i].tag),
136 float(coords[i] / 65536.0)});
138 if (!changed) {
139 aVariations->clear();
142 if (doneVar) {
143 (*doneVar)(aFace->glyph->library, mmVar);
144 } else {
145 free(mmVar);
150 void UnscaledFontFreeType::ApplyVariationsToFace(
151 const FontVariation* aVariations, uint32_t aNumVariations, FT_Face aFace) {
152 if (!aFace || !(aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
153 return;
156 typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
157 #ifdef MOZ_TREE_FREETYPE
158 SetVarDesignCoordsFunc setCoords = &FT_Set_Var_Design_Coordinates;
159 #else
160 typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
161 static SetVarDesignCoordsFunc setCoords;
162 static bool firstTime = true;
163 if (firstTime) {
164 firstTime = false;
165 setCoords = (SetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT,
166 "FT_Set_Var_Design_Coordinates");
168 if (!setCoords) {
169 return;
171 #endif
173 StackArray<FT_Fixed, 32> coords(aNumVariations);
174 for (uint32_t i = 0; i < aNumVariations; i++) {
175 coords[i] = std::round(aVariations[i].mValue * 65536.0f);
177 if ((*setCoords)(aFace, aNumVariations, coords.data()) != FT_Err_Ok) {
178 // ignore the problem?
182 #ifdef MOZ_WIDGET_ANDROID
184 already_AddRefed<ScaledFont> UnscaledFontFreeType::CreateScaledFont(
185 Float aGlyphSize, const uint8_t* aInstanceData,
186 uint32_t aInstanceDataLength, const FontVariation* aVariations,
187 uint32_t aNumVariations) {
188 if (aInstanceDataLength < sizeof(ScaledFontFreeType::InstanceData)) {
189 gfxWarning() << "FreeType scaled font instance data is truncated.";
190 return nullptr;
192 const ScaledFontFreeType::InstanceData& instanceData =
193 *reinterpret_cast<const ScaledFontFreeType::InstanceData*>(aInstanceData);
195 RefPtr<SharedFTFace> face(InitFace());
196 if (!face) {
197 gfxWarning() << "Attempted to deserialize FreeType scaled font without "
198 "FreeType face";
199 return nullptr;
202 if (aNumVariations > 0 && face->GetData()) {
203 if (RefPtr<SharedFTFace> varFace = face->GetData()->CloneFace()) {
204 face = varFace;
208 // Only apply variations if we have an explicitly cloned face.
209 if (aNumVariations > 0 && face != GetFace()) {
210 ApplyVariationsToFace(aVariations, aNumVariations, face->GetFace());
213 RefPtr<ScaledFontFreeType> scaledFont = new ScaledFontFreeType(
214 std::move(face), this, aGlyphSize, instanceData.mApplySyntheticBold);
216 return scaledFont.forget();
219 already_AddRefed<ScaledFont> UnscaledFontFreeType::CreateScaledFontFromWRFont(
220 Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
221 const wr::FontInstancePlatformOptions* aPlatformOptions,
222 const FontVariation* aVariations, uint32_t aNumVariations) {
223 ScaledFontFreeType::InstanceData instanceData(aOptions, aPlatformOptions);
224 return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
225 sizeof(instanceData), aVariations, aNumVariations);
228 already_AddRefed<UnscaledFont> UnscaledFontFreeType::CreateFromFontDescriptor(
229 const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
230 if (aDataLength == 0) {
231 gfxWarning() << "FreeType font descriptor is truncated.";
232 return nullptr;
234 const char* path = reinterpret_cast<const char*>(aData);
235 RefPtr<UnscaledFont> unscaledFont =
236 new UnscaledFontFreeType(std::string(path, aDataLength), aIndex);
237 return unscaledFont.forget();
240 #endif // MOZ_WIDGET_ANDROID
242 } // namespace mozilla::gfx