From fde990ead8bde644a27eeb190b82397753cb3f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Offenh=C3=A4user?= Date: Fri, 24 Mar 2023 22:07:03 +0100 Subject: [PATCH] LibPDF: Allow optional inheritable page attributes Previously, get_inheritable_object would always try to find the object and throw an error if it couldn't. The spec tells us that some page attributes, like CropBox, are optional but also inheritable. Others, like the media box and resources, are technically required by the spec, but omitted by some documents. In both cases, we are now able to search for inheritable objects and find a suitable replacement if there wasn't one. --- Userland/Libraries/LibPDF/Document.cpp | 50 ++++++++++++++++++-------- Userland/Libraries/LibPDF/Document.h | 2 +- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Userland/Libraries/LibPDF/Document.cpp b/Userland/Libraries/LibPDF/Document.cpp index 99d70127ca..de1a373a95 100644 --- a/Userland/Libraries/LibPDF/Document.cpp +++ b/Userland/Libraries/LibPDF/Document.cpp @@ -109,26 +109,46 @@ PDFErrorOr Document::get_page(u32 index) auto page_object = TRY(get_or_load_value(page_object_index)); auto raw_page_object = TRY(resolve_to(page_object)); - auto resources = TRY(get_inheritable_object(CommonNames::Resources, raw_page_object))->cast(); + RefPtr resources; + auto maybe_resources_object = TRY(get_inheritable_object(CommonNames::Resources, raw_page_object)); + if (maybe_resources_object.has_value()) + resources = maybe_resources_object.value()->cast(); + else + resources = adopt_ref(*new DictObject({})); + auto contents = TRY(raw_page_object->get_object(this, CommonNames::Contents)); - auto media_box_array = TRY(get_inheritable_object(CommonNames::MediaBox, raw_page_object))->cast(); - auto media_box = Rectangle { - media_box_array->at(0).to_float(), - media_box_array->at(1).to_float(), - media_box_array->at(2).to_float(), - media_box_array->at(3).to_float(), - }; + Rectangle media_box; + auto maybe_media_box_object = TRY(get_inheritable_object(CommonNames::MediaBox, raw_page_object)); + if (maybe_media_box_object.has_value()) { + auto media_box_array = maybe_media_box_object.value()->cast(); + media_box = Rectangle { + media_box_array->at(0).to_float(), + media_box_array->at(1).to_float(), + media_box_array->at(2).to_float(), + media_box_array->at(3).to_float(), + }; + } else { + // As most other libraries seem to do, we default to the standard + // US letter size of 8.5" x 11" (612 x 792 Postscript units). + media_box = Rectangle { + 0, 0, + 612, 792 + }; + } - auto crop_box = media_box; - if (raw_page_object->contains(CommonNames::CropBox)) { - auto crop_box_array = TRY(raw_page_object->get_array(this, CommonNames::CropBox)); + Rectangle crop_box; + auto maybe_crop_box_object = TRY(get_inheritable_object(CommonNames::CropBox, raw_page_object)); + if (maybe_crop_box_object.has_value()) { + auto crop_box_array = maybe_crop_box_object.value()->cast(); crop_box = Rectangle { crop_box_array->at(0).to_float(), crop_box_array->at(1).to_float(), crop_box_array->at(2).to_float(), crop_box_array->at(3).to_float(), }; + } else { + crop_box = media_box; } float user_unit = 1.0f; @@ -141,7 +161,7 @@ PDFErrorOr Document::get_page(u32 index) VERIFY(rotate % 90 == 0); } - Page page { move(resources), move(contents), media_box, crop_box, user_unit, rotate }; + Page page { resources.release_nonnull(), move(contents), media_box, crop_box, user_unit, rotate }; m_pages.set(index, page); return page; } @@ -306,13 +326,15 @@ PDFErrorOr Document::create_destination_from_parameters(NonnullRefP return Destination { type, page_number_by_index_ref.get(page_ref.as_ref_index()), parameters }; } -PDFErrorOr> Document::get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr object) +PDFErrorOr>> Document::get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr object) { if (!object->contains(name)) { + if (!object->contains(CommonNames::Parent)) + return { OptionalNone() }; auto parent = TRY(object->get_dict(this, CommonNames::Parent)); return get_inheritable_object(name, parent); } - return object->get_object(this, name); + return TRY(object->get_object(this, name)); } PDFErrorOr Document::create_destination_from_dictionary_entry(NonnullRefPtr const& entry, HashMap const& page_number_by_index_ref) diff --git a/Userland/Libraries/LibPDF/Document.h b/Userland/Libraries/LibPDF/Document.h index 7805a20017..8880c653a2 100644 --- a/Userland/Libraries/LibPDF/Document.h +++ b/Userland/Libraries/LibPDF/Document.h @@ -143,7 +143,7 @@ private: PDFErrorOr create_destination_from_parameters(NonnullRefPtr, HashMap const&); PDFErrorOr create_destination_from_dictionary_entry(NonnullRefPtr const& entry, HashMap const& page_number_by_index_ref); - PDFErrorOr> get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr); + PDFErrorOr>> get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr); PDFErrorOr> find_in_name_tree(NonnullRefPtr root, DeprecatedFlyString name); PDFErrorOr> find_in_name_tree_nodes(NonnullRefPtr siblings, DeprecatedFlyString name);