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/. */
6 
7 #include "UnscaledFontFreeType.h"
8 #include "NativeFontResourceFreeType.h"
9 #include "ScaledFontFreeType.h"
10 #include "Logging.h"
11 #include "StackArray.h"
12 
13 #include FT_MULTIPLE_MASTERS_H
14 #include FT_TRUETYPE_TABLES_H
15 
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>
22 
23 namespace mozilla::gfx {
24 
GetFontFileData(FontFileDataOutput aDataCallback,void * aBaton)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;
31     }
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;
40     }
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;
47     }
48     aDataCallback(fontData, length, mIndex, aBaton);
49     munmap(fontData, length);
50     return true;
51   }
52 
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;
63     }
64     delete[] fontData;
65   }
66   return success;
67 }
68 
GetFontDescriptor(FontDescriptorOutput aCb,void * aBaton)69 bool UnscaledFontFreeType::GetFontDescriptor(FontDescriptorOutput aCb,
70                                              void* aBaton) {
71   if (mFile.empty()) {
72     return false;
73   }
74 
75   aCb(reinterpret_cast<const uint8_t*>(mFile.data()), mFile.size(), mIndex,
76       aBaton);
77   return true;
78 }
79 
InitFace()80 RefPtr<SharedFTFace> UnscaledFontFreeType::InitFace() {
81   if (mFace) {
82     return mFace;
83   }
84   if (mFile.empty()) {
85     return nullptr;
86   }
87   mFace = Factory::NewSharedFTFace(nullptr, mFile.c_str(), mIndex);
88   if (!mFace) {
89     gfxWarning() << "Failed initializing FreeType face from filename";
90     return nullptr;
91   }
92   return mFace;
93 }
94 
GetVariationSettingsFromFace(std::vector<FontVariation> * aVariations,FT_Face aFace)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;
99   }
100 
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");
119   }
120   if (!getVar || !getCoords) {
121     return;
122   }
123 #endif
124 
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;
134         }
135         aVariations->push_back(FontVariation{uint32_t(mmVar->axis[i].tag),
136                                              float(coords[i] / 65536.0)});
137       }
138       if (!changed) {
139         aVariations->clear();
140       }
141     }
142     if (doneVar) {
143       (*doneVar)(aFace->glyph->library, mmVar);
144     } else {
145       free(mmVar);
146     }
147   }
148 }
149 
ApplyVariationsToFace(const FontVariation * aVariations,uint32_t aNumVariations,FT_Face aFace)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;
154   }
155 
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");
167   }
168   if (!setCoords) {
169     return;
170   }
171 #endif
172 
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);
176   }
177   if ((*setCoords)(aFace, aNumVariations, coords.data()) != FT_Err_Ok) {
178     // ignore the problem?
179   }
180 }
181 
182 }  // namespace mozilla::gfx
183