• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/cfx_fontmapper.h"
6 
7 #include <memory>
8 #include <numeric>
9 #include <utility>
10 
11 #include "core/fxcrt/fx_codepage.h"
12 #include "core/fxge/cfx_gemodule.h"
13 #include "core/fxge/systemfontinfo_iface.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 using testing::_;
18 using testing::DoAll;
19 using testing::ElementsAre;
20 using testing::InSequence;
21 using testing::Invoke;
22 using testing::Return;
23 using testing::WithArg;
24 
25 class MockSystemFontInfo : public SystemFontInfoIface {
26  public:
27   MockSystemFontInfo() = default;
28   ~MockSystemFontInfo() override = default;
29 
30   // SystemFontInfoIface:
31   MOCK_METHOD(bool, EnumFontList, (CFX_FontMapper*), (override));
32   MOCK_METHOD(void*,
33               MapFont,
34               (int, bool, FX_Charset, int, const ByteString&),
35               (override));
36   MOCK_METHOD(void*, GetFont, (const ByteString&), (override));
37   MOCK_METHOD(size_t,
38               GetFontData,
39               (void*, uint32_t, pdfium::span<uint8_t>),
40               (override));
41   MOCK_METHOD(bool, GetFaceName, (void*, ByteString*), (override));
42   MOCK_METHOD(bool, GetFontCharset, (void*, FX_Charset*), (override));
43   MOCK_METHOD(void, DeleteFont, (void*), (override));
44 };
45 
46 // Class that exposes private CFX_FontMapper methods.
47 class TestFontMapper : public CFX_FontMapper {
48  public:
TestFontMapper()49   TestFontMapper() : CFX_FontMapper(CFX_GEModule::Get()->GetFontMgr()) {}
50 
GetCachedTTCFace(void * font_handle,size_t ttc_size,size_t data_size)51   RetainPtr<CFX_Face> GetCachedTTCFace(void* font_handle,
52                                        size_t ttc_size,
53                                        size_t data_size) {
54     return CFX_FontMapper::GetCachedTTCFace(font_handle, ttc_size, data_size);
55   }
56 
GetCachedFace(void * font_handle,ByteString subst_name,int weight,bool is_italic,size_t data_size)57   RetainPtr<CFX_Face> GetCachedFace(void* font_handle,
58                                     ByteString subst_name,
59                                     int weight,
60                                     bool is_italic,
61                                     size_t data_size) {
62     return CFX_FontMapper::GetCachedFace(font_handle, subst_name, weight,
63                                          is_italic, data_size);
64   }
65 };
66 
67 class CFXFontMapperSystemFontInfoTest : public testing::Test {
68  protected:
69   CFXFontMapperSystemFontInfoTest() = default;
70   ~CFXFontMapperSystemFontInfoTest() override = default;
71 
SetUp()72   void SetUp() override {
73     font_mapper_ = std::make_unique<TestFontMapper>();
74     auto system_font_info = std::make_unique<MockSystemFontInfo>();
75     system_font_info_ = system_font_info.get();
76     font_mapper_->SetSystemFontInfo(std::move(system_font_info));
77     font_mapper_->AddInstalledFont("dummy", FX_Charset::kANSI);
78   }
79 
font_mapper()80   TestFontMapper& font_mapper() { return *font_mapper_; }
system_font_info()81   MockSystemFontInfo& system_font_info() { return *system_font_info_; }
82 
83  private:
84   // Must outlive `system_font_info_`.
85   std::unique_ptr<TestFontMapper> font_mapper_;
86   UnownedPtr<MockSystemFontInfo> system_font_info_;
87 };
88 
89 // Deliberately give this global variable external linkage.
90 char g_maybe_changes = '\xff';
91 
TEST(CFXFontMapperTest,IsStandardFontName)92 TEST(CFXFontMapperTest, IsStandardFontName) {
93   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Courier"));
94   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Courier-Bold"));
95   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Courier-BoldOblique"));
96   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Courier-Oblique"));
97   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Helvetica"));
98   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Helvetica-Bold"));
99   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Helvetica-BoldOblique"));
100   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Helvetica-Oblique"));
101   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Times-Roman"));
102   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Times-Bold"));
103   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Times-BoldItalic"));
104   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Times-Italic"));
105   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("Symbol"));
106   EXPECT_TRUE(CFX_FontMapper::IsStandardFontName("ZapfDingbats"));
107 
108   EXPECT_FALSE(CFX_FontMapper::IsStandardFontName("Courie"));
109   EXPECT_FALSE(CFX_FontMapper::IsStandardFontName("Courier-"));
110   EXPECT_FALSE(CFX_FontMapper::IsStandardFontName("Helvetica+Bold"));
111   EXPECT_FALSE(CFX_FontMapper::IsStandardFontName("YapfDingbats"));
112 }
113 
TEST(CFXFontMapperTest,MakeTag)114 TEST(CFXFontMapperTest, MakeTag) {
115   EXPECT_EQ(0x61626364u, CFX_FontMapper::MakeTag('a', 'b', 'c', 'd'));
116   EXPECT_EQ(0x00000000u, CFX_FontMapper::MakeTag('\0', '\0', '\0', '\0'));
117   EXPECT_EQ(0xfffe0a08u, CFX_FontMapper::MakeTag('\xff', '\xfe', '\n', '\b'));
118   EXPECT_EQ(0xffffffffu,
119             CFX_FontMapper::MakeTag('\xff', '\xff', '\xff', '\xff'));
120   EXPECT_EQ(0xffffffffu,
121             CFX_FontMapper::MakeTag(g_maybe_changes, '\xff', '\xff', '\xff'));
122   EXPECT_EQ(0x6e616d65u, CFX_FontMapper::MakeTag('n', 'a', 'm', 'e'));
123   EXPECT_EQ(0x4f532f32u, CFX_FontMapper::MakeTag('O', 'S', '/', '2'));
124   EXPECT_EQ(FT_MAKE_TAG('G', 'S', 'U', 'B'),
125             CFX_FontMapper::MakeTag('G', 'S', 'U', 'B'));
126 }
127 
TEST(CFXFontMapperTest,AddInstalledFontBasic)128 TEST(CFXFontMapperTest, AddInstalledFontBasic) {
129   const char kFontName[] = "dummy";
130   CFX_FontMapper font_mapper(nullptr);
131   font_mapper.SetSystemFontInfo(std::make_unique<MockSystemFontInfo>());
132 
133   font_mapper.AddInstalledFont(kFontName, FX_Charset::kANSI);
134   EXPECT_EQ(1u, font_mapper.GetFaceSize());
135   EXPECT_EQ(kFontName, font_mapper.GetFaceName(0));
136 }
137 
138 #ifdef PDF_ENABLE_XFA
TEST_F(CFXFontMapperSystemFontInfoTest,RawBytesForIndex)139 TEST_F(CFXFontMapperSystemFontInfoTest, RawBytesForIndex) {
140   {
141     void* const kFontHandle = reinterpret_cast<void*>(12345);
142 
143     InSequence s;
144     EXPECT_CALL(system_font_info(), MapFont).WillOnce(Return(kFontHandle));
145     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, 0, _))
146         .WillOnce(Return(2));
147     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, 0, _))
148         .WillOnce(DoAll(WithArg<2>(Invoke([](pdfium::span<uint8_t> buffer) {
149                           buffer[0] = '0';
150                           buffer[1] = '1';
151                         })),
152                         Return(2)));
153     EXPECT_CALL(system_font_info(), DeleteFont(kFontHandle));
154   }
155 
156   FixedSizeDataVector<uint8_t> data = font_mapper().RawBytesForIndex(0);
157   EXPECT_THAT(data.span(), ElementsAre('0', '1'));
158 }
159 
TEST_F(CFXFontMapperSystemFontInfoTest,RawBytesForIndexFailToMap)160 TEST_F(CFXFontMapperSystemFontInfoTest, RawBytesForIndexFailToMap) {
161   EXPECT_CALL(system_font_info(), MapFont).WillOnce(Return(nullptr));
162 
163   FixedSizeDataVector<uint8_t> data = font_mapper().RawBytesForIndex(0);
164   EXPECT_TRUE(data.empty());
165 }
166 
TEST_F(CFXFontMapperSystemFontInfoTest,RawBytesForIndexFailToGetDataSize)167 TEST_F(CFXFontMapperSystemFontInfoTest, RawBytesForIndexFailToGetDataSize) {
168   {
169     void* const kFontHandle = reinterpret_cast<void*>(12345);
170 
171     InSequence s;
172     EXPECT_CALL(system_font_info(), MapFont).WillOnce(Return(kFontHandle));
173     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, 0, _))
174         .WillOnce(Return(0));
175     EXPECT_CALL(system_font_info(), DeleteFont(kFontHandle));
176   }
177 
178   FixedSizeDataVector<uint8_t> data = font_mapper().RawBytesForIndex(0);
179   EXPECT_TRUE(data.empty());
180 }
181 
TEST_F(CFXFontMapperSystemFontInfoTest,RawBytesForIndexFailToGetData)182 TEST_F(CFXFontMapperSystemFontInfoTest, RawBytesForIndexFailToGetData) {
183   {
184     void* const kFontHandle = reinterpret_cast<void*>(12345);
185 
186     InSequence s;
187     EXPECT_CALL(system_font_info(), MapFont).WillOnce(Return(kFontHandle));
188     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, 0, _))
189         .WillOnce(Return(2));
190     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, 0, _))
191         .WillOnce(Return(0));
192     EXPECT_CALL(system_font_info(), DeleteFont(kFontHandle));
193   }
194 
195   FixedSizeDataVector<uint8_t> data = font_mapper().RawBytesForIndex(0);
196   EXPECT_TRUE(data.empty());
197 }
198 #endif  // PDF_ENABLE_XFA
199 
200 // Regression test for crbug.com/1372234 - should not crash.
TEST_F(CFXFontMapperSystemFontInfoTest,GetCachedTTCFaceFailToGetData)201 TEST_F(CFXFontMapperSystemFontInfoTest, GetCachedTTCFaceFailToGetData) {
202   void* const kFontHandle = reinterpret_cast<void*>(12345);
203   constexpr size_t kTtcSize = 1024;
204   constexpr size_t kDataSize = 2;
205 
206   {
207     InSequence s;
208     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, kTableTTCF, _))
209         .WillOnce(DoAll(WithArg<2>(Invoke([&](pdfium::span<uint8_t> buffer) {
210                           EXPECT_EQ(kTtcSize, buffer.size());
211                           std::iota(buffer.begin(), buffer.end(), 0);
212                         })),
213                         Return(kTtcSize)));
214     EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, kTableTTCF, _))
215         .WillOnce(Return(0));
216   }
217 
218   EXPECT_FALSE(
219       font_mapper().GetCachedTTCFace(kFontHandle, kTtcSize, kDataSize));
220 }
221 
222 // Regression test for crbug.com/1372234 - should not crash.
TEST_F(CFXFontMapperSystemFontInfoTest,GetCachedFaceFailToGetData)223 TEST_F(CFXFontMapperSystemFontInfoTest, GetCachedFaceFailToGetData) {
224   void* const kFontHandle = reinterpret_cast<void*>(12345);
225   constexpr char kSubstName[] = "dummy_font";
226   constexpr int kWeight = 400;
227   constexpr bool kItalic = false;
228   constexpr size_t kDataSize = 2;
229 
230   EXPECT_CALL(system_font_info(), GetFontData(kFontHandle, 0, _))
231       .WillOnce(Return(0));
232 
233   EXPECT_FALSE(font_mapper().GetCachedFace(kFontHandle, kSubstName, kWeight,
234                                            kItalic, kDataSize));
235 }
236