% \iffalse meta-comment
%
%% File: pdfmanagement-firstaid.dtx
%
% Copyright (C) 2018-2024 The LaTeX 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 "LaTeX PDF management testphase 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>
\DocumentMetadata{pdfstandard=A-2b}
\documentclass[full]{l3doc}
\usepackage{array,booktabs}
\hypersetup{pdfauthor=The LaTeX Project,pdftitle=pdfmanagement-firstaid
  (LaTeX PDF management testphase bundle)}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% \title{^^A
%   The \pkg{pdfmanagement-firstaid} package  -- temporary patches and package replacements  ^^A
%   \\ \LaTeX{} PDF management testphase bundle
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Version 0.96m, released 2024-09-29}
%
% \maketitle
% \begin{documentation}
%
% \section{\pkg{pdfmanagement-firstaid} documentation}
% This code is temporary! It tries to patch commands of other packages or even
% replace package which are incompatible with the pdfmanagement,
% to remove clashes and test if everything works as expected.
% This code should disappear when packages adapt to the central interfaces.
%
% The package contains an number of sections for various packages. Every
% section can be disabled in (the first) \cs{DocumentMetadata} with
% |debug={firstaidoff={name1,name2,...},...}|.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage{pdfmanagement-firstaid}{2024-09-29}{0.96m}
  {LaTeX PDF management testphase bundle / firstaid-patches}

%<@@=pdfmanagement>
\clist_map_inline:nn 
  {pgf,xmp,xcolor,color,output,colorspace,luacolor}
  {
    \bool_new:c       { g_@@_firstaid_#1_bool }
    \bool_gset_true:c { g_@@_firstaid_#1_bool }
  }
\clist_map_inline:Nn \g_@@_firstaidoff_clist
  {
    \bool_if_exist:cT { g_@@_firstaid_#1_bool }
      {
        \bool_gset_false:c { g_@@_firstaid_#1_bool }
      }
  }
\msg_new:nnn  { pdfmanagement } { firstaid }
              { loading~pdfmanagement~firstaid~code~for~#1 }
\msg_new:nnn  { pdfmanagement } { firstaid-changed }
              { package~#1~has~changed.~Check~if~patch~is~still~valid! }
\msg_new:nnn  { pdfmanagement } { firstaid-disabled }
              { The~loading~of~package~#1~is~disabled.\\
                It~is~not~compatible~with~the~PDF~management. }
\msg_new:nnn  { pdfmanagement } { firstaid-too-old }
              { Package~#1~is~too~old~and~not~compatible.\\
                Get~at~least~version~#2.}

%    \end{macrocode}
% 
% \subsection{\pkg{color}}
%
%  \pkg{color} is not incompatible, but the new \pkg{hyperref} driver makes use of
%  \pkg{l3color} to set the colors. It is therefore necessary to patch some
%  internal \pkg{color} commands, so
%  that colors defined with its \cs{definecolor} command are known to \pkg{l3color} and
%  so \pkg{hyperref}. This only supports the color models from l3color (which covers
%  all standard model of the \pkg{color} package). The |named| model is mapped to
%  \cs{color_set:nn}.
%
%  This patch serves also as test to check if this change can be safely
%  added to \pkg{color} later.
%    \begin{macrocode}
\bool_if:NT \g_@@_firstaid_color_bool
  {
    \declare@file@substitution{color.sty}{color-ltx.sty}
  }
%    \end{macrocode}
%
% \subsection{\pkg{xcolor}}
%
%  \pkg{xcolor} is not incompatible, but the new \pkg{hyperref} driver makes use of
%  \pkg{l3color} to set the colors. It is therefore necessary to patch \pkg{xcolor}, so
%  that colors defined with its \cs{definecolor} command are known to \pkg{l3color} and
%  so \pkg{hyperref}. This only supports the color model from l3color. Colors defined
%  with the models |cmy| and |tHsb| are silently ignored.
%
%  The |named| model is mapped to \cs{color_set:nn}.
%
%    \begin{macrocode}
\bool_if:NT \g_@@_firstaid_xcolor_bool
  {
    \AddToHook
       {
         package/xcolor/after
       }
       {\RequirePackage{xcolor-patches-tmp-ltx}}
%    \end{macrocode}
%  The patch must before color definitions are loaded, which will happen in 
%  hooks in a newer xcolor:
%    \begin{macrocode}
    \DeclareHookRule{package/xcolor/after}{pdfmanagement-firstaid}{before}{xcolor}   
  }
%    \end{macrocode}
%
% \subsection{luacolor}
% 
%  The luacolor package doesn't take colors from l3color into account.
%  We add a fix, but only for pdf mode. luacolor can disable the 
%  code by clearing the hook if needed.
%  
%    \begin{macrocode}
\bool_lazy_all:nT 
  { 
    {\sys_if_engine_luatex_p:} 
    {\g_@@_firstaid_luacolor_bool} 
    {\sys_if_output_pdf_p:} 
  }
  {
    \AddToHook{package/luacolor/after}
     {
       \cs_set_protected:Npn \__color_backend_select:nn #1#2
        {
          \tl_set:Nn \l__color_backend_fill_tl {#1}
          \tl_set:Nn \l__color_backend_stroke_tl {#2}
          \LuaCol@setattribute\LuaCol@Attribute
            {
              \directlua
                {
                  oberdiek.luacolor.get("\luaescapestring{#1~#2}")
                }
            }
         }
       \cs_set_protected:Npn \__color_backend_fill:n #1
         {
          \tl_set:Nn \l__color_backend_fill_tl {#1}
          \LuaCol@setattribute\LuaCol@Attribute
            {
              \directlua
                {
                  oberdiek.luacolor.get("\luaescapestring{#1}")
                }
            } 
         }
       \cs_set_protected:Npn \__color_backend_stroke:n #1
         {
           \tl_set:Nn \l__color_backend_stroke_tl {#1}
           \LuaCol@setattribute\LuaCol@Attribute
             {
               \directlua
                 {
                   oberdiek.luacolor.get("\luaescapestring{#1}")
                 }
             } 
         }
       \cs_set_protected:Npn \__color_backend_reset:  {}
       \cs_set_eq:NN \__color_backend_fill_reset:   \__color_backend_reset:
       \cs_set_eq:NN \__color_backend_stroke_reset: \__color_backend_reset:
     }      
  }  
%    \end{macrocode}
% \subsection{\pkg{pgf}}
%
% In \pkg{pgf}, resource management is set up in the file |pgfutil-common.tex|.
% This then provides three functions for adding to the resources, all of which
% are objects:
% \begin{itemize}
%   \item \cs{pgfutil@addpdfresource@extgs}: Extended graphics state
%   \item \cs{pgfutil@addpdfresource@colorspaces}: Color spaces
%   \item \cs{pgfutil@addpdfresource@patterns}: Patterns
% \end{itemize}
%
% These resource dictionaries are used by adding entries in a cumulative sense;
% the macro layer deals with ensuring that each entry is only given once. Note
% that the objects themselves must be given only once for each page.
%
% To support these functions, there are a series of set-up macros which install
% these resources. That has to take place for every page: the exact route
% therefore depends on the driver.
%
% For the pdfmanagement project we need to avoid that pgf interferes in ExtGState,
% ColorSpace and Pattern (Shadings are added to the xform resources and so probably
% unproblematic for now).
% The actual patch is in a file hook guarded by the boolean,
% the rest of the code is always defined.
%    \begin{macrocode}

\bool_if:NT \g_@@_firstaid_pgf_bool
  {
    \msg_info:nnn{pdfmanagement }{firstaid}{pgf}
    \AddToHook
      {
        file/pgfrcs.sty/after
      }
      {
        \cs_set_eq:NN
          \@@_pgfori_pgfutil@setuppdfresources
          \pgfutil@setuppdfresources
        \def\pgfutil@setuppdfresources
          {
            \pdfmanagement_if_active:TF
              {
                \@@_pgf_sys_setuppdfresources_plain:
              }
              {
                \@@_pgfori_pgfutil@setuppdfresources
              }
         }
     }
  }
%\def\pgfutil@addpdfresource@extgs#1{\pgf@sys@addpdfresource@extgs@plain{#1}}
%\def\pgfutil@addpdfresource@colorspaces#1{\pgf@sys@addpdfresource@colorspaces@plain{#1}}
%\def\pgfutil@addpdfresource@patterns#1{\pgf@sys@addpdfresource@patterns@plain{#1}}
%\def\pgfutil@setuppdfresources{\pgf@sys@setuppdfresources@plain}
% \pgf@sys@pdf@possible@resources %used in xform
%Trying to patch pgf ..
\cs_new_protected:Npn \@@_pgf_sys_setuppdfresources_plain:
  {
   %objects are already created ...
    \def\pgf@sys@pdf@possible@resources
      {
        /ColorSpace~\pdf_object_ref:n {__pdf/Page/Resources/ColorSpace}
        /Pattern   ~\pdf_object_ref:n {__pdf/Page/Resources/Pattern}
        /ExtGState ~\pdf_object_ref:n {__pdf/Page/Resources/ExtGState}
      }
    \let\pgf@sys@pdf@check@resources=\relax%
    %not sure if needed, but perhaps the lists are used somewhere else ...
    \let\pgf@sys@pgf@resource@list@extgs=\pgfutil@empty%
    \let\pgf@sys@pgf@resource@list@patterns=\pgfutil@empty%
    \let\pgf@sys@pgf@resource@list@colorspaces=\pgfutil@empty%
    % the commands to add page resources
    \def\pgf@sys@addpdfresource@extgs@plain##1
      {
        %\exp_after:wN %for transparent which passes a command
          \@@_patch_pgfextgs:w ##1\q_stop
      }
    \def\pgf@sys@addpdfresource@patterns@plain##1
      {
        \@@_patch_pgfpatterns:w ##1\q_stop
      }
   \def\pgf@sys@addpdfresource@colorspaces@plain##1
      {
        \@@_patch_pgfcolorspaces:w ##1\q_stop
      }
  }

%\AtEndPreamble{\pgfutil@setuppdfresources}
% helper commands as pgf doesn't pass resources as two arguments
% code to add to the resources existing stuff in the format "/name value":
\cs_new:Npn \@@_split_dict_entry_aux:NNw #1 #2 /#3~#4\q_stop
  {
    \tl_set:Nn #1 {#3}
    \tl_set:Nn #2 {#4}
  }

\cs_generate_variant:Nn \tl_trim_spaces:n{V}
\cs_generate_variant:Nn \pdfmanagement_add:nnn {nee}
\cs_new:Npn \@@_patch_pgfextgs:w  #1/#2<<#3>>#4\q_stop
  {
    \tl_set:Ne\l_tmpa_tl{#2}
      \pdfmanagement_add:nee
        {Page/Resources/ExtGState}{\tl_trim_spaces:V\l_tmpa_tl}{<<#3 #4>>}
  }
\cs_new:Npn \@@_patch_pgfpatterns:w  #1/#2\space#3\q_stop
  {
     \pdfmanagement_add:nee
        {Page/Resources/Pattern}{\tl_trim_spaces:n{#2}}{#3}
  }
\cs_new:Npn \@@_patch_pgfcolorspaces:w  #1/#2[#3]#4\q_stop
  {
    \pdfmanagement_add:nee
      {Page/Resources/ColorSpace}{\tl_trim_spaces:n{#2}}{[#3]}
  }

%    \end{macrocode}
%
% \subsection{xmp}
% This handles the new xmp code.
%    \begin{macrocode}
\bool_if:NT \g_@@_firstaid_xmp_bool
 {
   \disable@package@load{hyperxmp}{\msg_warning:nnn{pdfmanagement}{firstaid-disabled}{hyperxmp}}
   \disable@package@load{pdfx}    {\msg_warning:nnn{pdfmanagement}{firstaid-disabled}{pdfx}}
   \AddToHook{package/doclicense/after}
    {
      \AtBeginDocument
        {
          \hypersetup
            {
              pdfcopyright  = {\doclicenseLongTextForHyperref},
              pdflicenseurl = {\doclicenseURL},
            }
        }
    }
 }
%</package>
%    \end{macrocode}
% \subsection{\pkg{colorspace}}
% This is rather difficult as no real places to inject patches
% at first a try to avoid that its ExtGState is missing:
% it can not be avoided to recreate the objects (and so to get duplicates)
% as colorspace uses temporary macros whose contents is lost.
%    \begin{macrocode}
%<*package>
\bool_if:NT \g_@@_firstaid_colorspace_bool
 {
    \AddToHook
      {
       package/colorspace/after
      }
      {\RequirePackage{colorspace-patches-tmp-ltx}}
 }
%</package>
%    \end{macrocode}%
%
% \end{documentation}
% \PrintIndex
