8

There seems to be a problem with tikzmark and xelatex. Ulrike Fischer from the xetex list helped to track this down. The following code does not work when compiled with xelatex but produces the expected result when compiled with pdflatex:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark}


\begin{document}

x\pgfmark{tA}some text \pgfmark{tB} some text
\begin{tikzpicture}[remember picture]
\draw (0,0)node (A){A} rectangle (1,1)node (B){B};
\end{tikzpicture}
\begin{tikzpicture}[remember picture]
\draw (0,0)node {\pgfmark{nA}} rectangle (1,1)node {\pgfmark{nB}};
\end{tikzpicture}

\vspace{3cm}\centering
\begin{tikzpicture}[overlay,remember picture]
\draw[red,->] (0,0)--(pic cs:tA) (0,0)--(pic cs:tB);
\draw[blue,->](0,0)--(pic cs:nA) (0,0)--(pic cs:nB); %nB faulty
\draw[green,->](0,0)--(A) (0,0)--(B);
\end{tikzpicture}

\end{document} 

Is there a quick fix to this? The problem appeared after upgrading from texlive 2013 to texlive 2014.

Edit: The original code used \subnodebut it doesn't work either:

\documentclass{article}
\usepackage{forest}

\usetikzlibrary{tikzmark}


\begin{document}


\begin{forest}
[V
[\subnode{ap1}{AP}
[ungewaschen]]
[V{[ \subnode{arg11}{1}, \subnode{arg12}{2} ]}
[isst]]]
\end{forest}
\begin{forest}
[V
[\subnode{ap2}{AP}
[ungewaschen]]
[V{[\subnode{arg21}{1} ]}]]
\end{forest}
\begin{tikzpicture}[overlay,remember picture]
%% this works with tikzmark
%% \draw[->, bend angle=40, bend left] ($(pic cs:ap1)+(1ex,2ex)$) to($(pic cs:arg11)+(1ex,2.5ex)$);
%% \draw[->, bend angle=40, bend left] ($(pic cs:ap1)+(1ex,2ex)$) to($(pic cs:arg12)+(1ex,2.5ex)$); % 1ex links, 2ex hoch
%% %
%% this used to work with subnode in texlive 2013 but is broken now
%% \draw[->, bend angle=40, bend left] ($(pic cs:ap2)+(1ex,2ex)$) to($(pic cs:arg21)+(1ex,2.5ex)$);
\draw[->, bend angle=40, bend left] (ap1.north) to (arg11.north);
\draw[->, bend angle=40, bend left] (ap1.north) to (arg12.north); 
%
\draw[->, bend angle=40, bend left] (ap2.north) to (arg21.north);
\end{tikzpicture}


\end{document}

The AP should be connected to 1 and 2 respectively, but the arrows are up in the air.

enter image description here

Stefan Müller
  • 6,901
  • 3
  • 29
  • 61
  • 2
    For this example only, \documentclass{article} \newcount\pdftexversion \pdftexversion140 \def\pgfsysdriver{pgfsys-dvipdfm.def} \usepackage{tikz} \usetikzlibrary{tikzmark} \begin{document} ... \end{document} gives correct result. However, experts should investigate pgfsys-xetex.def and pgfsys-dvipdfmx.def which are used in usual usage of xelatex. – Akira Kakuto Feb 23 '15 at 06:01
  • Thanks! Would this work for all similar problems? And whom should I contact? The tikzmark package maintainer? xelatex people? pgfmaintainers? – Stefan Müller Feb 23 '15 at 16:39
  • Well it looks like a problem in the driver, probably with the definition of \pgfsys@hboxsynced. It is not possible to save a position inside a node. E.g. node {\pdfsavepos\write\@auxout{\@percentchar\the\pdflastxpos}} always store the zero coordinate. So probably the pgf maintainer should be informed. – Ulrike Fischer Feb 23 '15 at 18:47
  • Thanks Ulrike. I have confirmed that if I use \pgfsys@hboxsynced in pgfsys-common-pdf-via-dvi.def instead of that in pgfsys-dvipdfmx.def, the example becomes correct: \documentclass{article} \usepackage{tikz} \usetikzlibrary{tikzmark} \makeatletter \def\pgfsys@hboxsynced#1{% ... \makeatother \begin{document} ... \end{document}. However, the code must have been rewritten in pgfsys-dvipdfmx.def because of some reason, so pgf maintainer should be informed. – Akira Kakuto Feb 24 '15 at 03:47
  • @StefanMüller: Did you report this problem? I don't find a ticket https://sourceforge.net/p/pgf/bugs/. – Ulrike Fischer Feb 25 '15 at 09:11
  • I reported it now. Thanks for pointing out the location for bug reports. – Stefan Müller Feb 25 '15 at 10:59
  • 1
    Well you didn't invest much time in this bug report. Bug reports can lurk around quite long and so imho they should be self contained. Links to discussions which could be edited or deleted at any time can be inserted as additional material but are not a substitute. – Ulrike Fischer Feb 25 '15 at 13:09
  • 2
    For your example code then you wouldn't need \pgfmark inside the node as you could give a name to the node and use that instead. \tikzmark and \pgfmark shouldn't be used inside an existing tikzpicture. I wrote the \subnode command to avoid this problem since lots of people seemed to insist on using \tikzmark inside a tikzpicture! – Andrew Stacey Mar 29 '15 at 20:41
  • @LoopSpace Though that doesn't solve the problem, does it? – cfr Jul 15 '15 at 17:37
  • @cfr Well, it does. If I change the node {\pgfmark{nA} to coordinate (nA) and adjust the line drawing code accordingly then it works. So it solves the problem in that it gives code that works as expected. As I said above, \tikzmark and \pgfmark should not be used inside a tikzpicture because that is effectively putting a tikzpicture inside a tikzpicture and this Should Not Be Done. So while there may well be an underlying bug that should be squished, as far as the MWE in this question it doesn't need squishing to get code that will do what is wanted. – Andrew Stacey Jul 15 '15 at 20:48
  • @LoopSpace It wasn't meant as a criticism of that point. Only that switching to \subnode does not work around the bug which causes tikzmark to not work with XeTeX without the workaround mentioned in the comments above. That's not tikzmark's fault, of course. (At least, it certainly doesn't seem to be.) See this comment for a case where the solution uses \subnode but the workaround is still required for XeTeX. – cfr Jul 15 '15 at 20:58
  • @LoopSpace I edited my question. \subnode seems to be broken in texlive 2015. – Stefan Müller Sep 04 '15 at 16:13
  • It would be nice to have a link to the report ... – cfr Nov 19 '16 at 14:00
  • @UlrikeFischer I tried to improve it a bit. If you have any further suggestions, could you perhaps add them in? I have tried to provide a minimal example which should work (unlike the existing one which nests tikzpictures) by using \subnode, but I'm not sure how to eliminate the use of tikzmark completely. I've also tried to reflect the discussion here and in the more recent question about this. – cfr Nov 20 '16 at 00:12

1 Answers1

5

Thanks to @UlrikeFischer and @AkiraKakuto's comment.


In PGF, the command \pgfsys@hboxsynced is used to put some text at a specified position. There are two ways to do so:

  • work hard with \hskip and \raise;

  • tell the PDF renderers to do the dirty work for you.


When LaTeX is used, pgfsys-pdftex.def implements \pgfsys@hboxsynced by the first method. And as @AkiraKakuto suggested, the implementation in pgfsys-common-pdf-via-dvi.def uses the first method as well.

However when XeLaTeX is used, the implementation in pgfsys-common-pdf-via-dvi.def is overwritten by pgfsys-dvipdfmx.def, which uses the second method. Now all texts are put at the origin together with some positioning information. PDF renderers will recognize these information and shift those texts to the right place. However \tikzmark and any other marking macro will not work anymore because what you are marking is the origin.


Despite that we can implement \pgfsys@hboxsynced by ourselves, which need a bunch of knowledge regarding XeLaTeX, we might play around with the positioning information.

Notice that the positioning information is processed by \pgfsys@transformcm. So we might try

\let\temp=\pgfsys@transformcm
\def\pgfsys@transformcm#1#2#3#4#5#6{
    \rememberxshift{#5}
    \rememberyshift{#6}
    \temp{#1}{#2}{#3}{#4}{#5}{#6}
}

And then we can fix the \tikzmark or whatever marking macro by the information.


More technical details

  • \pgf@pt@x is the dimension for x-shift.
  • so \hskip\pgf@pt@x belongs to the first method.
  • on the other hand, anything like \pgflowlevelsynccm, \pgfsys@invoke, \special, is related to the second method.
  • A minimal example is
    \tikz[overlay]\node[xshift=100]{Some \pgfmark{X} Text};
    \tikz[overlay,remember picture]\draw(pic cs:X)circle(.1);
    
  • A ever simpler example is (we are not even inside a pgfpicture)
    \newbox\mybox
    \setbox\mybox=\hbox{Some \pgfmark{Y} Text 2}
    \pgftransformxshift{100}
    \pgfsys@hboxsynced\mybox
    

    \tikz[overlay,remember picture]\draw(pic cs:Y)circle(.1);

Symbol 1
  • 36,855