[latex3-commits] [git/LaTeX3-latex3-pdfresources] splitting: split dict in local and global part (9db7e4f)
Ulrike Fischer
fischer at troubleshooting-tex.de
Tue Jul 7 19:15:30 CEST 2020
Repository : https://github.com/latex3/pdfresources
On branch : splitting
Link : https://github.com/latex3/pdfresources/commit/9db7e4f9e4c1813f0491cb00a12d62a7b85b0deb
>---------------------------------------------------------------
commit 9db7e4f9e4c1813f0491cb00a12d62a7b85b0deb
Author: Ulrike Fischer <fischer at troubleshooting-tex.de>
Date: Wed Jun 10 00:29:36 2020 +0200
split dict in local and global part
>---------------------------------------------------------------
9db7e4f9e4c1813f0491cb00a12d62a7b85b0deb
info/sort-commands.txt | 91 ++++++++
l3pdfdict.dtx | 429 +++++++++++--------------------------
l3pdfgdict.dtx | 459 ++++++++++++++++++++++++++++++++++++++++
l3pdfmeta.ins => l3pdfgdict.ins | 6 +-
pdfresources.dtx | 51 +----
5 files changed, 674 insertions(+), 362 deletions(-)
diff --git a/info/sort-commands.txt b/info/sort-commands.txt
new file mode 100644
index 0000000..ce00a90
--- /dev/null
+++ b/info/sort-commands.txt
@@ -0,0 +1,91 @@
+\pdf_version_compare
+\pdf_uncompress:
+\pdf_version_gset
+\pdf_pageobject_ref:n
+\pdf_object_new:nn
+\pdf_object_write:nn
+\pdf_object_ref:nn
+\pdf_object_last:nn
+
+\pdf_bdc
+\pdf_bmc
+\pdf_emc
+
+======================
+pdfprint /output / text / value /content fill store type
+======================
+
+\pdftool_name:n
+\pdftool_name_print:n
+\pdftool_textstringlit
+\pdftool_textstringhex_print:nN
+
+commands using/replacing
+ text_purify /pdfstringdef etc
+
+\pdftext_flag_set % if any should be internal
+
+
+=====================
+pdfcoredict
+=====================
+
+\pdfcoredict_gremove \pdfdict_gremove:nn,
+\pdfcoredict_gput:nnn \pdfdict_gput:nnn,
+
+\@@coredict_gnew:n
+
+==================
+pdfq (graphics)
+================
+
+\pdf_xform_new:nnn
+\pdf_xform_use:n
+\pdf_xform_ref:n
+\pdf_xform_wd:n, \pdf_xform_ht:n, \pdf_xform_dp:n
+\pdf_xform_if_exist:n
+
+======
+pdfannot: annotations, links, destinations
+======
+
+\pdfannot:nnn
+\pdfannot_box:nnnn
+\pdfannot_box_last:
+\pdfannot_link:nnn
+\pdfannot_link_begin:nnw
+\pdfannot_link_goto_begin:nw
+\pdfannot_link_last:
+\pdfannot_dest:nn (local) <- pdf_destination:nn
+\pdfannot_dest_box:nn
+
+
+%flags ...
+
+\pdfdict_map:n
+\pdfdict_reset:n (local)
+\pdfdict_show:n (local,global)
+\pdfdict_if_exist:n
+\pdfdict_if_empty:n (global?)
+\pdfdict_get:nn
+\pdfdict_remove:nn,
+
+=======
+pdfmeta
+=======
+
+\pdfmeta_if_named_action_allowed:n
+
+====
+pdfoutline ????
+=====
+outline
+
+\pdffile_embed_file:nnn (embed + filespec)
+\pdffile_embed_stream:nnn
+
+
+==============
+pdffield
+=============
+fields appearances ocr
diff --git a/l3pdfdict.dtx b/l3pdfdict.dtx
index 2a217fe..e04fff0 100644
--- a/l3pdfdict.dtx
+++ b/l3pdfdict.dtx
@@ -32,7 +32,7 @@
% \fi
%
% \title{^^A
-% The \pkg{l3pdfdict} package\\ Managing global and local dictionaries ^^A
+% The \pkg{l3pdfdict} package\\ Managing local dictionaries ^^A
% }
%
% \author{^^A
@@ -51,55 +51,25 @@
%
% \section{\pkg{l3pdfdict} documentation}
% Many features of a PDF are set by adding a (pdf-)Name and a value
-% to specific PDF dictionaries. The commands in this module offer an interface to
-% these dictionaries. They unify a number of primitives like the pdftex
-% registers \cs{pdfcatalog}, \cs{pdfpagesattr}, \cs{pdfinfo} and similar commands
-% of the other backends in a backend independant way.
+% to specific PDF dictionaries. Examples are attributes of links,
+% filespec dictionaries, xform dictionaries.
+% The commands in this module offer an number of
+% tools to handle such dictionaries. The main purpose of the code
+% here is to give packages and users a better interface to add or
+% change values of such objects.
%
-% There are two distinct types of dictionaries
-% \begin{description}
-% \item[Global dictionaries] These are dictionaries which are inserted only
-% once in a PDF or only once per page. Examples are the Catalog dictionary,
-% the Info dictionary, the page resources. For these dictionaries it is necessary
-% that all package which want to write to them uses the interface provided
-% by this module to avoid clashes and incompatibilities. Values to these
-% dictionaries are always added globally and written by the code
-% at a suitable time to the PDF.
-% Global dictionaries are set and manipulated with the global commands, e.g.
-% \cs{pdf_dict_gput:nnn}. Global dictionaries have names starting with an
-% uppercase letter.
+% The dictionaries are implemented with local property lists.
+% All assignments are local.
%
-% \item[Local dictionaries ] These are dictionaries which are used in varying
-% numberswith varying content. Examples are attributes of links,
-% filespec dictionaries, xform dictionaries. The main purpose of the code
-% here is to give packages and users a better interface to add or
-% change values of such objects.
-%
-% Local dictionaries are set and manipulated with the local commands, e.g.
-% \cs{pdf_dict_put:nnn}. By convention their name start with a lowercase.
-% \end{description}
-%
-% The following tabular summarize the dictionaries and which pdftex primitive they
-% replace:
+% The following tabular summarize the dictionaries
% \begin{tabular}{lll}
-% Info & \cs{pdfinfo} &global\\
-% Catalog \& various subdictionaries & \cs{pdfcatalog} &global\\
-% Pages & \cs{pdfpagesattr}&global\\
-% Page, ThisPage & \cs{pdfpageattr}&global\\
-% Page/Resources/ExtGState & \cs{pdfpageresources}&global\\
-% Page/Resources/Shading & \cs{pdfpageresources}&global\\
-% Page/Resources/Pattern & \cs{pdfpageresources}&global\\
-% Page/Resources/ColorSpace & \cs{pdfpageresources}&global\\%
% xform\ldots & argument of \cs{pdfxform} &local\\
% annot\ldots & argument of \cs{pdfannot},
% \cs{pdfstartlink} &local\\
% \end{tabular}
-%
-% The /Properties dictionary of the page resources is not handled by this module. It is
-% filled and managed through side effects when setting BDC-marks.
+
% \subsection{User Commands}
% \begin{NOTE}{UF}
-% global: upper case: Catalog, Pages.
% local: lower case: annot/link/URI.
% \end{NOTE}
% \begin{function}[added = 2020-04-21]
@@ -112,10 +82,9 @@
% \begin{function}[added = 2020-04-06]
% {\pdfdict_put:nnn, \pdfdict_gput:nnn}
% \begin{syntax}
-% \cs{pdfdict_gput:nnn} \Arg{global dictionary} \Arg{name} \Arg{value}\\
% \cs{pdfdict_put:nnn} \Arg{local dictionary} \Arg{name} \Arg{value}
% \end{syntax}
-% This function puts \Arg{name} \Arg{value} either globally or locally in internal
+% This function puts \Arg{name} \Arg{value} locally in an internal
% property lists.
%
% \Arg{dictionary} is a symbolic name for a concrete PDF dictionary to which the
@@ -127,40 +96,52 @@
% \Arg{value} should be a valid PDF value for this Name in the
% target dictionary.
%
-% The PDF resource management code predefines a large number of
-% symbolic names for important dictionaries and will write the stored values
-% at the right time to the PDF. The predefined symbolic names are described below.
-% By convention, dictionaries starting with an uppercase letter are always stored
-% globally (e.g. \texttt{Catalog} or \texttt{Info}, lowercase letters indicates
-% dictionaries that respect \TeX-groups -- this is e.g. used for dictionaries used in
-% local objects like links.
-%
-% The code works with all major engines but not necessarily
-% in the same way. Most importantly
+% When adding a value keep in mind that
% \begin{itemize}
-% \item The expansion behaviour of the backends can differ. Some backends expand a
+% \item the expansion behaviour of the backends can differ. Some backends expand a
% value always fully when writing to the PDF, with other backends command names
% could end as strings in the PDF. So one should neither rely on \Arg{name}
% \Arg{value} to be expanded nor not expanded by the backend commands.
-% \item The number of compilations needed can differ between the engines and backends.
-% Some engines has to use labels and the aux-file to setup the dictionaries and so need
-% at least two compilations to put everything in place.
% \end{itemize}
% \end{function}
-
+% \begin{function}[EXP,added = 2020-04-21]
+% {\pdfdict_map:n }
+% \begin{syntax}
+% \cs{pdfdict_map:n} \Arg{dictionary}
+% \end{syntax}
+% This outputs the property list of the dictionary as a list of
+% \texttt{/key value} pairs.
+% This can be used e.g. when writing a dictionary object with
+% \cs{pdf_object_write:nx}
+% \end{function}
+% \begin{function}[added = 2020-04-25]
+% {\pdfdict_reset:n }
+% \begin{syntax}
+% \cs{pdfdict_reset:n} \Arg{(local) dictionary}
+% \end{syntax}
+% This resets a dictionary: it clears the entries and then adds eventually
+% default values (normally at least the Type entry).
+% \end{function}
+% \begin{function}[added = 2020-04-08]
+% {\pdfdict_show:n }
+% \begin{syntax}
+% \cs{pdfdict_show:n} \Arg{dictionary}
+% \end{syntax}
+% This shows the content of \Arg{dictionary} in the log and on the terminal.
+%\end{function}
% \end{documentation}
%
% \begin{implementation}
-%<@@=pdf>
+%<@@=pdfdict>
%<*package>
\ProvidesExplPackage {l3pdfdict} {2020-04-08} {0.5}
- {Managing global and local dictionaries}
+ {Managing local dictionaries}
% \section{\pkg{l3pdfdict} implementation}
% \begin{macro}{\pdfdict_new:n}
% \begin{macrocode}
\cs_new_protected:Npn \pdfdict_new:n #1
{
- \@@_dict_new:n {#1}
+ \@@_new:n {#1}
}
% \end{macrocode}
% \end{macro}
@@ -169,28 +150,16 @@
% \begin{macrocode}
\cs_new_protected:Npn \pdfdict_put:nnn #1 #2 #3
{
- \@@_dict_if_local:nTF { #1 }
+ \@@_if_exist:nTF { #1 }
{
- \@@_dict_handler_put:nnn { #1 }{ #2 }{ #3 }
+ \@@_handler_put:nnn { #1 }{ #2 }{ #3 }
}
{
\msg_error:nnnn{pdfdict}{wrong-or-unknown-dict}{#1}{local}
}
}
-\cs_new_protected:Npn \pdfdict_gput:nnn #1 #2 #3
- {
- \@@_dict_if_global:nTF { #1 }
- {
- \@@_dict_handler_put:nnn { #1 }{ #2 }{ #3 }
- }
- {
- \msg_error:nnnn{pdfdict}{wrong-or-unknown-dict}{#1}{global}
- }
- }
-
\cs_generate_variant:Nn \pdfdict_put:nnn {nnx,nno}
-\cs_generate_variant:Nn \pdfdict_gput:nnn {nnx}
% \end{macrocode}
% \subsection{Internal dictionary Code}
% Many code parts are quite similar: property lists for
@@ -198,31 +167,8 @@
% So we define some generic commands to ensure systematic
% internal names. The names are based on paths separated by slashed.
% The first slash is not used in the names.
-%
-% Currently the following names are used: ^^A!!!!! check, compare with g_@@_dict_gnames_seq
-% \begin{verbatim}
-% /Info % (\pdfinfo)
-% /Catalog % (\pdfcatalog)
-% /Catalog/AA %
-% /Catalog/AcroForm
-% /Catalog/OCProperties
-% /Catalog/OutputIntents
-% /Catalog/AcroForm/DR
-% /Catalog/AcroForm/DR/Font
-% /Catalog/MarkInfo
-% /Catalog/ViewerPreferences
-% /Pages % (\pagesattr)
-% /Page % (\pageattr)
-% /ThisPage % (\pageattr)
-% /backend_PageN/Resources/Properties %
-% /Page/Resources/ExtGState
-% /Page/Resources/ColorSpace
-% /Page/Resources/Pattern
-% /Page/Resources/Shading
-% /Page/Resources/Properties
-% /xform/Resources/Properties
-% \end{verbatim}
-% \begin{macro}{\@@_dict_item:nn,\@@_dict_objref_item:nn}
+
+% \begin{macro}{\@@_item:nn,\@@_objref_item:nn}
% Commands to output dict entries: The arguments are \meta{name}\meta{value} and
% \meta{name}\meta{object name}, \meta{name} should be a valid pdf name without
% the slash.
@@ -230,87 +176,38 @@
% in the pdf layer at the input.
% \begin{NOTE}{UF}
%TODO: check expansion behaviour of \cs{@@_dict_objref_item:nn} in the various uses
+%TODO: this should perhaps be move to the module for "content output"
% \end{NOTE}
% \begin{macrocode}
-\cs_new:Npn \@@_dict_item:nn #1 #2 { /#1~#2~ } %name, value
-\cs_generate_variant:Nn \@@_dict_item:nn {ne}
+\cs_new:Npn \@@_item:nn #1 #2 { /#1~#2~ } %name, value
+\cs_generate_variant:Nn \@@_item:nn {ne}
-\cs_new:Npn \@@_dict_objref_item:nn #1 #2 %name, object name
+\cs_new:Npn \@@_objref_item:nn #1 #2 %name, object name
{
- /#1~\@@_backend_object_ref:n { #2 }
+ /#1~\pdf_object_ref:n { #2 }
}
% \end{macrocode}
% \end{macro}
% \begin{macro}
% {
-% \@@_dict_get_g:n,
-% \@@_dict_gname:n,
% \@@_dict_name:n,
-% \@@_dict_gnew:n,
% \@@_dict_new:n,
-% \g_@@_dict_gnames_seq,
-% \g_@@_dict_names_seq
+% \g_@@_names_seq
% }
-% \cs{@@_dict_get_g:n} gives back a \enquote{g} if the dictionary is global.
% \begin{macrocode}
-\seq_new:N \g_@@_dict_gnames_seq
-\seq_new:N \g_@@_dict_names_seq
-
-\tl_const:Nn \c_@@_dict_globalprefix_tl {g}
-\tl_const:Nn \c_@@_dict_localprefix_tl {}
-
-% to retried global status from pathes
-\cs_new:Npn \@@_dict_get_g:n #1 % path name without the leading /
- {
- \tl_if_exist:cT {c_@@_dict_/#1_g_tl}
- {
- \tl_use:c {c_@@_dict_/#1_g_tl}
- }
- }
-
-%global
-\cs_new:Npn \@@_dict_gname:n #1 % path name without the leading /
- {
- g_@@_dict_/#1_prop
- }
+\seq_new:N \g_@@_names_seq
%local
\cs_new:Npn \@@_dict_name:n #1 % path name without the leading /
{
- l_@@_dict_/#1_prop
- }
-
-
-% hm, a bit unclear, can this work? How is expansion?
-% it falls back to prop_name if the path doesn't exist.
-% Can this lead to confusion?
-%
-\cs_new:Npn \@@_dict_Xname:n #1 % path name without the leading /
- {
- \use:c { @@_dict_\@@_dict_get_g:n{#1}name:n } { #1 }
+ l_@@_/#1_prop
}
-%global
-\cs_new_protected:Npn \@@_dict_gnew:n #1
- {
- \@@_dict_if_exist:nTF { #1 }
- {
- \msg_error:nnx
- { pdfdict }
- { dict-already-defined }
- { #1}
- }
- {
- \tl_const:cn { c_@@_dict_/#1_g_tl } { g }
- \prop_new:c { \@@_dict_gname:n { #1 } }
- \seq_gput_right:Nn \g_@@_dict_gnames_seq { #1 }
- }
- }
%local
-\cs_new_protected:Npn \@@_dict_new:n #1
+\cs_new_protected:Npn \@@_new:n #1
{
- \@@_dict_if_exist:nTF { #1 }
+ \@@_if_exist:nTF { #1 }
{
\msg_error:nnx
{ pdfdict }
@@ -318,126 +215,67 @@
{ #1}
}
{
- \tl_const:cn { c_@@_dict_/#1_g_tl } { }
- \prop_new:c { \@@_dict_name:n { #1 } }
- \seq_gput_right:Nn \g_@@_dict_names_seq { #1 }
+ \prop_new:c { \@@_name:n { #1 } }
+ \seq_gput_right:Nn \g_@@_names_seq { #1 }
}
}
% test existence
-\prg_new_conditional:Npnn \@@_dict_if_exist:n #1 { p , T , F , TF }
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
{
- \tl_if_exist:cTF
- { c_@@_dict_/#1_g_tl }
+ \prop_if_exist:cTF
+ { \@@_name:n { #1 } }
{ \prg_return_true: }
{ \prg_return_false: }
}
-% test if global, non existing dicts return false
-\prg_new_conditional:Npnn \@@_dict_if_global:n #1 { p , T , F , TF }
- {
- \tl_if_eq:NcTF
- \c_@@_dict_globalprefix_tl
- { c_@@_dict_/#1_g_tl }
- { \prg_return_true: }
- { \prg_return_false: }
- }
-% test if local, non existing dicts return false
-\prg_new_conditional:Npnn \@@_dict_if_local:n #1 { p , T , F , TF }
- {
- \tl_if_eq:NcTF
- \c_@@_dict_localprefix_tl
- { c_@@_dict_/#1_g_tl }
- { \prg_return_true: }
- { \prg_return_false: }
- }
-\prg_new_conditional:Npnn \@@_dict_if_empty:n #1 { p , T , F , TF }
+\prg_new_conditional:Npnn \@@_if_empty:n #1 { p , T , F , TF }
{
\prop_if_empty:cTF
- { \@@_dict_Xname:n { #1 } }
+ { \@@_name:n { #1 }}
{ \prg_return_true: }
{ \prg_return_false: }
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{
-% \@@_dict_clear,
-% \@@_dict_reset,
-% \@@_dict_handler_put:nnn,
-% \@@_dict_get:nnN,
-% \@@_dict_remove:nn,
-% \@@_dict_show:n
+% \@@_clear:n,
+% \@@_reset:n,
+% \@@_put:nnn,
+% \@@_get:nnN,
+% \@@_remove:nn,
+% \@@_show:n
% }
-% \cs{@@_dict_handler_put:nnn} is the main command to fill the dictionaries.
-% In simple cases it directly fill the property list, but if a handler exists
-% this is called. It is important to use it only in places where this make sense.
-% \cs{@@_dict_put:nnn} is a simpler variant which only fills the property list.
%
% \begin{macrocode}
-
-%we allow only for local dictionaries a clear command
-\cs_new_protected:Npn \@@_dict_clear:n #1
+\cs_new_protected:Npn \@@_clear:n #1
{
- \@@_dict_if_local:nT { #1 }
+ \@@_if_exist:nT { #1 }
{
- \prop_clear:c { \@@_dict_name:n { #1 } }
+ \prop_clear:c { \@@_name:n { #1 } }
}
}
-%reset clears and then fills with the default
-\cs_new_protected:Npn \@@_dict_reset:n #1
+\cs_new_protected:Npn \@@_reset:n #1
{
- \@@_dict_if_local:nT { #1 }
+ \@@_if_exist:nT { #1 }
{
- \prop_clear:c { \@@_dict_name:n { #1 } }
- \use:c { @@_dict_#1_reset: }
+ \prop_clear:c { \@@_name:n { #1 } }
+ \use:c { @@_#1_reset: }
}
}
-
-%local + global
-\cs_new_protected:Npn \@@_dict_handler_put:nnn #1 #2 #3 %#1 path, #2 name, #3 value
- {
- \tl_if_empty:nTF { #3 }
- {
- \msg_none:nnn { pdfdict }{ empty-value }{ /#1/#2 }
- }
- {
- \@@_dict_if_exist:nTF { #1 }
- {
- \cs_if_exist:cTF
- { @@_dict_handler/#1/?_\@@_dict_get_g:n{#1}put:nn } %general, name independant handler
- { \use:c {@@_dict_handler/#1/?_\@@_dict_get_g:n{#1}put:nn} {#2} {#3} }
- {
- \cs_if_exist:cTF
- { @@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}put:n }
- { \use:c {@@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}put:n} {#3} } %special handler
- {
- \use:c { prop_\@@_dict_get_g:n{#1}put:cnn }
- { \@@_dict_Xname:n { #1 } }{ #2 } { #3 }
- }
- }
- }
- {
- \msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
- }
- }
- }
-
-
-\cs_generate_variant:Nn \@@_dict_handler_put:nnn {nxx}
-
-\cs_new_protected:Npn \@@_dict_put:nnn #1 #2 #3 %#1 path, #2 name, #3 value
+\cs_new_protected:Npn \@@_put:nnn #1 #2 #3 %#1 path, #2 name, #3 value
{
\tl_if_empty:nTF { #3 }
{
\msg_none:nnn { pdfdict }{ empty-value }{ /#1/#2 }
}
{
- \@@_dict_if_exist:nTF { #1 }
+ \@@_if_exist:nTF { #1 }
{
- \use:c { prop_\@@_dict_get_g:n{#1}put:cnn }
- { \@@_dict_Xname:n { #1 } }{ #2 } { #3 }
+ \prop_put:cnn
+ { \@@_name:n { #1 } }{ #2 } { #3 }
}
{
\msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
@@ -445,44 +283,20 @@
}
}
-%local + global
-
-\cs_new_protected:Npn \@@_dict_get:nnN #1 #2 #3 %path,key,macro
+\cs_new_protected:Npn \@@_get:nnN #1 #2 #3 %path,key,macro
{
\prop_get:cnN
- { \use:c{ @@_dict_\tl_use:c{c_@@_dict_/#1_g_tl}name:n } { #1 } }
+ { \@@_name:n } { #1 } }
{ #2 } #3
}
-% local / global
-\cs_new_protected:Npn \@@_dict_handler_remove:nn #1 #2 %path,key
- {
- \@@_dict_if_exist:nTF { #1 }
- {
- \cs_if_exist:cTF
- { @@_dict_handler/#1/?_\@@_dict_get_g:n{#1}remove:n } %general, name independant handler
- { \use:c {@@_dict_handler/#1/?_\@@_dict_get_g:n{#1}remove:n} {#2} }
- {
- \cs_if_exist:cTF
- { @@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}remove: }
- { \use:c {@@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}remove:} } %special handler
- {
- \use:c { prop_\@@_dict_get_g:n{#1}remove:cn }
- { \@@_dict_Xname:n { #1 } }{ #2 }
- }
- }
- }
- {
- \msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
- }
- }
-\cs_new_protected:Npn \@@_dict_remove:nn #1 #2 %path,key
+\cs_new_protected:Npn \@@_remove:nn #1 #2 %path,key
{
- \@@_dict_if_exist:nTF { #1 }
+ \@@_if_exist:nTF { #1 }
{
- \use:c { prop_\@@_dict_get_g:n{#1}remove:cn }
- { \@@_dict_Xname:n { #1 } }{ #2 }
+ \prop_remove:cn
+ { \@@_name:n { #1 } }{ #2 }
}
{
\msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
@@ -490,66 +304,59 @@
}
-\cs_new_protected:Npn \@@_dict_show:Nn #1#2
+\cs_new_protected:Npn \@@_show:Nn #1#2
{
- \cs_if_exist:cTF
- { @@_dict_handler/#2/?_show: } %general, name independant handler
- { \use:c {@@_dict_handler/#2/?_show:} }
- {
- \prop_if_exist:cTF { \@@_dict_Xname:n { #2 } }
- {
- #1
- { pdfdict } { show-dict }
- { \tl_to_str:n {#2} }
- { \prop_map_function:cN {\@@_dict_Xname:n { #2 }} \msg_show_item:nn }
- { } { }
- }
- {
- #1 { pdfdict } { unknown-dict } {#2}{}{}{}
- }
+ \prop_if_exist:cTF { \@@_name:n { #2 } }
+ {
+ #1
+ { pdfdict } { show-dict }
+ { \tl_to_str:n {#2} }
+ { \prop_map_function:cN {\@@_name:n { #2 }} \msg_show_item:nn }
+ { } { }
+ }
+ {
+ #1 { pdfdict } { unknown-dict } {#2}{}{}{}
}
}
-\cs_new_protected:Npn \@@_dict_show:n #1 %path
+\cs_new_protected:Npn \@@_show:n #1 %path
{
- \prop_show:c { \use:c{ @@_dict_\@@_dict_get_g:n{#1}name:n } { #1 } }
+ \prop_show:c { \@@_name:n } { #1 } }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{ \@@_dict_map:n }
-% \cs{@@_dict_map:n} outputs a prop as needed in a dictionary:
+% \begin{macro}{ \@@_map:n }
+% \cs{@@_map:n} outputs a prop as needed in a dictionary:
% as a list of /\meta{key} \meta{value} pairs.
% \begin{macrocode}
-%local + global
-%!! Xname must be replaced later!
-% !! is xexpansion the right thing?
-\cs_new:Npn \@@_dict_map:n #1 %path
+% !! is e-expansion the right thing?
+\cs_new:Npn \@@_map:n #1 %path
{
- \prop_map_function:cN { \@@_dict_Xname:n { #1 } } \@@_dict_item:ne
+ \prop_map_function:cN { \@@_name:n { #1 } } \@@_item:ne
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{ \@@_dict_gmerge:nnN }
-% \cs{@@_dict_gmerge:nnN} merges at first the property \meta{name_1}
-% then optionally \meta{name_2} into property |#3|.
% \begin{macrocode}
-% only used globally imho so leaving the global version only for now
-\cs_new_protected:Npn \@@_dict_gmerge:nnN #1 #2 #3
+\cs_new:Npn \pdfdict_map:n #1
{
- \prop_gset_eq:Nc #3 { \@@_dict_gname:n { #1 } }
- \prop_if_exist:cT { \@@_dict_gname:n { #2 } }
- {
- \prop_map_inline:cn { \@@_dict_gname:n { #2 } }
- {
- \prop_gput:Nnn #3 { ##1 }{ ##2 }
- }
- }
+ \@@_map:n { #1 }
}
% \end{macrocode}
-% \end{macro}
%
% \begin{macrocode}
+\cs_new_protected:Npn \pdfdict_reset:n #1
+ {
+ \@@_reset:n { #1 }
+ }
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfdict_show:n
+ {
+ \@@_show:Nn \msg_show:nnxxxx {#1}
+ }
+% \end{macrocode}
+% \begin{macrocode}
%</package>
% \end{macrocode}
%
diff --git a/l3pdfgdict.dtx b/l3pdfgdict.dtx
new file mode 100644
index 0000000..696d449
--- /dev/null
+++ b/l3pdfgdict.dtx
@@ -0,0 +1,459 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfgdict.dtx
+%
+% Copyright (C) 2018-2020 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "(experimental) pdfresources bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3pdfgdict} package\\ Managing core pdf dictionaries ^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team at latex-project.org}
+% {latex-team at latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released XXXX-XX-XX}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfgdict} documentation}
+% The commands in this module offer interfaces to a number of core dictionaries
+% of a PDF. They unify a number of primitives like the pdftex
+% registers \cs{pdfcatalog}, \cs{pdfpagesattr}, \cs{pdfinfo} and similar commands
+% of the other backends in a backend independant way.
+%
+% The dictionaries handled by these module are inserted only
+% once in a PDF or only once per page. Examples are the Catalog dictionary,
+% the Info dictionary, the page resources. For these dictionaries management by the
+% \LaTeX{} kernel is necessary to avoid that packages overwrite settings from
+% other packages which would lead to clashes and incompatibilities.
+% It is therefor necessary that all packages which want to add content to this
+% dictionaries uses the interface provided by this module.
+%
+% As this dictionaries are so central for the PDF format values to these
+% dictionaries are always added globally. Through the interface values
+% can be added (and in many cases also removed), but the actually writing of the
+% dictionary objects to the PDF are then handled by
+% the kernel code at a suitable time.
+%
+% The names of this core dictionaries follow the names in the PDF reference.
+% They all have names starting with an uppercase letter.
+
+% \end{description}
+%
+% The following tabular summarize the core dictionaries and which pdftex primitive they
+% replace:
+% \begin{tabular}{ll}
+% Info & \cs{pdfinfo} \\
+% Catalog \& various subdictionaries & \cs{pdfcatalog} \\
+% Pages & \cs{pdfpagesattr} \\
+% Page, ThisPage & \cs{pdfpageattr} \\
+% Page/Resources/ExtGState & \cs{pdfpageresources} \\
+% Page/Resources/Shading & \cs{pdfpageresources} \\
+% Page/Resources/Pattern & \cs{pdfpageresources} \\
+% Page/Resources/ColorSpace & \cs{pdfpageresources} \\%
+% \end{tabular}
+%
+% There is no \texttt{Page/Resources/Properties} dictionary in the list
+% as this is dictionary is not filled directly but
+% filled and managed through side effects when setting BDC-marks.
+% \subsection{User Commands}
+%
+% \begin{function}[added = 2020-04-06]
+% {\pdfgdict_gput:nnn}
+% \begin{syntax}
+% \cs{pdfgdict_gput:nnn} \Arg{core dictionary} \Arg{name} \Arg{value}\\
+% \end{syntax}
+% This function puts \Arg{name} \Arg{value} globally in an internal
+% property lists.
+%
+% \Arg{core dictionary} is a symbolic name for a concrete PDF dictionary to
+% which the content of these property lists will be written by the PDF
+% resource management code.
+%
+% \Arg{name} should be a valid PDF Name without
+% the starting slash.
+%
+% \Arg{value} should be a valid PDF value for this Name in the
+% target dictionary.
+%
+% The PDF resource management code predefines a large number of
+% symbolic names for important core dictionaries and will write the stored values
+% at the right time to the PDF. The predefined symbolic names are described below.
+%
+% The code works with all major engines but not necessarily
+% in the same way. Most importantly
+% \begin{itemize}
+% \item The expansion behaviour of the backends can differ. Some backends expand a
+% value always fully when writing to the PDF, with other backends command names
+% could end as strings in the PDF. So one should neither rely on \Arg{name}
+% \Arg{value} to be expanded nor not expanded by the backend commands.
+% \item The number of compilations needed can differ between the engines and
+% backends. Some engines have to use labels and the aux-file to setup
+% the dictionaries and so need at least two compilations to put everything
+% in place.
+% \end{itemize}
+% \end{function}
+% \begin{function}[added = 2020-04-08]
+% {\pdfgdict_show:n }
+% \begin{syntax}
+% \cs{pdfgdict_show:n} \Arg{dictionary}
+% \end{syntax}
+% This shows the content of \Arg{dictionary} in the log and on the terminal.
+% It doesn't show the special catalog dictionaries with arrays as values
+% as these are filled only at the end of the document. It is not reliable for
+% page resources as these are filled a shipout.
+%\end{function}
+% \end{documentation}
+%
+% \begin{implementation}
+% \begin{macrocode}
+%<@@=pdfgdict>
+%<*package>
+% \end{macrocode}
+\ProvidesExplPackage {l3pdfgdict} {2020-04-08} {0.5}
+ {Managing global and local dictionaries}
+% \section{\pkg{l3pdfgdict} implementation}
+% \subsection{Messages}
+% \begin{macrocode}
+\msg_new:nnn { pdfgdict } { unknown-dict }
+ {
+ The~dictionary~'#1'~is~not~declared.
+ }
+\msg_new:nnn { pdfgdict } { wrong-or-unknown-dict }
+ {
+ The~dictionary~'#1'~is~either~not~a~#2~dictionary\\
+ or~is~not~declared.
+ }
+
+\msg_new:nnn { pdfgdict } { empty-value }
+ { The~value~for~#1~is~empty~and~will~be~ignored }
+
+\msg_new:nnn { pdfgdict } { no-removal }
+ { It~is~not~possible~to~remove~values~from~dictionary~'#1'.}
+
+\msg_new:nnn { pdfgdict } { no-show }
+ { It~is~not~possible~to~show~the~dictionary~'#1'.}
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfgdict_gput:nnn #1 #2 #3
+ {
+ \@@_if_global:nTF { #1 }
+ {
+ \@@_handler_put:nnn { #1 }{ #2 }{ #3 }
+ }
+ {
+ \msg_error:nnnn{pdfgdict}{wrong-or-unknown-dict}{#1}{core}
+ }
+ }
+
+\cs_generate_variant:Nn \pdfgdict_gput:nnn {nnx}
+% \end{macrocode}
+% \subsection{Internal dictionary Code}
+% Many code parts are quite similar: property lists for
+% dictionaries are filled and output.
+% So we define some generic commands to ensure systematic
+% internal names. The names are based on paths separated by slashed.
+% The first slash is not used in the names.
+%
+% Currently the following names are used: ^^A!!!!! check, compare with g_@@_gnames_seq
+% \begin{verbatim}
+% /Info % (\pdfinfo)
+% /Catalog % (\pdfcatalog)
+% /Catalog/AA %
+% /Catalog/AcroForm
+% /Catalog/OCProperties
+% /Catalog/OutputIntents
+% /Catalog/AcroForm/DR
+% /Catalog/AcroForm/DR/Font
+% /Catalog/MarkInfo
+% /Catalog/ViewerPreferences
+% /Pages % (\pagesattr)
+% /Page % (\pageattr)
+% /ThisPage % (\pageattr)
+% /backend_PageN/Resources/Properties %
+% /Page/Resources/ExtGState
+% /Page/Resources/ColorSpace
+% /Page/Resources/Pattern
+% /Page/Resources/Shading
+% /Page/Resources/Properties
+% /xform/Resources/Properties
+% \end{verbatim}
+% \begin{macro}{\@@_item:nn,\@@_objref_item:nn}
+% Commands to output dict entries: The arguments are \meta{name}\meta{value} and
+% \meta{name}\meta{object name}, \meta{name} should be a valid pdf name without
+% the slash.
+% The commands don't check if the arguments are empty or valid. This should be done
+% in the pdf layer at the input.
+% \begin{NOTE}{UF}
+%TODO: check expansion behaviour of \cs{@@_objref_item:nn} in the various uses
+%This command could be shared with pdfdict, but is it worth the trouble?
+% \end{NOTE}
+% \begin{macrocode}
+\cs_new:Npn \@@_item:nn #1 #2 { /#1~#2~ } %name, value
+\cs_generate_variant:Nn \@@_item:nn {ne}
+
+\cs_new:Npn \@@_objref_item:nn #1 #2 %name, object name
+ {
+ /#1~\pdf_object_ref:n { #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \@@_name:n,
+% \@@_new:n,
+% \g_@@_names_seq,
+% }
+% \begin{macrocode}
+\seq_new:N \g_@@_names_seq
+
+\cs_new:Npn \@@_name:n #1 % path name without the leading /
+ {
+ g_@@_/#1_prop
+ }
+
+\cs_new_protected:Npn \@@_new:n #1
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \msg_error:nnx
+ { pdfgdict }
+ { dict-already-defined }
+ { #1}
+ }
+ {
+ \prop_new:c { \@@_name:n { #1 } }
+ \seq_gput_right:Nn \g_@@_names_seq { #1 }
+ }
+ }
+
+% test existence
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
+ {
+ \prop_if_exist:cTF
+ { \@@_name:n { #1 } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+
+\prg_new_conditional:Npnn \@@_if_empty:n #1 { p , T , F , TF }
+ {
+ \prop_if_empty:cTF
+ { \@@_name:n { #1 } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{
+% \@@_handler_gput:nnn,
+% \@@_gput:nnn,
+% \@@_get:nnN,
+% \@@_gremove:nn,
+% \@@_show:n
+% }
+% \cs{@@_handler_gput:nnn} is the main command to fill the dictionaries.
+% In simple cases it directly fill the property list, but if a handler exists
+% this is called. It is important to use it only in places where this make sense.
+% \cs{@@_put:nnn} is a simpler variant which only fills the property list.
+%
+% \begin{macrocode}
+
+%global
+\cs_new_protected:Npn \@@_handler_gput:nnn #1 #2 #3 %#1 path, #2 name, #3 value
+ {
+ \tl_if_empty:nTF { #3 }
+ {
+ \msg_none:nnn { pdfgdict }{ empty-value }{ /#1/#2 }
+ }
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/?_gput:nn } %general, name independant handler
+ { \use:c {@@_handler/#1/?_gput:nn} {#2} {#3} }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/#2_gput:n }
+ { \use:c {@@_handler/#1/#2_gput:n} {#3} } %special handler
+ {
+ \use:c { prop_gput:cnn }
+ { \@@_name:n { #1 } }{ #2 } { #3 }
+ }
+ }
+ }
+ {
+ \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+ }
+ }
+ }
+
+
+\cs_generate_variant:Nn \@@_handler_gput:nnn {nxx}
+
+\cs_new_protected:Npn \@@_gput:nnn #1 #2 #3 %#1 path, #2 name, #3 value
+ {
+ \tl_if_empty:nTF { #3 }
+ {
+ \msg_none:nnn { pdfgdict }{ empty-value }{ /#1/#2 }
+ }
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \use:c { prop_gput:cnn }
+ { \@@_name:n { #1 } }{ #2 } { #3 }
+ }
+ {
+ \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+ }
+ }
+ }
+
+\cs_new_protected:Npn \@@_get:nnN #1 #2 #3 %path,key,macro
+ {
+ \prop_get:cnN
+ { \@@_name:n { #1 } }
+ { #2 } #3
+ }
+
+
+\cs_new_protected:Npn \@@_handler_gremove:nn #1 #2 %path,key
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/?_gremove:n } %general, name independant handler
+ { \use:c {@@_handler/#1/?_gremove:n} {#2} }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/#2_gremove: }
+ { \use:c {@@_handler/#1/#2_gremove:} } %special handler
+ {
+ \prop_gremove:cn
+ { \@@_name:n { #1 } }{ #2 }
+ }
+ }
+ }
+ {
+ \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+ }
+ }
+
+\cs_new_protected:Npn \@@_gremove:nn #1 #2 %path,key
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \prop_gremove:cn
+ { \@@_name:n { #1 } }{ #2 }
+ }
+ {
+ \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+ }
+ }
+
+
+\cs_new_protected:Npn \@@_show:Nn #1#2
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#2/?_show: } %general, name independant handler
+ { \use:c {@@_handler/#2/?_show:} }
+ {
+ \prop_if_exist:cTF { \@@_name:n { #2 } }
+ {
+ #1
+ { pdfgdict } { show-dict }
+ { \tl_to_str:n {#2} }
+ { \prop_map_function:cN {\@@_name:n { #2 }} \msg_show_item:nn }
+ { } { }
+ }
+ {
+ #1 { pdfgdict } { unknown-dict } {#2}{}{}{}
+ }
+ }
+ }
+
+\cs_new_protected:Npn \@@_show:n #1 %path
+ {
+ \prop_show:c { \@@_name:n { #1 } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ \@@_map:n }
+% \cs{@@_map:n} outputs a prop as needed in a dictionary:
+% as a list of /\meta{key} \meta{value} pairs.
+% \begin{macrocode}
+% !! is e-expansion the right thing?
+\cs_new:Npn \@@_map:n #1 %path
+ {
+ \prop_map_function:cN { \@@_name:n { #1 } } \@@_item:ne
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ \@@_gmerge:nnN }
+% \cs{@@_gmerge:nnN} merges at first the property \meta{name_1}
+% then optionally \meta{name_2} into property |#3|.
+% \begin{macrocode}
+
+\cs_new_protected:Npn \@@_gmerge:nnN #1 #2 #3
+ {
+ \prop_gset_eq:Nc #3 { \@@_name:n { #1 } }
+ \prop_if_exist:cT { \@@_name:n { #2 } }
+ {
+ \prop_map_inline:cn { \@@_name:n { #2 } }
+ {
+ \prop_gput:Nnn #3 { ##1 }{ ##2 }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfgdict_show:n
+ {
+ \@@_show:Nn \msg_show:nnxxxx {#1}
+ }
+% \end{macrocode}
+
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/l3pdfmeta.ins b/l3pdfgdict.ins
similarity index 93%
copy from l3pdfmeta.ins
copy to l3pdfgdict.ins
index d2e63a0..0454aa8 100644
--- a/l3pdfmeta.ins
+++ b/l3pdfgdict.ins
@@ -1,6 +1,6 @@
\iffalse meta-comment
-File: l3pdffile.ins
+File: l3pdfgdict.ins
Copyright (C) 2018-2020 The LaTeX3 Project
@@ -53,9 +53,9 @@ and all files in that bundle must be distributed together.
\keepsilent
-\generate{\file{l3pdfmeta.sty}
+\generate{\file{l3pdfgdict.sty}
{
- \from{l3pdfmeta.dtx} {package}
+ \from{l3pdfgdict.dtx} {package}
}
}
diff --git a/pdfresources.dtx b/pdfresources.dtx
index 9c46036..b384baa 100644
--- a/pdfresources.dtx
+++ b/pdfresources.dtx
@@ -366,56 +366,11 @@
%</package>
%<*package>
% \begin{macrocode}
+\RequirePackage{l3pdfgdict}
\RequirePackage{l3pdfdict}
+
% \end{macrocode}
-% \begin{function}[EXP,added = 2020-04-21]
-% {\pdfdict_map:n }
-% \begin{syntax}
-% \cs{pdfdict_map:n} \Arg{dictionary}
-% \end{syntax}
-% This outputs the property list of the dictionary as a list of
-% \texttt{/key value} pairs.
-% This is suitable for simple, local dictionaries which can be written directly
-% to the PDF.
-% \end{function}
-% \begin{macrocode}
-\cs_new:Npn \pdfdict_map:n #1
- {
- \@@_dict_map:n { #1 }
- }
-% \end{macrocode}
-%
-% \begin{function}[added = 2020-04-25]
-% {\pdfdict_reset:n }
-% \begin{syntax}
-% \cs{pdfdict_reset:n} \Arg{(local) dictionary}
-% \end{syntax}
-% This resets a dictionary: it clears the entries and then adds eventually
-% default values (normally at least the Type entry).
-% \end{function}
-% \begin{macrocode}
-\cs_new_protected:Npn \pdfdict_reset:n #1
- {
- \@@_dict_reset:n { #1 }
- }
-% \end{macrocode}
-% \begin{function}[added = 2020-04-08]
-% {\pdfdict_show:n }
-% \begin{syntax}
-% \cs{pdfdict_show:n} \Arg{dictionary}
-% \end{syntax}
-% This shows the content of \Arg{dictionary} in the log and on the terminal.
-% It also shows if \Arg{dictionary} is a local or a global dictionary.
-% It doesn't show the special catalog dictionaries with arrays as values
-% as these are filled only at
-% the end of the document.
-%\end{function}
-% \begin{macrocode}
-\cs_new_protected:Npn \pdfdict_show:n
- {
- \@@_dict_show:Nn \msg_show:nnxxxx
- }
-% \end{macrocode}
+
% \begin{function}[EXP, pTF,added = 2020-04-08]
% {\pdfdict_if_exist:n }
% \begin{syntax}
More information about the latex3-commits
mailing list.