fix: reworked ui components

This commit is contained in:
Furqan-14
2026-06-10 21:51:43 +05:30
parent 5f5c09eaa9
commit fa35589f81
12 changed files with 378 additions and 25 deletions
+9 -1
View File
@@ -182,7 +182,15 @@ public:
[[nodiscard]] virtual int pageCount() const noexcept = 0;
[[nodiscard]] virtual DocumentMetadata metadata() const noexcept = 0;
[[nodiscard]] virtual std::expected<std::shared_ptr<PdfPage>, EngineError>
// A single entry in the document outline (bookmarks), flattened with a depth level.
struct OutlineItem {
std::string title;
int pageIndex = -1; // -1 if the destination page can't be resolved
int level = 0; // 0 = top-level
};
[[nodiscard]] virtual std::expected<std::vector<OutlineItem>, EngineError> extractOutline() const = 0;
[[nodiscard]] virtual std::expected<std::shared_ptr<PdfPage>, EngineError>
getPage(int pageIndex) = 0;
[[nodiscard]] virtual std::expected<std::vector<FontInfo>, EngineError>
+94
View File
@@ -1530,6 +1530,52 @@ DocumentMetadata PdfiumDocument::metadata() const noexcept {
return meta;
}
#ifdef PDFENGINE_WITH_PDFIUM
namespace {
// Depth-first flatten of the bookmark tree into OutlineItems with a depth level.
void walkOutline(FPDF_DOCUMENT doc, FPDF_BOOKMARK bm, int level,
std::vector<PdfDocument::OutlineItem>& out) {
while (bm && level <= 32 && out.size() < 5000) {
PdfDocument::OutlineItem item;
item.level = level;
unsigned long len = FPDFBookmark_GetTitle(bm, nullptr, 0);
if (len > 2) {
std::vector<unsigned short> buf(len / 2);
FPDFBookmark_GetTitle(bm, buf.data(), len);
item.title = utf16le_to_utf8(reinterpret_cast<const char16_t*>(buf.data()), buf.size());
while (!item.title.empty() && item.title.back() == '\0') item.title.pop_back();
}
FPDF_DEST dest = FPDFBookmark_GetDest(doc, bm);
if (!dest) {
FPDF_ACTION action = FPDFBookmark_GetAction(bm);
if (action) dest = FPDFAction_GetDest(doc, action);
}
item.pageIndex = dest ? static_cast<int>(FPDFDest_GetDestPageIndex(doc, dest)) : -1;
out.push_back(std::move(item));
FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(doc, bm);
if (child) walkOutline(doc, child, level + 1, out);
bm = FPDFBookmark_GetNextSibling(doc, bm);
}
}
} // namespace
#endif
std::expected<std::vector<PdfDocument::OutlineItem>, EngineError> PdfiumDocument::extractOutline() const {
#ifdef PDFENGINE_WITH_PDFIUM
std::vector<PdfDocument::OutlineItem> result;
if (doc_) {
walkOutline(doc_, FPDFBookmark_GetFirstChild(doc_, nullptr), 0, result);
}
return result;
#else
return std::unexpected(EngineError::Unknown);
#endif
}
std::expected<std::shared_ptr<PdfPage>, EngineError> PdfiumDocument::getPage(int pageIndex) {
#ifdef PDFENGINE_WITH_PDFIUM
if (!doc_) {
@@ -2156,6 +2202,54 @@ std::expected<void, EngineError> PdfiumDocument::applyEdits(const std::string& e
spdlog::error("FPDF_MovePages failed from {} to {}", fromIndex, destPageIndex);
return std::unexpected(EngineError::Unknown);
}
} else if (type == "delete_annotation") {
if (!op.contains("data") || !op["data"].is_object()) {
spdlog::error("delete_annotation operation missing 'data' object");
return std::unexpected(EngineError::InvalidFormat);
}
std::string targetId = op["data"].value("annotationId", "");
if (targetId.empty()) {
spdlog::error("delete_annotation missing 'annotationId'");
return std::unexpected(EngineError::InvalidFormat);
}
FPDF_PAGE page = FPDF_LoadPage(doc_, pageIndex);
if (!page) {
spdlog::error("Failed to load page index {} for delete_annotation", pageIndex);
return std::unexpected(EngineError::Unknown);
}
int count = FPDFPage_GetAnnotCount(page);
int foundIndex = -1;
for (int i = 0; i < count; ++i) {
FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, i);
if (!annot) continue;
// Reconstruct the same id extractAnnotations() exposes (NM, else anno_<page>_<index>).
std::string id;
unsigned long len = FPDFAnnot_GetStringValue(annot, "NM", nullptr, 0);
if (len > 2) {
std::vector<uint8_t> buf(len);
FPDFAnnot_GetStringValue(annot, "NM", reinterpret_cast<FPDF_WCHAR*>(buf.data()), len);
id = utf16le_to_utf8(reinterpret_cast<const char16_t*>(buf.data()), len / sizeof(char16_t));
while (!id.empty() && id.back() == '\0') id.pop_back();
}
if (id.empty()) {
id = "anno_" + std::to_string(pageIndex) + "_" + std::to_string(i);
}
FPDFPage_CloseAnnot(annot);
if (id == targetId) { foundIndex = i; break; }
}
if (foundIndex >= 0) {
if (!FPDFPage_RemoveAnnot(page, foundIndex)) {
spdlog::error("FPDFPage_RemoveAnnot failed for index {}", foundIndex);
}
} else {
spdlog::warn("delete_annotation: annotation '{}' not found on page {}", targetId, pageIndex);
}
FPDF_ClosePage(page);
} else {
spdlog::warn("Unsupported edit operation type: {}", type);
}
+1
View File
@@ -78,6 +78,7 @@ public:
int pageCount() const noexcept override;
DocumentMetadata metadata() const noexcept override;
std::expected<std::vector<OutlineItem>, EngineError> extractOutline() const override;
std::expected<std::shared_ptr<PdfPage>, EngineError> getPage(int pageIndex) override;
std::expected<std::vector<FontInfo>, EngineError> getFonts(int startPage = 0, int endPage = -1) const override;