@@ -394,8 +394,7 @@ internal virtual PdfOutline GetOutlines(bool updateOutlines) {
394394 outlines = new PdfOutline ( GetDocument ( ) ) ;
395395 }
396396 else {
397- outlines = new PdfOutline ( OutlineRoot , outlineRoot , GetDocument ( ) ) ;
398- GetNextItem ( outlineRoot . GetAsDictionary ( PdfName . First ) , outlines , destsTree . GetNames ( ) ) ;
397+ ConstructOutlines ( outlineRoot , destsTree . GetNames ( ) ) ;
399398 }
400399 return outlines ;
401400 }
@@ -519,11 +518,70 @@ private void AddOutlineToPage(PdfOutline outline, IDictionary<String, PdfObject>
519518 }
520519 }
521520
522- private void GetNextItem ( PdfDictionary item , PdfOutline parent , IDictionary < String , PdfObject > names ) {
523- if ( null == item ) {
524- return ;
521+ /// <summary>Get the next outline of the current node in the outline tree by looking for a child or sibling node.
522+ /// </summary>
523+ /// <remarks>
524+ /// Get the next outline of the current node in the outline tree by looking for a child or sibling node.
525+ /// If there is no child or sibling of the current node
526+ /// <see cref="GetParentNextOutline(PdfDictionary)"/>
527+ /// is called to get a hierarchical parent's next node.
528+ /// <see langword="null"/>
529+ /// is returned if one does not exist.
530+ /// </remarks>
531+ /// <returns>
532+ /// the
533+ /// <see cref="PdfDictionary"/>
534+ /// object of the next outline if one exists,
535+ /// <see langword="null"/>
536+ /// otherwise.
537+ /// </returns>
538+ private PdfDictionary GetNextOutline ( PdfDictionary first , PdfDictionary next , PdfDictionary parent ) {
539+ if ( first != null ) {
540+ return first ;
541+ }
542+ else {
543+ if ( next != null ) {
544+ return next ;
545+ }
546+ else {
547+ return GetParentNextOutline ( parent ) ;
548+ }
549+ }
550+ }
551+
552+ /// <summary>Gets the parent's next outline of the current node.</summary>
553+ /// <remarks>
554+ /// Gets the parent's next outline of the current node.
555+ /// If the parent does not have a next we look at the grand parent, great-grand parent, etc until we find a next node or reach the root at which point
556+ /// <see langword="null"/>
557+ /// is returned to signify there is no next node present.
558+ /// </remarks>
559+ /// <returns>
560+ /// the
561+ /// <see cref="PdfDictionary"/>
562+ /// object of the next outline if one exists,
563+ /// <see langword="null"/>
564+ /// otherwise.
565+ /// </returns>
566+ private PdfDictionary GetParentNextOutline ( PdfDictionary parent ) {
567+ if ( parent == null ) {
568+ return null ;
525569 }
526- PdfOutline outline = new PdfOutline ( item . GetAsString ( PdfName . Title ) . ToUnicodeString ( ) , item , parent ) ;
570+ PdfDictionary current = null ;
571+ while ( current == null ) {
572+ current = parent . GetAsDictionary ( PdfName . Next ) ;
573+ if ( current == null ) {
574+ parent = parent . GetAsDictionary ( PdfName . Parent ) ;
575+ if ( parent == null ) {
576+ return null ;
577+ }
578+ }
579+ }
580+ return current ;
581+ }
582+
583+ private void AddOutlineToPage ( PdfOutline outline , PdfDictionary item , IDictionary < String , PdfObject > names
584+ ) {
527585 PdfObject dest = item . Get ( PdfName . Dest ) ;
528586 if ( dest != null ) {
529587 PdfDestination destination = PdfDestination . MakeDestination ( dest ) ;
@@ -535,7 +593,7 @@ private void GetNextItem(PdfDictionary item, PdfOutline parent, IDictionary<Stri
535593 PdfDictionary action = item . GetAsDictionary ( PdfName . A ) ;
536594 if ( action != null ) {
537595 PdfName actionType = action . GetAsName ( PdfName . S ) ;
538- //Check if it a go to action
596+ //Check if it is a go to action
539597 if ( PdfName . GoTo . Equals ( actionType ) ) {
540598 //Retrieve destination if it is.
541599 PdfObject destObject = action . Get ( PdfName . D ) ;
@@ -548,14 +606,43 @@ private void GetNextItem(PdfDictionary item, PdfOutline parent, IDictionary<Stri
548606 }
549607 }
550608 }
551- parent . GetAllChildren ( ) . Add ( outline ) ;
552- PdfDictionary processItem = item . GetAsDictionary ( PdfName . First ) ;
553- if ( processItem != null ) {
554- GetNextItem ( processItem , outline , names ) ;
609+ }
610+
611+ /// <summary>
612+ /// Constructs
613+ /// <see cref="outlines"/>
614+ /// iteratively
615+ /// </summary>
616+ private void ConstructOutlines ( PdfDictionary outlineRoot , IDictionary < String , PdfObject > names ) {
617+ if ( outlineRoot == null ) {
618+ return ;
555619 }
556- processItem = item . GetAsDictionary ( PdfName . Next ) ;
557- if ( processItem != null ) {
558- GetNextItem ( processItem , parent , names ) ;
620+ PdfDictionary first = outlineRoot . GetAsDictionary ( PdfName . First ) ;
621+ PdfDictionary current = first ;
622+ PdfDictionary next ;
623+ PdfDictionary parent ;
624+ Dictionary < PdfDictionary , PdfOutline > parentOutlineMap = new Dictionary < PdfDictionary , PdfOutline > ( ) ;
625+ outlines = new PdfOutline ( OutlineRoot , outlineRoot , GetDocument ( ) ) ;
626+ PdfOutline parentOutline = outlines ;
627+ parentOutlineMap . Put ( outlineRoot , parentOutline ) ;
628+ while ( current != null ) {
629+ first = current . GetAsDictionary ( PdfName . First ) ;
630+ next = current . GetAsDictionary ( PdfName . Next ) ;
631+ parent = current . GetAsDictionary ( PdfName . Parent ) ;
632+ parentOutline = parentOutlineMap . Get ( parent ) ;
633+ PdfOutline currentOutline = new PdfOutline ( current . GetAsString ( PdfName . Title ) . ToUnicodeString ( ) , current ,
634+ parentOutline ) ;
635+ AddOutlineToPage ( currentOutline , current , names ) ;
636+ parentOutline . GetAllChildren ( ) . Add ( currentOutline ) ;
637+ if ( first != null ) {
638+ parentOutlineMap . Put ( current , currentOutline ) ;
639+ }
640+ else {
641+ if ( current == parent . GetAsDictionary ( PdfName . Last ) ) {
642+ parentOutlineMap . JRemove ( parent ) ;
643+ }
644+ }
645+ current = GetNextOutline ( first , next , parent ) ;
559646 }
560647 }
561648 }
0 commit comments