fix: code refactor
This commit is contained in:
@@ -0,0 +1,601 @@
|
||||
#include "document_test_helpers.hpp"
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
TEST(FontDiagnosticsTest, IntrospectionAccuracy) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||||
}
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
auto pageRes = doc->getPage(0);
|
||||
ASSERT_TRUE(pageRes.has_value());
|
||||
auto page = *pageRes;
|
||||
|
||||
auto fontsRes = page->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
auto fonts = *fontsRes;
|
||||
|
||||
if (!fonts.empty()) {
|
||||
auto firstFont = fonts[0];
|
||||
EXPECT_FALSE(firstFont.fontName.empty());
|
||||
EXPECT_FALSE(firstFont.type.empty());
|
||||
EXPECT_FALSE(firstFont.normalizedFamily.empty());
|
||||
EXPECT_FALSE(firstFont.internalFontId.empty());
|
||||
}
|
||||
|
||||
auto docFontsRes = doc->getFonts();
|
||||
ASSERT_TRUE(docFontsRes.has_value());
|
||||
auto docFonts = *docFontsRes;
|
||||
EXPECT_EQ(docFonts.size(), fonts.size());
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, SubsetAndVerticalTextIntrospection) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
auto path = getCorpusPath("fonts", "vertical_text.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
path = getCorpusPath("fonts", "utf-8.pdf");
|
||||
}
|
||||
if (!std::filesystem::exists(path)) {
|
||||
GTEST_SKIP() << "vertical_text.pdf or utf-8.pdf not found in corpus.";
|
||||
}
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
auto fontsRes = doc->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
|
||||
for (const auto& f : *fontsRes) {
|
||||
if (f.isSubset) {
|
||||
EXPECT_FALSE(f.subsetTag.empty());
|
||||
EXPECT_EQ(f.subsetTag.size(), 6);
|
||||
}
|
||||
if (f.isVertical) {
|
||||
EXPECT_TRUE(f.isVertical);
|
||||
EXPECT_NE(f.encoding.find("Identity-V"), std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, CacheInvalidationAfterEdits) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||||
}
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
auto fontsRes1 = doc->getFonts();
|
||||
ASSERT_TRUE(fontsRes1.has_value());
|
||||
|
||||
std::string editsJson = R"({
|
||||
"version": "1.0",
|
||||
"operations": [
|
||||
{
|
||||
"id": "op_test_2",
|
||||
"type": "text_overlay",
|
||||
"pageIndex": 0,
|
||||
"data": {
|
||||
"text": "IntrospectionDiagnosticsNewText",
|
||||
"x": 10.0,
|
||||
"y": 20.0,
|
||||
"width": 200.0,
|
||||
"height": 20.0,
|
||||
"fontSize": 12.0,
|
||||
"fontFamily": "Helvetica",
|
||||
"color": "#000000"
|
||||
}
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
auto editRes = doc->applyEdits(editsJson);
|
||||
ASSERT_TRUE(editRes.has_value());
|
||||
|
||||
auto fontsRes2 = doc->getFonts();
|
||||
ASSERT_TRUE(fontsRes2.has_value());
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, ConcurrencyThreadSafety) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||||
}
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
threads.emplace_back([&doc]() {
|
||||
auto res = doc->getFonts();
|
||||
ASSERT_TRUE(res.has_value());
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, DeepIntrospectionAndFontSizeVerification) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
|
||||
{
|
||||
auto path = getCorpusPath("fonts", "utf-8.pdf");
|
||||
if (std::filesystem::exists(path)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
auto fontsRes = doc->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
auto fonts = *fontsRes;
|
||||
|
||||
for (const auto& f : fonts) {
|
||||
EXPECT_FALSE(f.fontName.empty());
|
||||
EXPECT_FALSE(f.type.empty());
|
||||
EXPECT_FALSE(f.normalizedFamily.empty());
|
||||
EXPECT_FALSE(f.internalFontId.empty());
|
||||
|
||||
if (f.isSubset) {
|
||||
EXPECT_EQ(f.subsetTag.size(), 6);
|
||||
for (char c : f.subsetTag) {
|
||||
EXPECT_TRUE(std::isupper(static_cast<unsigned char>(c)));
|
||||
}
|
||||
EXPECT_EQ(f.sourceType, "Embedded");
|
||||
EXPECT_TRUE(f.isEmbedded);
|
||||
EXPECT_EQ(f.internalFontId, f.fontName);
|
||||
} else {
|
||||
EXPECT_TRUE(f.subsetTag.empty());
|
||||
EXPECT_EQ(f.internalFontId, f.fontName + "_" + f.type + "_" + std::to_string(f.flags));
|
||||
}
|
||||
|
||||
if (f.sourceType == "SystemFallback") {
|
||||
EXPECT_FALSE(f.isEmbedded);
|
||||
EXPECT_TRUE(f.substitutedFrom.empty());
|
||||
EXPECT_TRUE(f.substitutedTo.empty());
|
||||
} else if (f.sourceType == "Substituted") {
|
||||
EXPECT_FALSE(f.isEmbedded);
|
||||
EXPECT_EQ(f.substitutedFrom, f.fontName);
|
||||
#if defined(_WIN32)
|
||||
EXPECT_EQ(f.substitutedTo, "Arial");
|
||||
#else
|
||||
EXPECT_EQ(f.substitutedTo, "Liberation Sans");
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPECT_GT(f.ascent, 0.0);
|
||||
EXPECT_LT(f.descent, 0.0);
|
||||
EXPECT_GT(f.capHeight, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto path = getCorpusPath("fonts", "vertical_text.pdf");
|
||||
if (std::filesystem::exists(path)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
auto fontsRes = doc->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
|
||||
bool foundVertical = false;
|
||||
for (const auto& f : *fontsRes) {
|
||||
if (f.isVertical) {
|
||||
foundVertical = true;
|
||||
EXPECT_TRUE(f.encoding.find("-V") != std::string::npos || f.cmapName.find("-V") != std::string::npos);
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(foundVertical);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto path1 = getCorpusPath("fonts", "vertical_identity_v.pdf");
|
||||
if (std::filesystem::exists(path1)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path1.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto fontsRes = (*docRes)->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
|
||||
bool foundVertical = false;
|
||||
for (const auto& f : *fontsRes) {
|
||||
if (f.isVertical) foundVertical = true;
|
||||
}
|
||||
EXPECT_TRUE(foundVertical) << "Failed to detect vertical font in vertical_identity_v.pdf";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto path = getCorpusPath("fonts", "utf-8.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
path = getCorpusPath("basic", "hello_world.pdf");
|
||||
}
|
||||
if (std::filesystem::exists(path)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto doc = *docRes;
|
||||
|
||||
auto pageRes = doc->getPage(0);
|
||||
ASSERT_TRUE(pageRes.has_value());
|
||||
auto page = *pageRes;
|
||||
|
||||
auto boundsRes = page->extractTextWithBounds();
|
||||
ASSERT_TRUE(boundsRes.has_value());
|
||||
|
||||
const auto& glyphs = *boundsRes;
|
||||
ASSERT_FALSE(glyphs.empty());
|
||||
|
||||
std::vector<double> uniqueSizes;
|
||||
for (const auto& glyph : glyphs) {
|
||||
if (glyph.text != " " && glyph.text != "\r" && glyph.text != "\n" && glyph.text != "\t") {
|
||||
EXPECT_GT(glyph.w, 0.0);
|
||||
EXPECT_GT(glyph.h, 0.0);
|
||||
}
|
||||
EXPECT_GT(glyph.fontSize, 0.0);
|
||||
EXPECT_LT(glyph.fontSize, 100.0);
|
||||
|
||||
if (std::find(uniqueSizes.begin(), uniqueSizes.end(), glyph.fontSize) == uniqueSizes.end()) {
|
||||
uniqueSizes.push_back(glyph.fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (path.filename().string() == "utf-8.pdf") {
|
||||
EXPECT_GE(uniqueSizes.size(), 2u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(FontDiagnosticsTest, RealPDFiumEmbeddingAndTypeAccuracy) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
|
||||
auto path = getCorpusPath("fonts", "text_font.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
GTEST_SKIP() << "text_font.pdf not found in corpus.";
|
||||
}
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value()) << "Failed to open text_font.pdf";
|
||||
auto doc = *docRes;
|
||||
|
||||
auto pageRes = doc->getPage(0);
|
||||
ASSERT_TRUE(pageRes.has_value());
|
||||
auto fontsRes = (*pageRes)->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
const auto& fonts = *fontsRes;
|
||||
ASSERT_FALSE(fonts.empty()) << "text_font.pdf must expose at least one font";
|
||||
|
||||
for (const auto& f : fonts) {
|
||||
EXPECT_FALSE(f.fontName.empty());
|
||||
EXPECT_FALSE(f.type.empty());
|
||||
|
||||
static const std::vector<std::string> kValidTypes = {
|
||||
"Type1", "TrueType", "CIDFontType0", "CIDFontType2"
|
||||
};
|
||||
bool typeValid = std::find(kValidTypes.begin(), kValidTypes.end(), f.type)
|
||||
!= kValidTypes.end();
|
||||
EXPECT_TRUE(typeValid) << "Unexpected type '" << f.type << "' for font '" << f.fontName << "'";
|
||||
|
||||
if (f.isSubset) {
|
||||
EXPECT_TRUE(f.isEmbedded)
|
||||
<< "Subset font '" << f.fontName
|
||||
<< "' must be embedded (FPDFFont_GetIsEmbedded should return 1)";
|
||||
EXPECT_EQ(f.sourceType, "Embedded")
|
||||
<< "sourceType must be 'Embedded' when isEmbedded=true";
|
||||
EXPECT_TRUE(f.substitutedFrom.empty());
|
||||
EXPECT_TRUE(f.substitutedTo.empty());
|
||||
}
|
||||
|
||||
if (f.isEmbedded) {
|
||||
EXPECT_EQ(f.sourceType, "Embedded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, RealPDFiumMetricsAccuracy) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
|
||||
auto path = getCorpusPath("fonts", "text_font.pdf");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
GTEST_SKIP() << "text_font.pdf not found in corpus.";
|
||||
}
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
ASSERT_TRUE(docRes.has_value());
|
||||
auto fontsRes = (*docRes)->getFonts();
|
||||
ASSERT_TRUE(fontsRes.has_value());
|
||||
|
||||
for (const auto& f : *fontsRes) {
|
||||
EXPECT_GT(f.ascent, 0.0)
|
||||
<< "ascent must be positive for font '" << f.fontName << "'";
|
||||
EXPECT_LT(f.descent, 0.0)
|
||||
<< "descent must be negative for font '" << f.fontName << "'";
|
||||
EXPECT_GT(f.capHeight, 0.0)
|
||||
<< "capHeight must be positive for font '" << f.fontName << "'";
|
||||
|
||||
EXPECT_LE(f.capHeight, f.ascent + 1.0)
|
||||
<< "capHeight should not exceed ascent for font '" << f.fontName << "'";
|
||||
|
||||
EXPECT_LT(f.ascent, 1500.0) << "Implausibly large ascent for '" << f.fontName << "'";
|
||||
EXPECT_GT(f.descent, -1500.0) << "Implausibly deep descent for '" << f.fontName << "'";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, ToUnicodePresenceAccuracy) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
|
||||
{
|
||||
auto path = getCorpusPath("fonts", "with_tounicode.pdf");
|
||||
if (std::filesystem::exists(path)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
if (docRes.has_value()) {
|
||||
auto pageRes = (*docRes)->getPage(0);
|
||||
if (pageRes.has_value()) {
|
||||
auto fontsRes = (*pageRes)->getFonts();
|
||||
if (fontsRes.has_value() && !fontsRes->empty()) {
|
||||
bool anyTrue = false;
|
||||
for (const auto& f : *fontsRes) {
|
||||
if (f.hasToUnicode) { anyTrue = true; break; }
|
||||
}
|
||||
EXPECT_TRUE(anyTrue)
|
||||
<< "At least one font in with_tounicode.pdf must have hasToUnicode=true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto path = getCorpusPath("fonts", "no_tounicode.pdf");
|
||||
if (std::filesystem::exists(path)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
if (docRes.has_value()) {
|
||||
auto pageRes = (*docRes)->getPage(0);
|
||||
if (pageRes.has_value()) {
|
||||
auto fontsRes = (*pageRes)->getFonts();
|
||||
if (fontsRes.has_value() && !fontsRes->empty()) {
|
||||
for (const auto& f : *fontsRes) {
|
||||
EXPECT_FALSE(f.hasToUnicode)
|
||||
<< "Font '" << f.fontName
|
||||
<< "' in no_tounicode.pdf must have hasToUnicode=false";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto path = getCorpusPath("fonts", "latin_extended.pdf");
|
||||
if (std::filesystem::exists(path)) {
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
if (docRes.has_value()) {
|
||||
auto pageRes = (*docRes)->getPage(0);
|
||||
if (pageRes.has_value()) {
|
||||
auto fontsRes = (*pageRes)->getFonts();
|
||||
if (fontsRes.has_value() && !fontsRes->empty()) {
|
||||
bool anyTrue = false;
|
||||
for (const auto& f : *fontsRes) {
|
||||
if (f.hasToUnicode) { anyTrue = true; break; }
|
||||
}
|
||||
EXPECT_TRUE(anyTrue)
|
||||
<< "At least one font in latin_extended.pdf must decode to Unicode";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST(GlyphCacheTest, ConcurrencyBench) {
|
||||
using namespace pdfengine::fonts;
|
||||
|
||||
FontFace face;
|
||||
bool loaded = face.loadFromFile("C:\\Windows\\Fonts\\arial.ttf");
|
||||
if (!loaded) {
|
||||
GTEST_SKIP() << "Skipping benchmark: Arial font not found.";
|
||||
}
|
||||
|
||||
GlyphCache cache(1000);
|
||||
|
||||
auto run_benchmark = [&](int num_threads, int ops_per_thread) {
|
||||
std::atomic<int> start_flag{0};
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (int i = 0; i < num_threads; ++i) {
|
||||
threads.emplace_back([&, i]() {
|
||||
while (start_flag.load() == 0) { std::this_thread::yield(); }
|
||||
|
||||
for (int op = 0; op < ops_per_thread; ++op) {
|
||||
unsigned int glyphIndex = (op + i) % 2000;
|
||||
unsigned int fontSize = 12 + (op % 5);
|
||||
|
||||
auto hit = cache.get(face, glyphIndex, fontSize);
|
||||
if (!hit) {
|
||||
GlyphBitmap bmp;
|
||||
bmp.width = 10; bmp.height = 10;
|
||||
cache.insert(face, glyphIndex, fontSize, bmp);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
start_flag.store(1);
|
||||
for (auto& t : threads) { t.join(); }
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
std::chrono::duration<double> diff = end_time - start_time;
|
||||
return diff.count();
|
||||
};
|
||||
|
||||
run_benchmark(2, 1000);
|
||||
cache.clear();
|
||||
|
||||
double time_10 = run_benchmark(10, 10000);
|
||||
std::cout << "[ BENCHMARK ] 10 Threads Time: " << time_10 << " seconds (" << (100000.0 / time_10) << " ops/sec)\n";
|
||||
|
||||
cache.clear();
|
||||
|
||||
double time_50 = run_benchmark(50, 10000);
|
||||
std::cout << "[ BENCHMARK ] 50 Threads Time: " << time_50 << " seconds (" << (500000.0 / time_50) << " ops/sec)\n";
|
||||
|
||||
EXPECT_LE(cache.size(), 1000 + 16);
|
||||
}
|
||||
|
||||
TEST(FontDiagnosticsTest, EmbeddedFontResolutionAndReloadingVerification) {
|
||||
SKIP_IF_NO_PDFIUM();
|
||||
|
||||
std::vector<std::string> testFiles = {
|
||||
"text_font.pdf",
|
||||
"embedded_truetype.pdf",
|
||||
"embedded_cid_font.pdf",
|
||||
"subset_font.pdf",
|
||||
"latin_extended.pdf"
|
||||
};
|
||||
|
||||
bool foundAnyEmbedded = false;
|
||||
for (const auto& fileName : testFiles) {
|
||||
auto path = getCorpusPath("fonts", fileName);
|
||||
if (!std::filesystem::exists(path)) {
|
||||
continue;
|
||||
}
|
||||
std::cout << "\n========================================\n";
|
||||
std::cout << "Testing PDF: " << fileName << "\n";
|
||||
std::cout << "========================================\n";
|
||||
|
||||
auto docRes = PdfDocument::loadFromFile(path.string());
|
||||
if (!docRes.has_value()) {
|
||||
std::cout << "Failed to load document: " << fileName << std::endl;
|
||||
continue;
|
||||
}
|
||||
auto doc = *docRes;
|
||||
|
||||
auto fontsRes = doc->getFonts();
|
||||
if (!fontsRes.has_value()) {
|
||||
std::cout << "Failed to get fonts for: " << fileName << std::endl;
|
||||
continue;
|
||||
}
|
||||
const auto& fonts = *fontsRes;
|
||||
|
||||
for (const auto& fontInfo : fonts) {
|
||||
std::cout << "Font: " << fontInfo.fontName
|
||||
<< ", type: " << fontInfo.type
|
||||
<< ", isEmbedded: " << (fontInfo.isEmbedded ? "yes" : "no")
|
||||
<< ", flags: " << fontInfo.flags << std::endl;
|
||||
if (fontInfo.isEmbedded) {
|
||||
foundAnyEmbedded = true;
|
||||
|
||||
auto resolvedFontRes = doc->getResolvedFont(fontInfo);
|
||||
if (!resolvedFontRes.has_value()) {
|
||||
std::cout << " Failed to resolve font: " << resolvedFontRes.error() << std::endl;
|
||||
continue;
|
||||
}
|
||||
auto resolvedFont = *resolvedFontRes;
|
||||
std::cout << " Resolved font successfully." << std::endl;
|
||||
|
||||
auto face = static_cast<FT_Face>(resolvedFont->getFontFace().getFace());
|
||||
if (face) {
|
||||
std::cout << " FreeType Face Num Glyphs: " << face->num_glyphs << std::endl;
|
||||
std::cout << " FreeType Charmaps Count: " << face->num_charmaps << std::endl;
|
||||
for (int i = 0; i < face->num_charmaps; ++i) {
|
||||
FT_CharMap cm = face->charmaps[i];
|
||||
std::cout << " Charmap " << i << ": platform_id=" << cm->platform_id
|
||||
<< ", encoding_id=" << cm->encoding_id << std::endl;
|
||||
|
||||
FT_Error err = FT_Set_Charmap(face, cm);
|
||||
if (err) {
|
||||
std::cout << " FT_Set_Charmap failed: " << err << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
FT_UInt gindex;
|
||||
FT_ULong charcode = FT_Get_First_Char(face, &gindex);
|
||||
std::cout << " Mapped characters under charmap " << i << ": ";
|
||||
int count = 0;
|
||||
while (gindex != 0 && count < 10) {
|
||||
std::cout << charcode << "->" << gindex << " ";
|
||||
charcode = FT_Get_Next_Char(face, charcode, &gindex);
|
||||
count++;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
if (face->num_charmaps > 0) {
|
||||
FT_Set_Charmap(face, face->charmaps[0]);
|
||||
}
|
||||
|
||||
std::cout << " Glyph names: ";
|
||||
for (int i = 0; i < face->num_glyphs; ++i) {
|
||||
char nameBuf[64] = {0};
|
||||
if (FT_Get_Glyph_Name(face, i, nameBuf, sizeof(nameBuf)) == 0) {
|
||||
std::cout << i << ":" << nameBuf << " ";
|
||||
} else {
|
||||
std::cout << i << ":[unknown] ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} else {
|
||||
std::cout << " No FreeType Face available." << std::endl;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(resolvedFont->isEmbedded());
|
||||
|
||||
std::vector<uint32_t> testChars = {32, 48, 65, 97};
|
||||
for (uint32_t cp : testChars) {
|
||||
bool hasG = resolvedFont->hasGlyph(cp);
|
||||
double w = resolvedFont->getAdvanceWidth(cp, 12.0);
|
||||
std::cout << " char(" << cp << "): hasGlyph=" << (hasG ? "yes" : "no")
|
||||
<< ", advanceWidth=" << w << std::endl;
|
||||
}
|
||||
|
||||
auto metrics = resolvedFont->getMetrics(12.0);
|
||||
std::cout << " Metrics: ascent=" << metrics.ascent << ", descent=" << metrics.descent << ", capHeight=" << metrics.capHeight << std::endl;
|
||||
EXPECT_NE(metrics.ascent, 0.0);
|
||||
EXPECT_NE(metrics.descent, 0.0);
|
||||
EXPECT_NE(metrics.capHeight, 0.0);
|
||||
|
||||
if (fileName == "text_font.pdf") {
|
||||
EXPECT_TRUE(resolvedFont->hasGlyph(1));
|
||||
double w = resolvedFont->getAdvanceWidth(1, 12.0);
|
||||
EXPECT_GT(w, 0.0);
|
||||
std::cout << " [VERIFIED] text_font.pdf char(1): hasGlyph=yes, advanceWidth=" << w << std::endl;
|
||||
}
|
||||
|
||||
if (face->num_glyphs > 1) {
|
||||
bool foundNonZeroWidth = false;
|
||||
for (int gid = 1; gid < face->num_glyphs; ++gid) {
|
||||
FT_Error err = FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT);
|
||||
if (err == 0) {
|
||||
double directWidth = static_cast<double>(face->glyph->advance.x) / 64.0;
|
||||
if (directWidth > 0.0) {
|
||||
foundNonZeroWidth = true;
|
||||
std::cout << " [VERIFIED] Direct glyph " << gid << " load: advanceWidth=" << directWidth << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(foundNonZeroWidth) << "Expected to find at least one glyph with a non-zero advance width";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(foundAnyEmbedded) << "Expected to find at least one embedded font in test files";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user