1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fgas/font/cfgas_gefont.h"
8
9#include <memory>
10#include <utility>
11
12#include "core/fxcrt/fx_codepage.h"
13#include "core/fxge/cfx_font.h"
14#include "core/fxge/cfx_substfont.h"
15#include "core/fxge/cfx_unicodeencoding.h"
16#include "core/fxge/cfx_unicodeencodingex.h"
17#include "third_party/base/ptr_util.h"
18#include "xfa/fgas/font/fgas_fontutils.h"
19
20// static
21RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(const wchar_t* pszFontFamily,
22                                               uint32_t dwFontStyles,
23                                               uint16_t wCodePage,
24                                               CFGAS_FontMgr* pFontMgr) {
25#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
26  if (!pFontMgr)
27    return nullptr;
28
29  return pFontMgr->GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
30#else
31  auto pFont = pdfium::MakeRetain<CFGAS_GEFont>(pFontMgr);
32  if (!pFont->LoadFontInternal(pszFontFamily, dwFontStyles, wCodePage))
33    return nullptr;
34  return pFont;
35#endif
36}
37
38// static
39RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(CFX_Font* pExternalFont,
40                                               CFGAS_FontMgr* pFontMgr) {
41  auto pFont = pdfium::MakeRetain<CFGAS_GEFont>(pFontMgr);
42  if (!pFont->LoadFontInternal(pExternalFont))
43    return nullptr;
44  return pFont;
45}
46
47// static
48RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(
49    std::unique_ptr<CFX_Font> pInternalFont,
50    CFGAS_FontMgr* pFontMgr) {
51  auto pFont = pdfium::MakeRetain<CFGAS_GEFont>(pFontMgr);
52  if (!pFont->LoadFontInternal(std::move(pInternalFont)))
53    return nullptr;
54  return pFont;
55}
56
57CFGAS_GEFont::CFGAS_GEFont(CFGAS_FontMgr* pFontMgr)
58    :
59      m_bUseLogFontStyle(false),
60      m_dwLogFontStyle(0),
61      m_pFont(nullptr),
62      m_bExternalFont(false),
63      m_pFontMgr(pFontMgr) {
64}
65
66CFGAS_GEFont::~CFGAS_GEFont() {
67  if (!m_bExternalFont)
68    delete m_pFont;
69}
70
71#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
72bool CFGAS_GEFont::LoadFontInternal(const wchar_t* pszFontFamily,
73                                    uint32_t dwFontStyles,
74                                    uint16_t wCodePage) {
75  if (m_pFont)
76    return false;
77  ByteString csFontFamily;
78  if (pszFontFamily)
79    csFontFamily = ByteString::FromUnicode(pszFontFamily);
80
81  int32_t iWeight =
82      FontStyleIsBold(dwFontStyles) ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL;
83  m_pFont = new CFX_Font;
84  if (FontStyleIsItalic(dwFontStyles) && FontStyleIsBold(dwFontStyles))
85    csFontFamily += ",BoldItalic";
86  else if (FontStyleIsBold(dwFontStyles))
87    csFontFamily += ",Bold";
88  else if (FontStyleIsItalic(dwFontStyles))
89    csFontFamily += ",Italic";
90
91  m_pFont->LoadSubst(csFontFamily, true, dwFontStyles, iWeight, 0, wCodePage,
92                     false);
93  if (!m_pFont->GetFace())
94    return false;
95  return InitFont();
96}
97#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
98
99bool CFGAS_GEFont::LoadFontInternal(CFX_Font* pExternalFont) {
100  if (m_pFont || !pExternalFont)
101    return false;
102
103  m_pFont = pExternalFont;
104  m_bExternalFont = true;
105  return InitFont();
106}
107
108bool CFGAS_GEFont::LoadFontInternal(std::unique_ptr<CFX_Font> pInternalFont) {
109  if (m_pFont || !pInternalFont)
110    return false;
111
112  m_pFont = pInternalFont.release();
113  m_bExternalFont = false;
114  return InitFont();
115}
116
117bool CFGAS_GEFont::InitFont() {
118  if (!m_pFont)
119    return false;
120
121  if (m_pFontEncoding)
122    return true;
123
124  m_pFontEncoding = FX_CreateFontEncodingEx(m_pFont, FXFM_ENCODING_NONE);
125  return !!m_pFontEncoding;
126}
127
128WideString CFGAS_GEFont::GetFamilyName() const {
129  if (!m_pFont->GetSubstFont() ||
130      m_pFont->GetSubstFont()->m_Family.GetLength() == 0) {
131    return WideString::FromLocal(m_pFont->GetFamilyName().AsStringView());
132  }
133  return WideString::FromLocal(
134      m_pFont->GetSubstFont()->m_Family.AsStringView());
135}
136
137uint32_t CFGAS_GEFont::GetFontStyles() const {
138  ASSERT(m_pFont);
139  if (m_bUseLogFontStyle)
140    return m_dwLogFontStyle;
141
142  uint32_t dwStyles = 0;
143  auto* pSubstFont = m_pFont->GetSubstFont();
144  if (pSubstFont) {
145    if (pSubstFont->m_Weight == FXFONT_FW_BOLD)
146      dwStyles |= FXFONT_BOLD;
147    if (pSubstFont->m_bFlagItalic)
148      dwStyles |= FXFONT_ITALIC;
149  } else {
150    if (m_pFont->IsBold())
151      dwStyles |= FXFONT_BOLD;
152    if (m_pFont->IsItalic())
153      dwStyles |= FXFONT_ITALIC;
154  }
155  return dwStyles;
156}
157
158bool CFGAS_GEFont::GetCharWidth(wchar_t wUnicode, int32_t& iWidth) {
159  auto it = m_CharWidthMap.find(wUnicode);
160  iWidth = it != m_CharWidthMap.end() ? it->second : 0;
161  if (iWidth == 65535)
162    return false;
163
164  if (iWidth > 0)
165    return true;
166
167  if (!m_pProvider || !m_pProvider->GetCharWidth(RetainPtr<CFGAS_GEFont>(this),
168                                                 wUnicode, &iWidth)) {
169    RetainPtr<CFGAS_GEFont> pFont;
170    int32_t iGlyph;
171    std::tie(iGlyph, pFont) = GetGlyphIndexAndFont(wUnicode, true);
172    if (iGlyph != 0xFFFF && pFont) {
173      if (pFont.Get() == this) {
174        iWidth = m_pFont->GetGlyphWidth(iGlyph);
175        if (iWidth < 0)
176          iWidth = -1;
177      } else if (pFont->GetCharWidth(wUnicode, iWidth)) {
178        return true;
179      }
180    } else {
181      iWidth = -1;
182    }
183  }
184  m_CharWidthMap[wUnicode] = iWidth;
185  return iWidth > 0;
186}
187
188bool CFGAS_GEFont::GetCharBBox(wchar_t wUnicode, CFX_Rect* bbox) {
189  auto it = m_BBoxMap.find(wUnicode);
190  if (it != m_BBoxMap.end()) {
191    *bbox = it->second;
192    return true;
193  }
194
195  RetainPtr<CFGAS_GEFont> pFont;
196  int32_t iGlyph;
197  std::tie(iGlyph, pFont) = GetGlyphIndexAndFont(wUnicode, true);
198  if (!pFont || iGlyph == 0xFFFF)
199    return false;
200
201  if (pFont.Get() != this)
202    return pFont->GetCharBBox(wUnicode, bbox);
203
204  FX_RECT rtBBox;
205  if (!m_pFont->GetGlyphBBox(iGlyph, rtBBox))
206    return false;
207
208  CFX_Rect rt(rtBBox.left, rtBBox.top, rtBBox.Width(), rtBBox.Height());
209  m_BBoxMap[wUnicode] = rt;
210  *bbox = rt;
211  return true;
212}
213
214bool CFGAS_GEFont::GetBBox(CFX_Rect* bbox) {
215  FX_RECT rt(0, 0, 0, 0);
216  if (!m_pFont->GetBBox(rt))
217    return false;
218
219  bbox->left = rt.left;
220  bbox->width = rt.Width();
221  bbox->top = rt.bottom;
222  bbox->height = -rt.Height();
223  return true;
224}
225
226int32_t CFGAS_GEFont::GetGlyphIndex(wchar_t wUnicode) {
227  int32_t glyph;
228  RetainPtr<CFGAS_GEFont> font;
229  std::tie(glyph, font) = GetGlyphIndexAndFont(wUnicode, true);
230  return glyph;
231}
232
233std::pair<int32_t, RetainPtr<CFGAS_GEFont>> CFGAS_GEFont::GetGlyphIndexAndFont(
234    wchar_t wUnicode,
235    bool bRecursive) {
236  int32_t iGlyphIndex = m_pFontEncoding->GlyphFromCharCode(wUnicode);
237  if (iGlyphIndex > 0)
238    return {iGlyphIndex, RetainPtr<CFGAS_GEFont>(this)};
239
240  const FGAS_FONTUSB* pFontUSB = FGAS_GetUnicodeBitField(wUnicode);
241  if (!pFontUSB)
242    return {0xFFFF, nullptr};
243
244  uint16_t wBitField = pFontUSB->wBitField;
245  if (wBitField >= 128)
246    return {0xFFFF, nullptr};
247
248  auto it = m_FontMapper.find(wUnicode);
249  if (it != m_FontMapper.end() && it->second && it->second.Get() != this) {
250    RetainPtr<CFGAS_GEFont> font;
251    std::tie(iGlyphIndex, font) =
252        it->second->GetGlyphIndexAndFont(wUnicode, false);
253    if (iGlyphIndex != 0xFFFF) {
254      for (size_t i = 0; i < m_SubstFonts.size(); ++i) {
255        if (m_SubstFonts[i] == it->second)
256          return {(iGlyphIndex | ((i + 1) << 24)), it->second};
257      }
258    }
259  }
260  if (!m_pFontMgr || !bRecursive)
261    return {0xFFFF, nullptr};
262
263  WideString wsFamily = GetFamilyName();
264  RetainPtr<CFGAS_GEFont> pFont =
265      m_pFontMgr->GetFontByUnicode(wUnicode, GetFontStyles(), wsFamily.c_str());
266#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
267  if (!pFont)
268    pFont = m_pFontMgr->GetFontByUnicode(wUnicode, GetFontStyles(), nullptr);
269#endif
270  if (!pFont || pFont.Get() == this)  // Avoids direct cycles below.
271    return {0xFFFF, nullptr};
272
273  m_FontMapper[wUnicode] = pFont;
274  m_SubstFonts.push_back(pFont);
275
276  RetainPtr<CFGAS_GEFont> font;
277  std::tie(iGlyphIndex, font) = pFont->GetGlyphIndexAndFont(wUnicode, false);
278  if (iGlyphIndex == 0xFFFF)
279    return {0xFFFF, nullptr};
280
281  return {(iGlyphIndex | (m_SubstFonts.size() << 24)), pFont};
282}
283
284int32_t CFGAS_GEFont::GetAscent() const {
285  return m_pFont->GetAscent();
286}
287
288int32_t CFGAS_GEFont::GetDescent() const {
289  return m_pFont->GetDescent();
290}
291
292RetainPtr<CFGAS_GEFont> CFGAS_GEFont::GetSubstFont(int32_t iGlyphIndex) {
293  iGlyphIndex = static_cast<uint32_t>(iGlyphIndex) >> 24;
294  if (iGlyphIndex == 0)
295    return RetainPtr<CFGAS_GEFont>(this);
296  return m_SubstFonts[iGlyphIndex - 1];
297}
298