1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 10:27:35 +00:00

LibPDF: Support all Dest types

This commit is contained in:
Matthew Olsson 2022-03-05 18:25:33 -07:00 committed by Andreas Kling
parent b240d23a87
commit e9342183f0
3 changed files with 57 additions and 30 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org> * Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -29,6 +29,7 @@
V(D) \ V(D) \
V(DCTDecode) \ V(DCTDecode) \
V(Dest) \ V(Dest) \
V(Dests) \
V(DeviceCMYK) \ V(DeviceCMYK) \
V(DeviceGray) \ V(DeviceGray) \
V(DeviceRGB) \ V(DeviceRGB) \

View file

@ -209,6 +209,39 @@ PDFErrorOr<void> Document::build_outline()
return {}; return {};
} }
PDFErrorOr<Destination> Document::create_destination_from_parameters(NonnullRefPtr<ArrayObject> array)
{
auto page_ref = array->at(0);
auto type_name = TRY(array->get_name_at(this, 1))->name();
Vector<float> parameters;
for (size_t i = 2; i < array->size(); i++)
parameters.append(array->at(i).to_float());
Destination::Type type;
if (type_name == CommonNames::XYZ) {
type = Destination::Type::XYZ;
} else if (type_name == CommonNames::Fit) {
type = Destination::Type::Fit;
} else if (type_name == CommonNames::FitH) {
type = Destination::Type::FitH;
} else if (type_name == CommonNames::FitV) {
type = Destination::Type::FitV;
} else if (type_name == CommonNames::FitR) {
type = Destination::Type::FitR;
} else if (type_name == CommonNames::FitB) {
type = Destination::Type::FitB;
} else if (type_name == CommonNames::FitBH) {
type = Destination::Type::FitBH;
} else if (type_name == CommonNames::FitBV) {
type = Destination::Type::FitBV;
} else {
VERIFY_NOT_REACHED();
}
return Destination { type, page_ref, parameters };
}
PDFErrorOr<NonnullRefPtr<OutlineItem>> Document::build_outline_item(NonnullRefPtr<DictObject> const& outline_item_dict) PDFErrorOr<NonnullRefPtr<OutlineItem>> Document::build_outline_item(NonnullRefPtr<DictObject> const& outline_item_dict)
{ {
auto outline_item = adopt_ref(*new OutlineItem {}); auto outline_item = adopt_ref(*new OutlineItem {});
@ -228,37 +261,28 @@ PDFErrorOr<NonnullRefPtr<OutlineItem>> Document::build_outline_item(NonnullRefPt
outline_item->count = outline_item_dict->get_value(CommonNames::Count).get<int>(); outline_item->count = outline_item_dict->get_value(CommonNames::Count).get<int>();
if (outline_item_dict->contains(CommonNames::Dest)) { if (outline_item_dict->contains(CommonNames::Dest)) {
auto dest_arr = TRY(outline_item_dict->get_array(this, CommonNames::Dest)); auto dest_obj = TRY(outline_item_dict->get_object(this, CommonNames::Dest));
dbgln("IS ARRAY = {}", dest_arr->is_array());
auto page_ref = dest_arr->at(0);
auto type_name = TRY(dest_arr->get_name_at(this, 1))->name();
Vector<float> parameters; if (dest_obj->is<ArrayObject>()) {
for (size_t i = 2; i < dest_arr->size(); i++) auto dest_arr = dest_obj->cast<ArrayObject>();
parameters.append(dest_arr->at(i).to_float()); outline_item->dest = TRY(create_destination_from_parameters(dest_arr));
} else if (dest_obj->is<NameObject>()) {
Destination::Type type; auto dest_name = dest_obj->cast<NameObject>()->name();
if (type_name == CommonNames::XYZ) { if (auto dests_value = m_catalog->get(CommonNames::Dests); dests_value.has_value()) {
type = Destination::Type::XYZ; auto dests = dests_value.value().get<NonnullRefPtr<Object>>()->cast<DictObject>();
} else if (type_name == CommonNames::Fit) { auto entry = MUST(dests->get_object(this, dest_name));
type = Destination::Type::Fit; if (entry->is<ArrayObject>()) {
} else if (type_name == CommonNames::FitH) { auto entry_array = entry->cast<ArrayObject>();
type = Destination::Type::FitH; outline_item->dest = TRY(create_destination_from_parameters(entry_array));
} else if (type_name == CommonNames::FitV) { } else {
type = Destination::Type::FitV; auto entry_dictionary = entry->cast<DictObject>();
} else if (type_name == CommonNames::FitR) { auto d_array = MUST(entry_dictionary->get_array(this, CommonNames::D));
type = Destination::Type::FitR; outline_item->dest = TRY(create_destination_from_parameters(d_array));
} else if (type_name == CommonNames::FitB) { }
type = Destination::Type::FitB; } else {
} else if (type_name == CommonNames::FitBH) { return Error { Error::Type::MalformedPDF, "Malformed outline destination" };
type = Destination::Type::FitBH; }
} else if (type_name == CommonNames::FitBV) {
type = Destination::Type::FitBV;
} else {
VERIFY_NOT_REACHED();
} }
outline_item->dest = Destination { type, page_ref, parameters };
} }
if (outline_item_dict->contains(CommonNames::C)) { if (outline_item_dict->contains(CommonNames::C)) {

View file

@ -135,6 +135,8 @@ private:
PDFErrorOr<NonnullRefPtr<OutlineItem>> build_outline_item(NonnullRefPtr<DictObject> const& outline_item_dict); 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, Value const& last_ref);
PDFErrorOr<Destination> create_destination_from_parameters(NonnullRefPtr<ArrayObject>);
NonnullRefPtr<Parser> m_parser; NonnullRefPtr<Parser> m_parser;
RefPtr<DictObject> m_catalog; RefPtr<DictObject> m_catalog;
Vector<u32> m_page_object_indices; Vector<u32> m_page_object_indices;