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 "public/fpdf_sysfontinfo.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "build/build_config.h"
11 #include "core/fxcrt/compiler_specific.h"
12 #include "testing/embedder_test.h"
13 #include "testing/embedder_test_environment.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace {
18
19 extern "C" {
20
FakeRelease(FPDF_SYSFONTINFO * pThis)21 void FakeRelease(FPDF_SYSFONTINFO* pThis) {}
FakeEnumFonts(FPDF_SYSFONTINFO * pThis,void * pMapper)22 void FakeEnumFonts(FPDF_SYSFONTINFO* pThis, void* pMapper) {}
23
FakeMapFont(FPDF_SYSFONTINFO * pThis,int weight,FPDF_BOOL bItalic,int charset,int pitch_family,const char * face,FPDF_BOOL * bExact)24 void* FakeMapFont(FPDF_SYSFONTINFO* pThis,
25 int weight,
26 FPDF_BOOL bItalic,
27 int charset,
28 int pitch_family,
29 const char* face,
30 FPDF_BOOL* bExact) {
31 // Any non-null return will do.
32 return pThis;
33 }
34
FakeGetFont(FPDF_SYSFONTINFO * pThis,const char * face)35 void* FakeGetFont(FPDF_SYSFONTINFO* pThis, const char* face) {
36 // Any non-null return will do.
37 return pThis;
38 }
39
FakeGetFontData(FPDF_SYSFONTINFO * pThis,void * hFont,unsigned int table,unsigned char * buffer,unsigned long buf_size)40 unsigned long FakeGetFontData(FPDF_SYSFONTINFO* pThis,
41 void* hFont,
42 unsigned int table,
43 unsigned char* buffer,
44 unsigned long buf_size) {
45 return 0;
46 }
47
FakeGetFaceName(FPDF_SYSFONTINFO * pThis,void * hFont,char * buffer,unsigned long buf_size)48 unsigned long FakeGetFaceName(FPDF_SYSFONTINFO* pThis,
49 void* hFont,
50 char* buffer,
51 unsigned long buf_size) {
52 return 0;
53 }
54
FakeGetFontCharset(FPDF_SYSFONTINFO * pThis,void * hFont)55 int FakeGetFontCharset(FPDF_SYSFONTINFO* pThis, void* hFont) {
56 return 1;
57 }
58
FakeDeleteFont(FPDF_SYSFONTINFO * pThis,void * hFont)59 void FakeDeleteFont(FPDF_SYSFONTINFO* pThis, void* hFont) {}
60
61 } // extern "C"
62
63 class FPDFUnavailableSysFontInfoEmbedderTest : public EmbedderTest {
64 public:
65 FPDFUnavailableSysFontInfoEmbedderTest() = default;
66 ~FPDFUnavailableSysFontInfoEmbedderTest() override = default;
67
SetUp()68 void SetUp() override {
69 EmbedderTest::SetUp();
70 font_info_.version = 1;
71 font_info_.Release = FakeRelease;
72 font_info_.EnumFonts = FakeEnumFonts;
73 font_info_.MapFont = FakeMapFont;
74 font_info_.GetFont = FakeGetFont;
75 font_info_.GetFontData = FakeGetFontData;
76 font_info_.GetFaceName = FakeGetFaceName;
77 font_info_.GetFontCharset = FakeGetFontCharset;
78 font_info_.DeleteFont = FakeDeleteFont;
79 FPDF_SetSystemFontInfo(&font_info_);
80 }
81
TearDown()82 void TearDown() override {
83 FPDF_SetSystemFontInfo(nullptr);
84 EmbedderTest::TearDown();
85
86 // Bouncing the library is the only reliable way to fully undo the initial
87 // FPDF_SetSystemFontInfo() call at the moment.
88 EmbedderTestEnvironment::GetInstance()->TearDown();
89 EmbedderTestEnvironment::GetInstance()->SetUp();
90 }
91
92 FPDF_SYSFONTINFO font_info_;
93 };
94
95 class FPDFSysFontInfoEmbedderTest : public EmbedderTest {
96 public:
97 FPDFSysFontInfoEmbedderTest() = default;
98 ~FPDFSysFontInfoEmbedderTest() override = default;
99
SetUp()100 void SetUp() override {
101 EmbedderTest::SetUp();
102 font_info_ = FPDF_GetDefaultSystemFontInfo();
103 ASSERT_TRUE(font_info_);
104 FPDF_SetSystemFontInfo(font_info_);
105 }
106
TearDown()107 void TearDown() override {
108 EmbedderTest::TearDown();
109
110 // After releasing `font_info_` from PDFium, it is safe to free it.
111 FPDF_SetSystemFontInfo(nullptr);
112 FPDF_FreeDefaultSystemFontInfo(font_info_);
113
114 // Bouncing the library is the only reliable way to fully undo the initial
115 // FPDF_SetSystemFontInfo() call at the moment.
116 EmbedderTestEnvironment::GetInstance()->TearDown();
117
118 EmbedderTestEnvironment::GetInstance()->SetUp();
119 }
120
121 FPDF_SYSFONTINFO* font_info_;
122 };
123
124 } // namespace
125
TEST_F(FPDFUnavailableSysFontInfoEmbedderTest,Bug972518)126 TEST_F(FPDFUnavailableSysFontInfoEmbedderTest, Bug972518) {
127 ASSERT_TRUE(OpenDocument("bug_972518.pdf"));
128 ASSERT_EQ(1, FPDF_GetPageCount(document()));
129
130 ScopedEmbedderTestPage page = LoadScopedPage(0);
131 ASSERT_TRUE(page);
132 }
133
TEST_F(FPDFSysFontInfoEmbedderTest,DefaultSystemFontInfo)134 TEST_F(FPDFSysFontInfoEmbedderTest, DefaultSystemFontInfo) {
135 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
136 ASSERT_EQ(1, FPDF_GetPageCount(document()));
137
138 ScopedEmbedderTestPage page = LoadScopedPage(0);
139 ASSERT_TRUE(page);
140
141 {
142 // Not checking the rendering because it will depend on the fonts installed.
143 ScopedFPDFBitmap bitmap = RenderPage(page.get());
144 ASSERT_EQ(200, FPDFBitmap_GetWidth(bitmap.get()));
145 ASSERT_EQ(200, FPDFBitmap_GetHeight(bitmap.get()));
146 }
147 }
148
TEST_F(FPDFSysFontInfoEmbedderTest,DefaultTTFMap)149 TEST_F(FPDFSysFontInfoEmbedderTest, DefaultTTFMap) {
150 static constexpr int kExpectedCharsets[] = {
151 FXFONT_ANSI_CHARSET, FXFONT_SHIFTJIS_CHARSET,
152 FXFONT_HANGEUL_CHARSET, FXFONT_GB2312_CHARSET,
153 FXFONT_CHINESEBIG5_CHARSET, FXFONT_ARABIC_CHARSET,
154 FXFONT_CYRILLIC_CHARSET, FXFONT_EASTERNEUROPEAN_CHARSET,
155 };
156 std::vector<int> charsets;
157
158 const FPDF_CharsetFontMap* cfmap = FPDF_GetDefaultTTFMap();
159 ASSERT_TRUE(cfmap);
160
161 // Stop at either end mark.
162 while (cfmap->charset != -1 && cfmap->fontname) {
163 charsets.push_back(cfmap->charset);
164 // SAFETY: requires FPDF_GetDefaultTTFMap() to provide a sentinel.
165 UNSAFE_BUFFERS(++cfmap);
166 }
167
168 // Confirm end marks only occur as a pair.
169 EXPECT_EQ(cfmap->charset, -1);
170 EXPECT_EQ(cfmap->fontname, nullptr);
171
172 EXPECT_THAT(charsets, testing::UnorderedElementsAreArray(kExpectedCharsets));
173 }
174
TEST_F(FPDFSysFontInfoEmbedderTest,DefaultTTFMapCountAndEntries)175 TEST_F(FPDFSysFontInfoEmbedderTest, DefaultTTFMapCountAndEntries) {
176 static constexpr int kExpectedCharsets[] = {
177 FXFONT_ANSI_CHARSET,
178 FXFONT_GB2312_CHARSET,
179 FXFONT_CHINESEBIG5_CHARSET,
180 FXFONT_SHIFTJIS_CHARSET,
181 FXFONT_HANGEUL_CHARSET,
182 FXFONT_CYRILLIC_CHARSET,
183 FXFONT_EASTERNEUROPEAN_CHARSET,
184 FXFONT_ARABIC_CHARSET,
185 };
186 static const std::string kExpectedFontNames[] = {
187 "Helvetica", "SimSun", "MingLiU", "MS Gothic", "Batang", "Arial",
188 #if BUILDFLAG(IS_WIN)
189 "Tahoma",
190 #else
191 "Arial",
192 #endif
193 "Arial",
194 };
195 std::vector<int> charsets;
196 std::vector<const char*> font_names;
197
198 const size_t count = FPDF_GetDefaultTTFMapCount();
199 for (size_t i = 0; i < count; ++i) {
200 const FPDF_CharsetFontMap* entry = FPDF_GetDefaultTTFMapEntry(i);
201 ASSERT_TRUE(entry);
202 charsets.push_back(entry->charset);
203 font_names.push_back(entry->fontname);
204 }
205
206 EXPECT_THAT(charsets, testing::ElementsAreArray(kExpectedCharsets));
207 EXPECT_THAT(font_names, testing::ElementsAreArray(kExpectedFontNames));
208
209 // Test out of bound indices.
210 EXPECT_FALSE(FPDF_GetDefaultTTFMapEntry(count));
211 EXPECT_FALSE(FPDF_GetDefaultTTFMapEntry(9999));
212 }
213