UnscaledFontFreeType.cpp (7858B)
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 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 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 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 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 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 #ifdef MOZ_WIDGET_ANDROID 183 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; 191 } 192 const ScaledFontFreeType::InstanceData& instanceData = 193 *reinterpret_cast<const ScaledFontFreeType::InstanceData*>(aInstanceData); 194 195 RefPtr<SharedFTFace> face(InitFace()); 196 if (!face) { 197 gfxWarning() << "Attempted to deserialize FreeType scaled font without " 198 "FreeType face"; 199 return nullptr; 200 } 201 202 if (aNumVariations > 0 && face->GetData()) { 203 if (RefPtr<SharedFTFace> varFace = face->GetData()->CloneFace()) { 204 face = varFace; 205 } 206 } 207 208 // Only apply variations if we have an explicitly cloned face. 209 if (aNumVariations > 0 && face != GetFace()) { 210 ApplyVariationsToFace(aVariations, aNumVariations, face->GetFace()); 211 } 212 213 RefPtr<ScaledFontFreeType> scaledFont = new ScaledFontFreeType( 214 std::move(face), this, aGlyphSize, instanceData.mApplySyntheticBold); 215 216 return scaledFont.forget(); 217 } 218 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); 226 } 227 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; 233 } 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(); 238 } 239 240 #endif // MOZ_WIDGET_ANDROID 241 242 } // namespace mozilla::gfx