1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 12:17:44 +00:00

LibPDF: Implement GoTo action for outline

Outline items can contain either a /Dest key or an /A key.

The /Dest key points to a "Destination" (various ways to reference a
page in the same document).

The /A key points to an "Action" which can have several types.
One type, the /GoTo type, just also points to a Destination.

Implement GoTo actions. This makes clicking "Contents" in the outline of
https://developer.apple.com/library/archive/documentation/mac/pdf/Text.pdf
work. (Almost all other items in this file's outline use /Dest.
"Contents" could too, but it uses /A /GoTo for some reason.)

(Other action types are things like opening a hyperlink, opening a
different file, playing a sound, submitting a form, etc. Actions
are also used for in-page links, not just in outlines. Many of
these action types we'll likely never want to implement.)
This commit is contained in:
Nico Weber 2023-10-17 08:07:59 -04:00 committed by Tim Flynn
parent d9c9510d3c
commit 182639217f
2 changed files with 18 additions and 0 deletions

View file

@ -9,6 +9,7 @@
#include <AK/DeprecatedFlyString.h> #include <AK/DeprecatedFlyString.h>
#define ENUMERATE_COMMON_NAMES(X) \ #define ENUMERATE_COMMON_NAMES(X) \
X(A) \
X(AIS) \ X(AIS) \
X(Alternate) \ X(Alternate) \
X(ASCII85Decode) \ X(ASCII85Decode) \
@ -134,6 +135,7 @@
X(Root) \ X(Root) \
X(Rotate) \ X(Rotate) \
X(RunLengthDecode) \ X(RunLengthDecode) \
X(S) \
X(SA) \ X(SA) \
X(SM) \ X(SM) \
X(SMask) \ X(SMask) \

View file

@ -540,6 +540,22 @@ PDFErrorOr<NonnullRefPtr<OutlineItem>> Document::build_outline_item(NonnullRefPt
if (outline_item_dict->contains(CommonNames::Dest)) { if (outline_item_dict->contains(CommonNames::Dest)) {
auto dest_obj = TRY(outline_item_dict->get_object(this, CommonNames::Dest)); auto dest_obj = TRY(outline_item_dict->get_object(this, CommonNames::Dest));
outline_item->dest = TRY(create_destination_from_object(dest_obj, page_number_by_index_ref)); outline_item->dest = TRY(create_destination_from_object(dest_obj, page_number_by_index_ref));
} else if (outline_item_dict->contains(CommonNames::A)) {
// PDF 1.7 spec, "8.5 Actions"
auto action_dict = TRY(outline_item_dict->get_dict(this, CommonNames::A));
if (action_dict->contains(CommonNames::S)) {
// PDF 1.7 spec, "TABLE 8.48 Action types"
auto action_type = TRY(action_dict->get_name(this, CommonNames::S))->name();
if (action_type == "GoTo") {
// PDF 1.7 spec, "Go-To Actions"
if (action_dict->contains(CommonNames::D)) {
auto dest_obj = TRY(action_dict->get_object(this, CommonNames::D));
outline_item->dest = TRY(create_destination_from_object(dest_obj, page_number_by_index_ref));
}
} else {
dbgln("Unhandled action type {}", action_type);
}
}
} }
if (outline_item_dict->contains(CommonNames::C)) { if (outline_item_dict->contains(CommonNames::C)) {