chromium/third_party/pdfium/xfa/fgas/font/cfgas_fontmgr.cpp

// Copyright 2015 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fgas/font/cfgas_fontmgr.h"

#include <stdint.h>

#include <algorithm>
#include <array>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>

#include "build/build_config.h"
#include "core/fxcrt/byteorder.h"
#include "core/fxcrt/cfx_read_only_vector_stream.h"
#include "core/fxcrt/check.h"
#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/containers/contains.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fixed_size_data_vector.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/fx_memcpy_wrappers.h"
#include "core/fxcrt/fx_system.h"
#include "core/fxcrt/numerics/safe_conversions.h"
#include "core/fxcrt/span.h"
#include "core/fxcrt/stl_util.h"
#include "core/fxge/cfx_font.h"
#include "core/fxge/cfx_fontmapper.h"
#include "core/fxge/cfx_fontmgr.h"
#include "core/fxge/cfx_gemodule.h"
#include "core/fxge/fx_font.h"
#include "core/fxge/fx_fontencoding.h"
#include "xfa/fgas/font/cfgas_gefont.h"
#include "xfa/fgas/font/fgas_fontutils.h"

#if BUILDFLAG(IS_WIN)
#include "core/fxcrt/win/win_util.h"
#endif

namespace {

bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode) {}

uint32_t ShortFormHash(FX_CodePage wCodePage,
                       uint32_t dwFontStyles,
                       WideStringView wsFontFamily) {}

uint32_t LongFormHash(FX_CodePage wCodePage,
                      uint16_t wBitField,
                      uint32_t dwFontStyles,
                      WideStringView wsFontFamily) {}

}  // namespace

#if BUILDFLAG(IS_WIN)

namespace {

struct FX_FONTMATCHPARAMS {
  const wchar_t* pwsFamily;
  uint32_t dwFontStyles;
  uint32_t dwUSB;
  bool matchParagraphStyle;
  wchar_t wUnicode;
  FX_CodePage wCodePage;
};

int32_t GetSimilarityScore(FX_FONTDESCRIPTOR const* pFont,
                           uint32_t dwFontStyles) {
  int32_t iValue = 0;
  if (FontStyleIsSymbolic(dwFontStyles) ==
      FontStyleIsSymbolic(pFont->dwFontStyles)) {
    iValue += 64;
  }
  if (FontStyleIsFixedPitch(dwFontStyles) ==
      FontStyleIsFixedPitch(pFont->dwFontStyles)) {
    iValue += 32;
  }
  if (FontStyleIsSerif(dwFontStyles) == FontStyleIsSerif(pFont->dwFontStyles))
    iValue += 16;
  if (FontStyleIsScript(dwFontStyles) == FontStyleIsScript(pFont->dwFontStyles))
    iValue += 8;
  return iValue;
}

const FX_FONTDESCRIPTOR* MatchDefaultFont(
    FX_FONTMATCHPARAMS* pParams,
    const std::deque<FX_FONTDESCRIPTOR>& fonts) {
  const FX_FONTDESCRIPTOR* pBestFont = nullptr;
  int32_t iBestSimilar = 0;
  for (const auto& font : fonts) {
    if (FontStyleIsForceBold(font.dwFontStyles) &&
        FontStyleIsItalic(font.dwFontStyles)) {
      continue;
    }

    if (pParams->pwsFamily) {
      if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace))
        continue;
      if (font.uCharSet == FX_Charset::kSymbol)
        return &font;
    }
    if (font.uCharSet == FX_Charset::kSymbol)
      continue;
    if (pParams->wCodePage != FX_CodePage::kFailure) {
      if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
        continue;
    } else {
      if (pParams->dwUSB < 128) {
        uint32_t dwByte = pParams->dwUSB / 32;
        uint32_t dwUSB = 1 << (pParams->dwUSB % 32);
        if ((font.FontSignature.fsUsb[dwByte] & dwUSB) == 0)
          continue;
      }
    }
    if (pParams->matchParagraphStyle) {
      if ((font.dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
        return &font;
      continue;
    }
    if (pParams->pwsFamily) {
      if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace) == 0)
        return &font;
    }
    int32_t iSimilarValue = GetSimilarityScore(&font, pParams->dwFontStyles);
    if (iBestSimilar < iSimilarValue) {
      iBestSimilar = iSimilarValue;
      pBestFont = &font;
    }
  }
  return iBestSimilar < 1 ? nullptr : pBestFont;
}

uint32_t GetGdiFontStyles(const LOGFONTW& lf) {
  uint32_t dwStyles = 0;
  if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH)
    dwStyles |= FXFONT_FIXED_PITCH;
  uint8_t nFamilies = lf.lfPitchAndFamily & 0xF0;
  if (nFamilies == FF_ROMAN)
    dwStyles |= FXFONT_SERIF;
  if (nFamilies == FF_SCRIPT)
    dwStyles |= FXFONT_SCRIPT;
  if (lf.lfCharSet == SYMBOL_CHARSET)
    dwStyles |= FXFONT_SYMBOLIC;
  return dwStyles;
}

int32_t CALLBACK GdiFontEnumProc(ENUMLOGFONTEX* lpelfe,
                                 NEWTEXTMETRICEX* lpntme,
                                 DWORD dwFontType,
                                 LPARAM lParam) {
  if (dwFontType != TRUETYPE_FONTTYPE)
    return 1;
  const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
  if (lf.lfFaceName[0] == L'@')
    return 1;
  FX_FONTDESCRIPTOR font = {};  // Aggregate initialization.
  static_assert(std::is_aggregate_v<decltype(font)>);
  font.uCharSet = FX_GetCharsetFromInt(lf.lfCharSet);
  font.dwFontStyles = GetGdiFontStyles(lf);
  UNSAFE_TODO({
    FXSYS_wcsncpy(font.wsFontFace, (const wchar_t*)lf.lfFaceName, 31);
    font.wsFontFace[31] = 0;
    FXSYS_memcpy(&font.FontSignature, &lpntme->ntmFontSig,
                 sizeof(lpntme->ntmFontSig));
  });
  reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(font);
  return 1;
}

std::deque<FX_FONTDESCRIPTOR> EnumGdiFonts(const wchar_t* pwsFaceName,
                                           wchar_t wUnicode) {
  std::deque<FX_FONTDESCRIPTOR> fonts;
  if (!pdfium::IsUser32AndGdi32Available()) {
    // Without GDI32 and User32, GetDC / EnumFontFamiliesExW / ReleaseDC all
    // fail.
    return fonts;
  }

  LOGFONTW lfFind = {};  // Aggregate initialization.
  static_assert(std::is_aggregate_v<decltype(lfFind)>);
  lfFind.lfCharSet = DEFAULT_CHARSET;
  if (pwsFaceName) {
    UNSAFE_TODO({
      FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
      lfFind.lfFaceName[31] = 0;
    });
  }
  HDC hDC = ::GetDC(nullptr);
  EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind, (FONTENUMPROCW)GdiFontEnumProc,
                      (LPARAM)&fonts, 0);
  ::ReleaseDC(nullptr, hDC);
  return fonts;
}

}  // namespace

CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(nullptr, 0xFEFF)) {}

CFGAS_FontMgr::~CFGAS_FontMgr() = default;

bool CFGAS_FontMgr::EnumFonts() {
  return true;
}

RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
    wchar_t wUnicode,
    uint32_t dwFontStyles,
    const wchar_t* pszFontFamily,
    uint32_t dwHash,
    FX_CodePage wCodePage,
    uint16_t wBitField) {
  const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles, false,
                                          wCodePage, wBitField, wUnicode);
  if (!pFD && pszFontFamily) {
    pFD =
        FindFont(nullptr, dwFontStyles, false, wCodePage, wBitField, wUnicode);
  }
  if (!pFD)
    return nullptr;

  FX_CodePage newCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
  RetainPtr<CFGAS_GEFont> pFont =
      CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, newCodePage);
  if (!pFont)
    return nullptr;

  pFont->SetLogicalFontStyle(dwFontStyles);
  if (!VerifyUnicode(pFont, wUnicode)) {
    m_FailedUnicodesSet.insert(wUnicode);
    return nullptr;
  }

  m_Hash2Fonts[dwHash].push_back(pFont);
  return pFont;
}

const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(const wchar_t* pszFontFamily,
                                                 uint32_t dwFontStyles,
                                                 bool matchParagraphStyle,
                                                 FX_CodePage wCodePage,
                                                 uint32_t dwUSB,
                                                 wchar_t wUnicode) {
  FX_FONTMATCHPARAMS params = {};  // Aggregate initialization.
  static_assert(std::is_aggregate_v<decltype(params)>);
  params.dwUSB = dwUSB;
  params.wUnicode = wUnicode;
  params.wCodePage = wCodePage;
  params.pwsFamily = pszFontFamily;
  params.dwFontStyles = dwFontStyles;
  params.matchParagraphStyle = matchParagraphStyle;

  const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(&params, m_FontFaces);
  if (pDesc)
    return pDesc;

  if (!pszFontFamily)
    return nullptr;

  // Use a named object to store the returned value of EnumGdiFonts() instead
  // of using a temporary object. This can prevent use-after-free issues since
  // pDesc may point to one of std::deque object's elements.
  std::deque<FX_FONTDESCRIPTOR> namedFonts =
      EnumGdiFonts(pszFontFamily, wUnicode);
  params.pwsFamily = nullptr;
  pDesc = MatchDefaultFont(&params, namedFonts);
  if (!pDesc)
    return nullptr;

  auto it = std::find(m_FontFaces.rbegin(), m_FontFaces.rend(), *pDesc);
  if (it != m_FontFaces.rend())
    return &*it;

  m_FontFaces.push_back(*pDesc);
  return &m_FontFaces.back();
}

#else  // BUILDFLAG(IS_WIN)

namespace {

constexpr auto kCodePages =;

uint16_t FX_GetCodePageBit(FX_CodePage wCodePage) {}

uint16_t FX_GetUnicodeBit(wchar_t wcUnicode) {}

uint16_t ReadUInt16FromSpanAtOffset(pdfium::span<const uint8_t> data,
                                    size_t offset) {}

extern "C" {

unsigned long ftStreamRead(FXFT_StreamRec* stream,
                           unsigned long offset,
                           unsigned char* buffer,
                           unsigned long count) {}

void ftStreamClose(FXFT_StreamRec* stream) {}

}  // extern "C"

std::vector<WideString> GetNames(pdfium::span<const uint8_t> name_table) {}

uint32_t GetFlags(const RetainPtr<CFX_Face>& face) {}

RetainPtr<IFX_SeekableReadStream> CreateFontStream(CFX_FontMapper* pFontMapper,
                                                   size_t index) {}

RetainPtr<IFX_SeekableReadStream> CreateFontStream(
    const ByteString& bsFaceName) {}

RetainPtr<CFX_Face> LoadFace(
    const RetainPtr<IFX_SeekableReadStream>& pFontStream,
    int32_t iFaceIndex) {}

bool VerifyUnicodeForFontDescriptor(CFGAS_FontDescriptor* pDesc,
                                    wchar_t wcUnicode) {}

bool IsPartName(const WideString& name1, const WideString& name2) {}

int32_t CalcPenalty(CFGAS_FontDescriptor* pInstalled,
                    FX_CodePage wCodePage,
                    uint32_t dwFontStyles,
                    const WideString& FontName,
                    wchar_t wcUnicode) {}

}  // namespace

CFGAS_FontDescriptor::CFGAS_FontDescriptor() = default;

CFGAS_FontDescriptor::~CFGAS_FontDescriptor() = default;

CFGAS_FontMgr::CFGAS_FontMgr() = default;

CFGAS_FontMgr::~CFGAS_FontMgr() = default;

bool CFGAS_FontMgr::EnumFontsFromFontMapper() {}

bool CFGAS_FontMgr::EnumFonts() {}

RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
    wchar_t wUnicode,
    uint32_t dwFontStyles,
    const wchar_t* pszFontFamily,
    uint32_t dwHash,
    FX_CodePage wCodePage,
    uint16_t /* wBitField*/) {}

RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFontInternal(
    const WideString& wsFaceName,
    int32_t iFaceIndex) {}

std::vector<CFGAS_FontDescriptorInfo> CFGAS_FontMgr::MatchFonts(
    FX_CodePage wCodePage,
    uint32_t dwFontStyles,
    const WideString& FontName,
    wchar_t wcUnicode) {}

void CFGAS_FontMgr::RegisterFace(RetainPtr<CFX_Face> pFace,
                                 const WideString& wsFaceName) {}

void CFGAS_FontMgr::RegisterFaces(
    const RetainPtr<IFX_SeekableReadStream>& pFontStream,
    const WideString& wsFaceName) {}

#endif  // BUILDFLAG(IS_WIN)

RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
    FX_CodePage wCodePage,
    uint32_t dwFontStyles,
    const wchar_t* pszFontFamily) {}

RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicode(
    wchar_t wUnicode,
    uint32_t dwFontStyles,
    const wchar_t* pszFontFamily) {}

RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
                                                uint32_t dwFontStyles,
                                                FX_CodePage wCodePage) {}