summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorRodrigo Tobar <rtobar@icrar.org>2022-12-16 00:14:40 +0800
committerAndrew Kaster <andrewdkaster@gmail.com>2022-12-16 01:24:43 -0700
commitcb1a7cc7211b21a160a4a2faa1cf3bb0ac30a698 (patch)
tree2d7761fef51101825f678b8423d1de397ab37bf9 /Userland
parent41bd304a7f1cc10dbffa46b1de9f4906f9a6be72 (diff)
downloadserenity-cb1a7cc7211b21a160a4a2faa1cf3bb0ac30a698.zip
LibPDF: Simplify outline construction
While the Outline Items making up the document's Outline have all sorts of cross-references (parent, first/last chlid, next/previous sibling, etc), not all documents out there have fully-consistent references. Our implementation already discarded some of that information too (e.g., /Parent and /Prev were never read), and trusted that /First and /Next were good enough to traverse the whole hierarchy. Where the current implementation failed was in assuming that /Last was also a good source of information. There are documents out there were /Last also points to dead ends, and were therefore causing a crash when we verified that the last child found on a chain was the /Last child declared by the parent. To fix this I'm simply removing the check, and simplifying the function call to remove any references to /Last. This way we affirm our commitment to /First and /Next as the main sources of information.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibPDF/Document.cpp17
-rw-r--r--Userland/Libraries/LibPDF/Document.h2
2 files changed, 9 insertions, 10 deletions
diff --git a/Userland/Libraries/LibPDF/Document.cpp b/Userland/Libraries/LibPDF/Document.cpp
index e25dc0e6a0..5dac546ac5 100644
--- a/Userland/Libraries/LibPDF/Document.cpp
+++ b/Userland/Libraries/LibPDF/Document.cpp
@@ -211,9 +211,8 @@ PDFErrorOr<void> Document::build_outline()
return {};
auto first_ref = outline_dict->get_value(CommonNames::First);
- auto last_ref = outline_dict->get_value(CommonNames::Last);
- auto children = TRY(build_outline_item_chain(first_ref, last_ref));
+ auto children = TRY(build_outline_item_chain(first_ref));
m_outline = adopt_ref(*new OutlineDict());
m_outline->children = move(children);
@@ -273,9 +272,7 @@ PDFErrorOr<NonnullRefPtr<OutlineItem>> Document::build_outline_item(NonnullRefPt
if (outline_item_dict->contains(CommonNames::First)) {
VERIFY(outline_item_dict->contains(CommonNames::Last));
auto first_ref = outline_item_dict->get_value(CommonNames::First);
- auto last_ref = outline_item_dict->get_value(CommonNames::Last);
-
- auto children = TRY(build_outline_item_chain(first_ref, last_ref));
+ auto children = TRY(build_outline_item_chain(first_ref));
outline_item->children = move(children);
}
@@ -326,10 +323,14 @@ PDFErrorOr<NonnullRefPtr<OutlineItem>> Document::build_outline_item(NonnullRefPt
return outline_item;
}
-PDFErrorOr<NonnullRefPtrVector<OutlineItem>> Document::build_outline_item_chain(Value const& first_ref, Value const& last_ref)
+PDFErrorOr<NonnullRefPtrVector<OutlineItem>> Document::build_outline_item_chain(Value const& first_ref)
{
+ // We used to receive a last_ref parameter, which was what the parent of this chain
+ // thought was this chain's last child. There are documents out there in the wild
+ // where this cross-references don't match though, and it seems like simply following
+ // the /First and /Next links is the way to go to construct the whole Outline
+ // (we already ignore the /Parent attribute too, which can also be out of sync).
VERIFY(first_ref.has<Reference>());
- VERIFY(last_ref.has<Reference>());
NonnullRefPtrVector<OutlineItem> children;
@@ -352,8 +353,6 @@ PDFErrorOr<NonnullRefPtrVector<OutlineItem>> Document::build_outline_item_chain(
current_child_dict = move(next_child_dict);
}
- VERIFY(last_ref.as_ref_index() == current_child_index);
-
return children;
}
diff --git a/Userland/Libraries/LibPDF/Document.h b/Userland/Libraries/LibPDF/Document.h
index 99a41aa641..e2968b36bd 100644
--- a/Userland/Libraries/LibPDF/Document.h
+++ b/Userland/Libraries/LibPDF/Document.h
@@ -146,7 +146,7 @@ private:
PDFErrorOr<void> build_outline();
PDFErrorOr<NonnullRefPtr<OutlineItem>> build_outline_item(NonnullRefPtr<DictObject> const& outline_item_dict);
- PDFErrorOr<NonnullRefPtrVector<OutlineItem>> build_outline_item_chain(Value const& first_ref, Value const& last_ref);
+ PDFErrorOr<NonnullRefPtrVector<OutlineItem>> build_outline_item_chain(Value const& first_ref);
PDFErrorOr<Destination> create_destination_from_parameters(NonnullRefPtr<ArrayObject>);