@@ -22,6 +22,7 @@ This file is part of the iText (R) project.
22
22
*/
23
23
package com .itextpdf .layout .renderer ;
24
24
25
+ import com .itextpdf .commons .datastructures .Tuple2 ;
25
26
import com .itextpdf .commons .utils .MessageFormatUtil ;
26
27
import com .itextpdf .io .logs .IoLogMessageConstant ;
27
28
import com .itextpdf .io .util .NumberUtil ;
@@ -37,12 +38,17 @@ This file is part of the iText (R) project.
37
38
import com .itextpdf .kernel .pdf .PdfName ;
38
39
import com .itextpdf .kernel .pdf .PdfNumber ;
39
40
import com .itextpdf .kernel .pdf .PdfPage ;
41
+ import com .itextpdf .kernel .pdf .PdfVersion ;
40
42
import com .itextpdf .kernel .pdf .action .PdfAction ;
41
43
import com .itextpdf .kernel .pdf .annot .PdfAnnotation ;
42
44
import com .itextpdf .kernel .pdf .annot .PdfLinkAnnotation ;
43
45
import com .itextpdf .kernel .pdf .canvas .CanvasArtifact ;
44
46
import com .itextpdf .kernel .pdf .canvas .PdfCanvas ;
45
47
import com .itextpdf .kernel .pdf .extgstate .PdfExtGState ;
48
+ import com .itextpdf .kernel .pdf .navigation .PdfStructureDestination ;
49
+ import com .itextpdf .kernel .pdf .tagging .PdfStructElem ;
50
+ import com .itextpdf .kernel .pdf .tagutils .TagStructureContext ;
51
+ import com .itextpdf .kernel .pdf .tagutils .TagTreePointer ;
46
52
import com .itextpdf .kernel .pdf .xobject .PdfFormXObject ;
47
53
import com .itextpdf .kernel .pdf .xobject .PdfXObject ;
48
54
import com .itextpdf .layout .Document ;
@@ -135,6 +141,10 @@ public abstract class AbstractRenderer implements IRenderer {
135
141
136
142
private static final int ARC_QUARTER_CLOCKWISE_EXTENT = -90 ;
137
143
144
+ // For autoport
145
+ private static final Tuple2 <String , PdfDictionary > CHECK_TUPLE2_TYPE =
146
+ new Tuple2 <String , PdfDictionary >("" , new PdfDictionary ());
147
+
138
148
protected List <IRenderer > childRenderers = new ArrayList <>();
139
149
protected List <IRenderer > positionedRenderers = new ArrayList <>();
140
150
protected IPropertyContainer modelElement ;
@@ -1918,8 +1928,22 @@ protected void applyRelativePositioningTranslation(boolean reverse) {
1918
1928
}
1919
1929
1920
1930
protected void applyDestination (PdfDocument document ) {
1921
- String destination = this .<String >getProperty (Property .DESTINATION );
1922
- if (destination != null ) {
1931
+ Object destination = this .<Object >getProperty (Property .DESTINATION );
1932
+ if (destination == null ) {
1933
+ return ;
1934
+ }
1935
+ String destinationName = null ;
1936
+ PdfDictionary linkActionDict = null ;
1937
+ if (destination instanceof String ) {
1938
+ destinationName = (String )destination ;
1939
+ } else if (CHECK_TUPLE2_TYPE .getClass ().equals (destination .getClass ())) {
1940
+ // 'If' above is the only autoportable way it seems
1941
+ Tuple2 <String , PdfDictionary > destTuple = (Tuple2 <String , PdfDictionary >)destination ;
1942
+ destinationName = destTuple .getFirst ();
1943
+ linkActionDict = destTuple .getSecond ();
1944
+ }
1945
+
1946
+ if (destinationName != null ) {
1923
1947
int pageNumber = occupiedArea .getPageNumber ();
1924
1948
if (pageNumber < 1 || pageNumber > document .getNumberOfPages ()) {
1925
1949
Logger logger = LoggerFactory .getLogger (AbstractRenderer .class );
@@ -1935,10 +1959,19 @@ protected void applyDestination(PdfDocument document) {
1935
1959
array .add (new PdfNumber (occupiedArea .getBBox ().getX ()));
1936
1960
array .add (new PdfNumber (occupiedArea .getBBox ().getY () + occupiedArea .getBBox ().getHeight ()));
1937
1961
array .add (new PdfNumber (0 ));
1938
- document .addNamedDestination (destination , array .makeIndirect (document ));
1962
+ document .addNamedDestination (destinationName , array .makeIndirect (document ));
1963
+ }
1939
1964
1940
- deleteProperty (Property .DESTINATION );
1965
+ final boolean isPdf20 = document .getPdfVersion ().compareTo (PdfVersion .PDF_2_0 ) >= 0 ;
1966
+ if (linkActionDict != null && isPdf20 && document .isTagged ()) {
1967
+ TagStructureContext context = document .getTagStructureContext ();
1968
+ TagTreePointer tagPointer = context .getAutoTaggingPointer ();
1969
+ PdfStructElem structElem = context .getPointerStructElem (tagPointer );
1970
+ PdfStructureDestination dest = PdfStructureDestination .createFit (structElem );
1971
+ linkActionDict .put (PdfName .SD , dest .getPdfObject ());
1941
1972
}
1973
+
1974
+ deleteProperty (Property .DESTINATION );
1942
1975
}
1943
1976
1944
1977
protected void applyAction (PdfDocument document ) {
@@ -1962,32 +1995,35 @@ protected void applyAction(PdfDocument document) {
1962
1995
protected void applyLinkAnnotation (PdfDocument document ) {
1963
1996
Logger logger = LoggerFactory .getLogger (AbstractRenderer .class );
1964
1997
PdfLinkAnnotation linkAnnotation = this .<PdfLinkAnnotation >getProperty (Property .LINK_ANNOTATION );
1965
- if (linkAnnotation != null ) {
1966
- int pageNumber = occupiedArea .getPageNumber ();
1967
- if (pageNumber < 1 || pageNumber > document .getNumberOfPages ()) {
1968
- String logMessageArg = "Property.LINK_ANNOTATION, which specifies a link associated with this element content area, see com.itextpdf.layout.element.Link." ;
1969
- logger .warn (MessageFormatUtil .format (
1970
- IoLogMessageConstant .UNABLE_TO_APPLY_PAGE_DEPENDENT_PROP_UNKNOWN_PAGE_ON_WHICH_ELEMENT_IS_DRAWN ,
1971
- logMessageArg ));
1972
- return ;
1973
- }
1974
- // If an element with a link annotation occupies more than two pages,
1975
- // then a NPE might occur, because of the annotation being partially flushed.
1976
- // That's why we create and use an annotation's copy.
1977
- PdfDictionary oldAnnotation = (PdfDictionary ) linkAnnotation .getPdfObject ().clone ();
1978
- linkAnnotation = (PdfLinkAnnotation ) PdfAnnotation .makeAnnotation (oldAnnotation );
1979
- Rectangle pdfBBox = calculateAbsolutePdfBBox ();
1980
- linkAnnotation .setRectangle (new PdfArray (pdfBBox ));
1981
-
1982
- PdfPage page = document .getPage (pageNumber );
1983
- // TODO DEVSIX-1655 This check is necessary because, in some cases, our renderer's hierarchy may contain
1984
- // a renderer from the different page that was already flushed
1985
- if (page .isFlushed ()) {
1986
- logger .error (MessageFormatUtil .format (
1987
- IoLogMessageConstant .PAGE_WAS_FLUSHED_ACTION_WILL_NOT_BE_PERFORMED , "link annotation applying" ));
1988
- } else {
1989
- page .addAnnotation (linkAnnotation );
1990
- }
1998
+ if (linkAnnotation == null ) {
1999
+ return ;
2000
+ }
2001
+
2002
+ int pageNumber = occupiedArea .getPageNumber ();
2003
+ if (pageNumber < 1 || pageNumber > document .getNumberOfPages ()) {
2004
+ String logMessageArg = "Property.LINK_ANNOTATION, which specifies a link associated with this element content area, see com.itextpdf.layout.element.Link." ;
2005
+ logger .warn (MessageFormatUtil .format (
2006
+ IoLogMessageConstant .UNABLE_TO_APPLY_PAGE_DEPENDENT_PROP_UNKNOWN_PAGE_ON_WHICH_ELEMENT_IS_DRAWN ,
2007
+ logMessageArg ));
2008
+ return ;
2009
+ }
2010
+
2011
+ // If an element with a link annotation occupies more than two pages,
2012
+ // then a NPE might occur, because of the annotation being partially flushed.
2013
+ // That's why we create and use an annotation's copy.
2014
+ PdfDictionary newAnnotation = (PdfDictionary ) linkAnnotation .getPdfObject ().clone ();
2015
+ linkAnnotation = (PdfLinkAnnotation ) PdfAnnotation .makeAnnotation (newAnnotation );
2016
+ Rectangle pdfBBox = calculateAbsolutePdfBBox ();
2017
+ linkAnnotation .setRectangle (new PdfArray (pdfBBox ));
2018
+
2019
+ PdfPage page = document .getPage (pageNumber );
2020
+ // TODO DEVSIX-1655 This check is necessary because, in some cases, our renderer's hierarchy may contain
2021
+ // a renderer from the different page that was already flushed
2022
+ if (page .isFlushed ()) {
2023
+ logger .error (MessageFormatUtil .format (
2024
+ IoLogMessageConstant .PAGE_WAS_FLUSHED_ACTION_WILL_NOT_BE_PERFORMED , "link annotation applying" ));
2025
+ } else {
2026
+ page .addAnnotation (linkAnnotation );
1991
2027
}
1992
2028
}
1993
2029
0 commit comments