blob: 9751bfbb9e463d93a4c2836a6470849f101ef96c [file] [log] [blame]
K. Moon832a6942022-10-31 20:11:31 +00001// Copyright 2019 The PDFium Authors
Lei Zhang533ade12019-02-07 18:41:37 +00002// 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
Lei Zhangee390602024-06-26 16:24:13 +00007#include <string>
Lei Zhang69defca2020-09-21 18:16:23 +00008#include <vector>
Lei Zhangf49c47d2020-05-12 03:14:12 +00009
Lei Zhangee390602024-06-26 16:24:13 +000010#include "build/build_config.h"
Tom Sepezb0874842024-06-11 00:35:07 +000011#include "core/fxcrt/compiler_specific.h"
Lei Zhang533ade12019-02-07 18:41:37 +000012#include "testing/embedder_test.h"
Tom Sepez72f520c2020-08-24 23:43:46 +000013#include "testing/embedder_test_environment.h"
Lei Zhang69defca2020-09-21 18:16:23 +000014#include "testing/gmock/include/gmock/gmock.h"
Lei Zhang533ade12019-02-07 18:41:37 +000015#include "testing/gtest/include/gtest/gtest.h"
16
17namespace {
18
Tom Sepez47472962019-06-19 18:28:04 +000019extern "C" {
20
21void FakeRelease(FPDF_SYSFONTINFO* pThis) {}
22void FakeEnumFonts(FPDF_SYSFONTINFO* pThis, void* pMapper) {}
23
24void* 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
35void* FakeGetFont(FPDF_SYSFONTINFO* pThis, const char* face) {
36 // Any non-null return will do.
37 return pThis;
38}
39
40unsigned 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
48unsigned long FakeGetFaceName(FPDF_SYSFONTINFO* pThis,
49 void* hFont,
50 char* buffer,
51 unsigned long buf_size) {
52 return 0;
53}
54
55int FakeGetFontCharset(FPDF_SYSFONTINFO* pThis, void* hFont) {
56 return 1;
57}
58
59void FakeDeleteFont(FPDF_SYSFONTINFO* pThis, void* hFont) {}
60
61} // extern "C"
62
63class FPDFUnavailableSysFontInfoEmbedderTest : public EmbedderTest {
64 public:
65 FPDFUnavailableSysFontInfoEmbedderTest() = default;
66 ~FPDFUnavailableSysFontInfoEmbedderTest() override = default;
67
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
Tom Sepez72f520c2020-08-24 23:43:46 +000082 void TearDown() override {
Lei Zhanga7fca8a2024-02-21 20:05:15 +000083 FPDF_SetSystemFontInfo(nullptr);
Tom Sepez72f520c2020-08-24 23:43:46 +000084 EmbedderTest::TearDown();
85
Lei Zhanga7fca8a2024-02-21 20:05:15 +000086 // Bouncing the library is the only reliable way to fully undo the initial
Lei Zhang69defca2020-09-21 18:16:23 +000087 // FPDF_SetSystemFontInfo() call at the moment.
Tom Sepez72f520c2020-08-24 23:43:46 +000088 EmbedderTestEnvironment::GetInstance()->TearDown();
89 EmbedderTestEnvironment::GetInstance()->SetUp();
90 }
91
Tom Sepez47472962019-06-19 18:28:04 +000092 FPDF_SYSFONTINFO font_info_;
93};
94
Lei Zhang533ade12019-02-07 18:41:37 +000095class FPDFSysFontInfoEmbedderTest : public EmbedderTest {
96 public:
97 FPDFSysFontInfoEmbedderTest() = default;
98 ~FPDFSysFontInfoEmbedderTest() override = default;
99
100 void SetUp() override {
101 EmbedderTest::SetUp();
102 font_info_ = FPDF_GetDefaultSystemFontInfo();
103 ASSERT_TRUE(font_info_);
104 FPDF_SetSystemFontInfo(font_info_);
105 }
106
107 void TearDown() override {
108 EmbedderTest::TearDown();
Tom Sepez72f520c2020-08-24 23:43:46 +0000109
Lei Zhanga7fca8a2024-02-21 20:05:15 +0000110 // 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
Lei Zhang69defca2020-09-21 18:16:23 +0000115 // FPDF_SetSystemFontInfo() call at the moment.
Tom Sepez72f520c2020-08-24 23:43:46 +0000116 EmbedderTestEnvironment::GetInstance()->TearDown();
117
Tom Sepez72f520c2020-08-24 23:43:46 +0000118 EmbedderTestEnvironment::GetInstance()->SetUp();
Lei Zhang533ade12019-02-07 18:41:37 +0000119 }
120
121 FPDF_SYSFONTINFO* font_info_;
122};
123
124} // namespace
125
AbdAlRahmanGadc0589222024-06-28 01:28:29 +0000126TEST_F(FPDFUnavailableSysFontInfoEmbedderTest, Bug972518) {
Tom Sepez47472962019-06-19 18:28:04 +0000127 ASSERT_TRUE(OpenDocument("bug_972518.pdf"));
128 ASSERT_EQ(1, FPDF_GetPageCount(document()));
129
130 FPDF_PAGE page = LoadPage(0);
131 ASSERT_TRUE(page);
132 UnloadPage(page);
133}
134
Lei Zhang533ade12019-02-07 18:41:37 +0000135TEST_F(FPDFSysFontInfoEmbedderTest, DefaultSystemFontInfo) {
136 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
137 ASSERT_EQ(1, FPDF_GetPageCount(document()));
138
139 FPDF_PAGE page = LoadPage(0);
140 ASSERT_TRUE(page);
141
142 {
143 // Not checking the rendering because it will depend on the fonts installed.
144 ScopedFPDFBitmap bitmap = RenderPage(page);
145 ASSERT_EQ(200, FPDFBitmap_GetWidth(bitmap.get()));
146 ASSERT_EQ(200, FPDFBitmap_GetHeight(bitmap.get()));
147 }
148
149 UnloadPage(page);
150}
Tom Sepez3c04fb32020-01-09 20:19:05 +0000151
152TEST_F(FPDFSysFontInfoEmbedderTest, DefaultTTFMap) {
Lei Zhang69defca2020-09-21 18:16:23 +0000153 static constexpr int kExpectedCharsets[] = {
154 FXFONT_ANSI_CHARSET, FXFONT_SHIFTJIS_CHARSET,
Tom Sepez3c04fb32020-01-09 20:19:05 +0000155 FXFONT_HANGEUL_CHARSET, FXFONT_GB2312_CHARSET,
156 FXFONT_CHINESEBIG5_CHARSET, FXFONT_ARABIC_CHARSET,
157 FXFONT_CYRILLIC_CHARSET, FXFONT_EASTERNEUROPEAN_CHARSET,
158 };
Lei Zhang69defca2020-09-21 18:16:23 +0000159 std::vector<int> charsets;
Tom Sepez3c04fb32020-01-09 20:19:05 +0000160
161 const FPDF_CharsetFontMap* cfmap = FPDF_GetDefaultTTFMap();
162 ASSERT_TRUE(cfmap);
163
164 // Stop at either end mark.
165 while (cfmap->charset != -1 && cfmap->fontname) {
Lei Zhang69defca2020-09-21 18:16:23 +0000166 charsets.push_back(cfmap->charset);
Tom Sepezb0874842024-06-11 00:35:07 +0000167 // SAFETY: requires FPDF_GetDefaultTTFMap() to provide a sentinel.
168 UNSAFE_BUFFERS(++cfmap);
Tom Sepez3c04fb32020-01-09 20:19:05 +0000169 }
170
171 // Confirm end marks only occur as a pair.
172 EXPECT_EQ(cfmap->charset, -1);
173 EXPECT_EQ(cfmap->fontname, nullptr);
Lei Zhang69defca2020-09-21 18:16:23 +0000174
175 EXPECT_THAT(charsets, testing::UnorderedElementsAreArray(kExpectedCharsets));
Tom Sepez3c04fb32020-01-09 20:19:05 +0000176}
Lei Zhangee390602024-06-26 16:24:13 +0000177
178TEST_F(FPDFSysFontInfoEmbedderTest, DefaultTTFMapCountAndEntries) {
179 static constexpr int kExpectedCharsets[] = {
180 FXFONT_ANSI_CHARSET,
181 FXFONT_GB2312_CHARSET,
182 FXFONT_CHINESEBIG5_CHARSET,
183 FXFONT_SHIFTJIS_CHARSET,
184 FXFONT_HANGEUL_CHARSET,
185 FXFONT_CYRILLIC_CHARSET,
186 FXFONT_EASTERNEUROPEAN_CHARSET,
187 FXFONT_ARABIC_CHARSET,
188 };
189 static const std::string kExpectedFontNames[] = {
190 "Helvetica", "SimSun", "MingLiU", "MS Gothic", "Batang", "Arial",
191#if BUILDFLAG(IS_WIN)
192 "Tahoma",
193#else
194 "Arial",
195#endif
196 "Arial",
197 };
198 std::vector<int> charsets;
199 std::vector<const char*> font_names;
200
201 const size_t count = FPDF_GetDefaultTTFMapCount();
202 for (size_t i = 0; i < count; ++i) {
203 const FPDF_CharsetFontMap* entry = FPDF_GetDefaultTTFMapEntry(i);
204 ASSERT_TRUE(entry);
205 charsets.push_back(entry->charset);
206 font_names.push_back(entry->fontname);
207 }
208
209 EXPECT_THAT(charsets, testing::ElementsAreArray(kExpectedCharsets));
210 EXPECT_THAT(font_names, testing::ElementsAreArray(kExpectedFontNames));
211
212 // Test out of bound indices.
213 EXPECT_FALSE(FPDF_GetDefaultTTFMapEntry(count));
214 EXPECT_FALSE(FPDF_GetDefaultTTFMapEntry(9999));
215}