• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "core/fxge/fx_font.h"
6 
7 #include <stdint.h>
8 
9 #include <algorithm>
10 
11 #include "core/fxcrt/byteorder.h"
12 #include "core/fxcrt/fx_safe_types.h"
13 #include "core/fxcrt/numerics/safe_conversions.h"
14 #include "core/fxcrt/widestring.h"
15 #include "core/fxge/cfx_glyphbitmap.h"
16 #include "core/fxge/dib/cfx_dibitmap.h"
17 #include "core/fxge/freetype/fx_freetype.h"
18 #include "core/fxge/text_glyph_pos.h"
19 
20 namespace {
21 
22 // These numbers come from the OpenType name table specification.
23 constexpr uint16_t kNameMacEncodingRoman = 0;
24 constexpr uint16_t kNameWindowsEncodingUnicode = 1;
25 
GetStringFromTable(pdfium::span<const uint8_t> string_span,uint16_t offset,uint16_t length)26 ByteString GetStringFromTable(pdfium::span<const uint8_t> string_span,
27                               uint16_t offset,
28                               uint16_t length) {
29   if (string_span.size() < static_cast<uint32_t>(offset + length))
30     return ByteString();
31 
32   return ByteString(ByteStringView(string_span.subspan(offset, length)));
33 }
34 
35 }  // namespace
36 
GetGlyphsBBox(const std::vector<TextGlyphPos> & glyphs,int anti_alias)37 FX_RECT GetGlyphsBBox(const std::vector<TextGlyphPos>& glyphs, int anti_alias) {
38   FX_RECT rect;
39   bool bStarted = false;
40   for (const TextGlyphPos& glyph : glyphs) {
41     if (!glyph.m_pGlyph)
42       continue;
43 
44     std::optional<CFX_Point> point = glyph.GetOrigin({0, 0});
45     if (!point.has_value())
46       continue;
47 
48     int char_width = glyph.m_pGlyph->GetBitmap()->GetWidth();
49     if (anti_alias == FT_RENDER_MODE_LCD)
50       char_width /= 3;
51 
52     FX_SAFE_INT32 char_right = point.value().x;
53     char_right += char_width;
54     if (!char_right.IsValid())
55       continue;
56 
57     FX_SAFE_INT32 char_bottom = point.value().y;
58     char_bottom += glyph.m_pGlyph->GetBitmap()->GetHeight();
59     if (!char_bottom.IsValid())
60       continue;
61 
62     if (bStarted) {
63       rect.left = std::min(rect.left, point.value().x);
64       rect.top = std::min(rect.top, point.value().y);
65       rect.right = pdfium::ValueOrDieForType<int32_t>(
66           pdfium::CheckMax(rect.right, char_right));
67       rect.bottom = pdfium::ValueOrDieForType<int32_t>(
68           pdfium::CheckMax(rect.bottom, char_bottom));
69       continue;
70     }
71 
72     rect.left = point.value().x;
73     rect.top = point.value().y;
74     rect.right = char_right.ValueOrDie();
75     rect.bottom = char_bottom.ValueOrDie();
76     bStarted = true;
77   }
78   return rect;
79 }
80 
GetNameFromTT(pdfium::span<const uint8_t> name_table,uint32_t name_id)81 ByteString GetNameFromTT(pdfium::span<const uint8_t> name_table,
82                          uint32_t name_id) {
83   if (name_table.size() < 6)
84     return ByteString();
85 
86   uint32_t name_count = fxcrt::GetUInt16MSBFirst(name_table.subspan(2));
87   uint32_t string_offset = fxcrt::GetUInt16MSBFirst(name_table.subspan(4));
88   // We will ignore the possibility of overlap of structures and
89   // string table as if it's all corrupt there's not a lot we can do.
90   if (name_table.size() < string_offset)
91     return ByteString();
92 
93   pdfium::span<const uint8_t> string_span = name_table.subspan(string_offset);
94   name_table = name_table.subspan(6);
95   if (name_table.size() < name_count * 12)
96     return ByteString();
97 
98   for (uint32_t i = 0; i < name_count;
99        i++, name_table = name_table.subspan(12)) {
100     if (fxcrt::GetUInt16MSBFirst(name_table.subspan(6)) == name_id) {
101       const uint16_t platform_identifier = fxcrt::GetUInt16MSBFirst(name_table);
102       const uint16_t platform_encoding =
103           fxcrt::GetUInt16MSBFirst(name_table.subspan(2));
104 
105       if (platform_identifier == kNamePlatformMac &&
106           platform_encoding == kNameMacEncodingRoman) {
107         return GetStringFromTable(
108             string_span, fxcrt::GetUInt16MSBFirst(name_table.subspan(10)),
109             fxcrt::GetUInt16MSBFirst(name_table.subspan(8)));
110       }
111       if (platform_identifier == kNamePlatformWindows &&
112           platform_encoding == kNameWindowsEncodingUnicode) {
113         // This name is always UTF16-BE and we have to convert it to UTF8.
114         ByteString utf16_be = GetStringFromTable(
115             string_span, fxcrt::GetUInt16MSBFirst(name_table.subspan(10)),
116             fxcrt::GetUInt16MSBFirst(name_table.subspan(8)));
117         if (utf16_be.IsEmpty() || utf16_be.GetLength() % 2 != 0) {
118           return ByteString();
119         }
120 
121         return WideString::FromUTF16BE(utf16_be.unsigned_span()).ToUTF8();
122       }
123     }
124   }
125   return ByteString();
126 }
127 
GetTTCIndex(pdfium::span<const uint8_t> pFontData,size_t font_offset)128 size_t GetTTCIndex(pdfium::span<const uint8_t> pFontData, size_t font_offset) {
129   pdfium::span<const uint8_t> p = pFontData.subspan(8);
130   size_t nfont = fxcrt::GetUInt32MSBFirst(p);
131   for (size_t index = 0; index < nfont; index++) {
132     p = pFontData.subspan(12 + index * 4);
133     if (fxcrt::GetUInt32MSBFirst(p) == font_offset) {
134       return index;
135     }
136   }
137   return 0;
138 }
139 
UnicodeFromAdobeName(const char * name)140 wchar_t UnicodeFromAdobeName(const char* name) {
141   return (wchar_t)(FXFT_unicode_from_adobe_name(name) & 0x7FFFFFFF);
142 }
143 
AdobeNameFromUnicode(wchar_t unicode)144 ByteString AdobeNameFromUnicode(wchar_t unicode) {
145   char glyph_name[64];
146   FXFT_adobe_name_from_unicode(glyph_name, unicode);
147   return ByteString(glyph_name);
148 }
149 
NormalizeFontMetric(int64_t value,uint16_t upem)150 int NormalizeFontMetric(int64_t value, uint16_t upem) {
151   if (upem == 0) {
152     return pdfium::saturated_cast<int>(value);
153   }
154 
155   const double scaled_value = (value * 1000.0 + upem / 2) / upem;
156   return pdfium::saturated_cast<int>(scaled_value);
157 }
158