diff options
Diffstat (limited to 'Build/source/texk')
-rw-r--r-- | Build/source/texk/web2c/pdftexdir/ChangeLog | 4 | ||||
-rw-r--r-- | Build/source/texk/web2c/pdftexdir/NEWS | 3 | ||||
-rw-r--r-- | Build/source/texk/web2c/pdftexdir/pdftex.web | 137 |
3 files changed, 121 insertions, 23 deletions
diff --git a/Build/source/texk/web2c/pdftexdir/ChangeLog b/Build/source/texk/web2c/pdftexdir/ChangeLog index 73e37b6ab9d..3ceceeb6e9c 100644 --- a/Build/source/texk/web2c/pdftexdir/ChangeLog +++ b/Build/source/texk/web2c/pdftexdir/ChangeLog @@ -1,3 +1,7 @@ +2021-11-04 Marcel Kr\"uger <tex@2krueger.de> + + * pdftex.web: Implement support for PDF 2.0 structure destinations. + 2021-09-25 Karl Berry <karl@freefriends.org> * pdftex.web: always call pdf_warning with prepend_nl true, diff --git a/Build/source/texk/web2c/pdftexdir/NEWS b/Build/source/texk/web2c/pdftexdir/NEWS index 5c552424d32..5942d51d67d 100644 --- a/Build/source/texk/web2c/pdftexdir/NEWS +++ b/Build/source/texk/web2c/pdftexdir/NEWS @@ -1,3 +1,6 @@ +- changes: + - support structured destinations from PDF 2.0. + pdfTeX 3.141592653-2.6-1.40.23 (TeX Live 2021 post-release) (June 28, 2021) - changes: - for letterspaced fonts, use explicit \fontdimen6 if specified. diff --git a/Build/source/texk/web2c/pdftexdir/pdftex.web b/Build/source/texk/web2c/pdftexdir/pdftex.web index b62bc56b585..0d3c7147713 100644 --- a/Build/source/texk/web2c/pdftexdir/pdftex.web +++ b/Build/source/texk/web2c/pdftexdir/pdftex.web @@ -16437,10 +16437,11 @@ well. @d obj_type_font == 3 {index of linked list of Fonts objects} @d obj_type_outline == 4 {index of linked list of outline objects} @d obj_type_dest == 5 {index of linked list of destination objects} -@d obj_type_obj == 6 {index of linked list of raw objects} -@d obj_type_xform == 7 {index of linked list of XObject forms} -@d obj_type_ximage == 8 {index of linked list of XObject image} -@d obj_type_thread == 9 {index of linked list of num article threads} +@d obj_type_struct_dest == 6 {index of linked list of structure destination objects} +@d obj_type_obj == 7 {index of linked list of raw objects} +@d obj_type_xform == 8 {index of linked list of XObject forms} +@d obj_type_ximage == 9 {index of linked list of XObject image} +@d obj_type_thread == 10 {index of linked list of num article threads} @d head_tab_max == obj_type_thread {max index of |head_tab|} @# {max number of kids for balanced trees} @@ -16558,7 +16559,7 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} @d pdf_action_user == 3 {user-defined action} @# {data structure of actions} -@d pdf_action_size == 3 {size of action structure in |mem|} +@d pdf_action_size == 4 {size of action structure in |mem|} @d pdf_action_type == type {action type} @d pdf_action_named_id == subtype {identifier is type of name} @d pdf_action_id == link {destination/thread name identifier} @@ -16567,6 +16568,7 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} @d pdf_action_page_tokens(#) == info(# + 2) {specification of GoTo page action} @d pdf_action_user_tokens(#) == info(# + 2) {user-defined action string} @d pdf_action_refcount(#) == link(# + 2) {counter of references to this action} +@d pdf_action_struct_id(#) == link(# + 3) {structure destination identifier} @# {data structure of outlines; it's not able to write out outline entries before all outline entries are defined, so memory allocated for outline @@ -16597,7 +16599,7 @@ action} @d pdf_dest_fitbv == 6 @d pdf_dest_fitr == 7 -@# {data structure of destinations} +@# {data structure of structure and regular destinations} @d obj_dest_ptr == obj_aux {pointer to |pdf_dest_node|} @d pdf_dest_node_size == 7 {size of whatsit node for destination; words |1..4| hold dest dimensions, word |6| identifier type, subtype @@ -19518,13 +19520,18 @@ if pdf_dest_list <> null then begin "destination has been already written (this shouldn't happen)") else begin i := obj_dest_ptr(info(k)); - if pdf_dest_named_id(i) > 0 then begin + if (pdf_dest_named_id(i) > 0) and (pdf_dest_objnum(i) = null) then begin pdf_begin_dict(info(k), 1); pdf_print("/D "); end else pdf_begin_obj(info(k), 1); - pdf_out("["); pdf_print_int(pdf_last_page); pdf_print(" 0 R "); + pdf_out("["); + if pdf_dest_objnum(i) = null then + pdf_print_int(pdf_last_page) + else + pdf_print_int(pdf_dest_objnum(i)); + pdf_print(" 0 R "); case pdf_dest_type(i) of pdf_dest_xyz: begin pdf_print("/XYZ "); @@ -19565,7 +19572,7 @@ if pdf_dest_list <> null then begin othercases pdf_error("ext5", "unknown dest type"); endcases; pdf_print_ln("]"); - if pdf_dest_named_id(i) > 0 then + if (pdf_dest_named_id(i) > 0) and (pdf_dest_objnum(i) = null) then pdf_end_dict else pdf_end_obj; @@ -19838,6 +19845,7 @@ else begin @<Check for non-existing pages@>; @<Reverse the linked list of Page and Pages objects@>; @<Check for non-existing destinations@>; + @<Check for non-existing structure destinations@>; @<Output fonts definition@>; @<Output pages tree@>; @<Output outlines@>; @@ -19902,6 +19910,39 @@ while k <> 0 do begin k := obj_link(k); end +@ The same for structure destinations, except that there is no sensible default +object to point to. + +@p procedure pdf_fix_struct_dest(k: integer); +begin + if obj_dest_ptr(k) <> null then + return; + pdf_warning("structure dest", "", false, false); + if obj_info(k) < 0 then begin + print("name{"); + print(-obj_info(k)); + print("}"); + end + else begin + print("num"); + print_int(obj_info(k)); + end; + print(" has been referenced but does not exist"); + print_ln; print_ln; + {pdf_begin_obj(k, 1); + pdf_out("["); + pdf_print_int(head_tab[obj_type_page]); + pdf_print_ln(" 0 R /Fit]"); + pdf_end_obj;} +end; + +@ @<Check for non-existing structure destinations@>= +k := head_tab[obj_type_struct_dest]; +while k <> 0 do begin + pdf_fix_struct_dest(k); + k := obj_link(k); +end + @ @<Check for non-existing pages@>= k := head_tab[obj_type_page]; while obj_aux(k) = 0 do begin @@ -33931,8 +33972,10 @@ begin delete_token_ref(pdf_action_file(#)); if pdf_action_type(#) = pdf_action_page then delete_token_ref(pdf_action_page_tokens(#)) - else if pdf_action_named_id(#) > 0 then + else if (pdf_action_named_id(#) and 1) = 1 then delete_token_ref(pdf_action_id(#)); + if (pdf_action_named_id(#) and 2) = 2 then + delete_token_ref(pdf_action_struct_id(#)); end; free_node(#, pdf_action_size); end @@ -34528,7 +34571,7 @@ begin else pdf_create_obj(t, i); r := obj_ptr; - if t = obj_type_dest then + if (t = obj_type_dest) or (t = obj_type_struct_dest) then obj_dest_ptr(r) := null; end; if s <> 0 then @@ -34570,10 +34613,35 @@ begin pdf_action_user_tokens(p) := def_ref; return; end; + pdf_action_named_id(p) := 0; if scan_keyword("file") then begin scan_pdf_ext_toks; pdf_action_file(p) := def_ref; end; + if scan_keyword("struct") then begin + if pdf_action_type(p) <> pdf_action_goto then + pdf_error("ext1", "only GoTo action can be used with `struct'"); + if pdf_action_file(p) <> null then begin + scan_pdf_ext_toks; + pdf_action_named_id(p) := pdf_action_named_id(p) + 2; + pdf_action_struct_id(p) := def_ref; + end + else if scan_keyword("name") then begin + scan_pdf_ext_toks; + pdf_action_named_id(p) := pdf_action_named_id(p) + 2; + pdf_action_struct_id(p) := def_ref; + end + else if scan_keyword("num") then begin + scan_int; + if cur_val <= 0 then + pdf_error("ext1", "num identifier must be positive"); + pdf_action_struct_id(p) := cur_val; + end + else + pdf_error("ext1", "identifier type missing"); + end + else + pdf_action_struct_id(p) := null; if scan_keyword("page") then begin if pdf_action_type(p) <> pdf_action_goto then pdf_error("ext1", "only GoTo action can be used with `page'"); @@ -34582,13 +34650,12 @@ begin if cur_val <= 0 then pdf_error("ext1", "page number must be positive"); pdf_action_id(p) := cur_val; - pdf_action_named_id(p) := 0; scan_pdf_ext_toks; pdf_action_page_tokens(p) := def_ref; end else if scan_keyword("name") then begin scan_pdf_ext_toks; - pdf_action_named_id(p) := 1; + pdf_action_named_id(p) := pdf_action_named_id(p) + 1; pdf_action_id(p) := def_ref; end else if scan_keyword("num") then begin @@ -34599,7 +34666,6 @@ begin scan_int; if cur_val <= 0 then pdf_error("ext1", "num identifier must be positive"); - pdf_action_named_id(p) := 0; pdf_action_id(p) := cur_val; end else @@ -34819,6 +34885,16 @@ begin check_pdfoutput("\pdfdest", true); q := tail; new_whatsit(pdf_dest_node, pdf_dest_node_size); + if scan_keyword("struct") then begin + scan_int; + if cur_val <= 0 then + pdf_error("ext1", "struct identifier must be positive"); + pdf_dest_objnum(tail) := cur_val; + j := obj_type_struct_dest; + end else begin + pdf_dest_objnum(tail) := null; + j := obj_type_dest; + end; if scan_keyword("num") then begin scan_int; if cur_val <= 0 then @@ -34871,11 +34947,11 @@ begin end; if pdf_dest_named_id(tail) <> 0 then begin i := tokens_to_string(pdf_dest_id(tail)); - k := find_obj(obj_type_dest, i, true); + k := find_obj(j, i, true); flush_str(i); end else - k := find_obj(obj_type_dest, pdf_dest_id(tail), false); + k := find_obj(j, pdf_dest_id(tail), false); if (k <> 0) and (obj_dest_ptr(k) <> null) then begin warn_dest_dup(pdf_dest_id(tail), pdf_dest_named_id(tail), "ext4", "has been already used, duplicate ignored"); @@ -35410,7 +35486,7 @@ pdf_start_link_node: begin end; case pdf_action_type(pdf_link_action(p)) of pdf_action_goto: begin - if pdf_action_named_id(pdf_link_action(p)) > 0 then begin + if (pdf_action_named_id(pdf_link_action(p)) mod 2) = 1 then begin print(" goto name"); print_mark(pdf_action_id(pdf_link_action(p))); end @@ -35425,7 +35501,7 @@ pdf_start_link_node: begin print_mark(pdf_action_page_tokens(pdf_link_action(p))); end; pdf_action_thread: begin - if pdf_action_named_id(pdf_link_action(p)) > 0 then begin + if (pdf_action_named_id(pdf_link_action(p)) mod 2) = 1 then begin print(" thread name"); print_mark(pdf_action_id(pdf_link_action(p))); end @@ -36102,11 +36178,11 @@ begin if pdf_action_file(p) = null then begin pdf_print("/S /GoTo "); d := get_obj(obj_type_dest, pdf_action_id(p), - pdf_action_named_id(p)); + pdf_action_named_id(p) mod 2); end else pdf_print("/S /GoToR "); - if pdf_action_named_id(p) > 0 then begin + if (pdf_action_named_id(p) mod 2) = 1 then begin pdf_str_entry("D", tokens_to_string(pdf_action_id(p))); flush_str(last_tokens_string); end @@ -36119,8 +36195,8 @@ begin pdf_print("/S /Thread "); if pdf_action_file(p) = null then d := get_obj(obj_type_thread, pdf_action_id(p), - pdf_action_named_id(p)); - if pdf_action_named_id(p) > 0 then begin + pdf_action_named_id(p) mod 2); + if (pdf_action_named_id(p) mod 2) = 1 then begin pdf_str_entry("D", tokens_to_string(pdf_action_id(p))); flush_str(last_tokens_string); end @@ -36130,6 +36206,18 @@ begin pdf_int_entry("D", pdf_action_id(p)); end; endcases; + if pdf_action_struct_id(p) <> null then begin + pdf_out(" "); + if pdf_action_file(p) = null then + pdf_indirect("SD", get_obj(obj_type_struct_dest, + pdf_action_struct_id(p), + (pdf_action_named_id(p) div 2) mod 2)) + else begin + pdf_print("/SD "); + pdf_print(tokens_to_string(pdf_action_struct_id(p))); + flush_str(last_tokens_string); + end; + end; pdf_print_ln(" >>"); end; @@ -36410,7 +36498,10 @@ begin pdf_error("ext4", "destinations cannot be inside an XForm"); if doing_leaders then return; - k := get_obj(obj_type_dest, pdf_dest_id(p), pdf_dest_named_id(p)); + if pdf_dest_objnum(p) = null then + k := get_obj(obj_type_dest, pdf_dest_id(p), pdf_dest_named_id(p)) + else + k := get_obj(obj_type_struct_dest, pdf_dest_id(p), pdf_dest_named_id(p)); if obj_dest_ptr(k) <> null then begin warn_dest_dup(pdf_dest_id(p), pdf_dest_named_id(p), "ext4", "has been already used, duplicate ignored"); |