tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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