gfx/2d/UnscaledFontFreeType.cpp
author pyup-bot <github-bot@pyup.io>
Wed, 06 Mar 2019 16:53:25 +0000
changeset 522589 0b9ff65fb560cbf087eaa9b23e3377db31772f0d
parent 505383 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1531372 [wpt PR 15543] - Update mozrunner to 7.4.0, a=testonly Automatic update from web-platform-tests Update mozrunner from 7.3.0 to 7.4.0 -- wpt-commits: 0f1c6e9b1f63e523eb241e8c0eba1cdc764fd180 wpt-pr: 15543

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "UnscaledFontFreeType.h"
#include "NativeFontResourceFreeType.h"
#include "ScaledFontFreeType.h"
#include "Logging.h"
#include "StackArray.h"

#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H

#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

namespace mozilla {
namespace gfx {

bool UnscaledFontFreeType::GetFontFileData(FontFileDataOutput aDataCallback,
                                           void* aBaton) {
  if (!mFile.empty()) {
    int fd = open(mFile.c_str(), O_RDONLY);
    if (fd < 0) {
      return false;
    }
    struct stat buf;
    if (fstat(fd, &buf) < 0 ||
        // Don't erroneously read directories as files.
        !S_ISREG(buf.st_mode) ||
        // Verify the file size fits in a uint32_t.
        buf.st_size <= 0 || off_t(uint32_t(buf.st_size)) != buf.st_size) {
      close(fd);
      return false;
    }
    uint32_t length = buf.st_size;
    uint8_t* fontData = reinterpret_cast<uint8_t*>(
        mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0));
    close(fd);
    if (fontData == MAP_FAILED) {
      return false;
    }
    aDataCallback(fontData, length, mIndex, aBaton);
    munmap(fontData, length);
    return true;
  }

  bool success = false;
  FT_ULong length = 0;
  // Request the SFNT file. This may not always succeed for all font types.
  if (FT_Load_Sfnt_Table(mFace, 0, 0, nullptr, &length) == FT_Err_Ok) {
    uint8_t* fontData = new uint8_t[length];
    if (FT_Load_Sfnt_Table(mFace, 0, 0, fontData, &length) == FT_Err_Ok) {
      aDataCallback(fontData, length, 0, aBaton);
      success = true;
    }
    delete[] fontData;
  }
  return success;
}

bool UnscaledFontFreeType::GetFontDescriptor(FontDescriptorOutput aCb,
                                             void* aBaton) {
  if (mFile.empty()) {
    return false;
  }

  aCb(reinterpret_cast<const uint8_t*>(mFile.data()), mFile.size(), mIndex,
      aBaton);
  return true;
}

bool UnscaledFontFreeType::GetWRFontDescriptor(WRFontDescriptorOutput aCb,
                                               void* aBaton) {
  if (mFile.empty()) {
    return false;
  }

  aCb(reinterpret_cast<const uint8_t*>(mFile.data()), mFile.size(), mIndex,
      aBaton);
  return true;
}

void UnscaledFontFreeType::GetVariationSettingsFromFace(
    std::vector<FontVariation>* aVariations, FT_Face aFace) {
  if (!aFace || !(aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
    return;
  }

  typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
  typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
  typedef FT_Error (*GetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
#if MOZ_TREE_FREETYPE
  GetVarFunc getVar = &FT_Get_MM_Var;
  DoneVarFunc doneVar = &FT_Done_MM_Var;
  GetVarDesignCoordsFunc getCoords = &FT_Get_Var_Design_Coordinates;
#else
  static GetVarFunc getVar;
  static DoneVarFunc doneVar;
  static GetVarDesignCoordsFunc getCoords;
  static bool firstTime = true;
  if (firstTime) {
    firstTime = false;
    getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
    doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
    getCoords = (GetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT,
                                              "FT_Get_Var_Design_Coordinates");
  }
  if (!getVar || !getCoords) {
    return;
  }
#endif

  FT_MM_Var* mmVar = nullptr;
  if ((*getVar)(aFace, &mmVar) == FT_Err_Ok) {
    aVariations->reserve(mmVar->num_axis);
    StackArray<FT_Fixed, 32> coords(mmVar->num_axis);
    if ((*getCoords)(aFace, mmVar->num_axis, coords.data()) == FT_Err_Ok) {
      bool changed = false;
      for (uint32_t i = 0; i < mmVar->num_axis; i++) {
        if (coords[i] != mmVar->axis[i].def) {
          changed = true;
        }
        aVariations->push_back(FontVariation{uint32_t(mmVar->axis[i].tag),
                                             float(coords[i] / 65536.0)});
      }
      if (!changed) {
        aVariations->clear();
      }
    }
    if (doneVar) {
      (*doneVar)(aFace->glyph->library, mmVar);
    } else {
      free(mmVar);
    }
  }
}

void UnscaledFontFreeType::ApplyVariationsToFace(
    const FontVariation* aVariations, uint32_t aNumVariations, FT_Face aFace) {
  if (!aFace || !(aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
    return;
  }

  typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
#ifdef MOZ_TREE_FREETYPE
  SetVarDesignCoordsFunc setCoords = &FT_Set_Var_Design_Coordinates;
#else
  typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
  static SetVarDesignCoordsFunc setCoords;
  static bool firstTime = true;
  if (firstTime) {
    firstTime = false;
    setCoords = (SetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT,
                                              "FT_Set_Var_Design_Coordinates");
  }
  if (!setCoords) {
    return;
  }
#endif

  StackArray<FT_Fixed, 32> coords(aNumVariations);
  for (uint32_t i = 0; i < aNumVariations; i++) {
    coords[i] = std::round(aVariations[i].mValue * 65536.0f);
  }
  if ((*setCoords)(aFace, aNumVariations, coords.data()) != FT_Err_Ok) {
    // ignore the problem?
  }
}

}  // namespace gfx
}  // namespace mozilla