xref: /AOO41X/main/sw/source/core/text/EnhancedPDFExportHelper.cxx (revision 2ab8e59e44d5950d9c68a72781ee6b8163bb05bd)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <com/sun/star/embed/XEmbeddedObject.hpp>
27 #include <com/sun/star/i18n/ScriptType.hdl>
28 #include <EnhancedPDFExportHelper.hxx>
29 #include <hintids.hxx>
30 
31 #include <vcl/outdev.hxx>
32 #include <tools/multisel.hxx>
33 #include <editeng/adjitem.hxx>
34 #include <editeng/lrspitem.hxx>
35 #include <editeng/langitem.hxx>
36 #include <editeng/scripttypeitem.hxx>
37 #include <tools/urlobj.hxx>
38 #include <svl/zforlist.hxx>
39 #include <swatrset.hxx>
40 #include <frmatr.hxx>
41 #include <paratr.hxx>
42 #include <ndtxt.hxx>
43 #include <ndole.hxx>
44 #include <section.hxx>
45 #include <tox.hxx>
46 #include <fmtfld.hxx>
47 #include <txtinet.hxx>
48 #include <fmtinfmt.hxx>
49 #include <fchrfmt.hxx>
50 #include <charfmt.hxx>
51 #include <fmtanchr.hxx>
52 #include <fmturl.hxx>
53 #include <editsh.hxx>
54 #include <viscrs.hxx>
55 #include <txtfld.hxx>
56 #include <reffld.hxx>
57 #include <doc.hxx>
58 #include <docary.hxx>
59 #include <crsskip.hxx>
60 #include <mdiexp.hxx>
61 #include <docufld.hxx>
62 #include <ftnidx.hxx>
63 #include <txtftn.hxx>
64 #include <fmtftn.hxx>
65 #include <rootfrm.hxx>
66 #include <pagefrm.hxx>
67 #include <txtfrm.hxx>
68 #include <tabfrm.hxx>
69 #include <rowfrm.hxx>
70 #include <cellfrm.hxx>
71 #include <sectfrm.hxx>
72 #include <flyfrm.hxx>
73 #include <notxtfrm.hxx>
74 #include <porfld.hxx>
75 #include <SwStyleNameMapper.hxx>
76 #include <itrpaint.hxx>
77 #include "i18npool/mslangid.hxx"
78 #include <IMark.hxx>
79 #include <SwNodeNum.hxx>
80 #include <switerator.hxx>
81 #include <stack>
82 
83 #include <tools/globname.hxx>
84 
85 using namespace ::com::sun::star;
86 
87 //
88 // Some static data structures
89 //
90 TableColumnsMap SwEnhancedPDFExportHelper::aTableColumnsMap;
91 LinkIdMap SwEnhancedPDFExportHelper::aLinkIdMap;
92 NumListIdMap SwEnhancedPDFExportHelper::aNumListIdMap;
93 NumListBodyIdMap SwEnhancedPDFExportHelper::aNumListBodyIdMap;
94 FrmTagIdMap SwEnhancedPDFExportHelper::aFrmTagIdMap;
95 
96 LanguageType SwEnhancedPDFExportHelper::eLanguageDefault = 0;
97 
98 #ifdef DBG_UTIL
99 
100 static std::vector< sal_uInt16 > aStructStack;
101 
102 void lcl_DBGCheckStack()
103 {
104     /* NonStructElement = 0     Document = 1        Part = 2
105      * Article = 3              Section = 4         Division = 5
106      * BlockQuote = 6           Caption = 7         TOC = 8
107      * TOCI = 9                 Index = 10          Paragraph = 11
108      * Heading = 12             H1-6 = 13 - 18      List = 19
109      * ListItem = 20            LILabel = 21        LIBody = 22
110      * Table = 23               TableRow = 24       TableHeader = 25
111      * TableData = 26           Span = 27           Quote = 28
112      * Note = 29                Reference = 30      BibEntry = 31
113      * Code = 32                Link = 33           Figure = 34
114      * Formula = 35             Form = 36           Continued frame = 99
115      */
116 
117     sal_uInt16 nElement;
118     std::vector< sal_uInt16 >::iterator aIter;
119     for ( aIter = aStructStack.begin(); aIter != aStructStack.end(); ++aIter )
120     {
121         nElement = *aIter;
122     }
123 }
124 
125 #endif
126 
127 namespace
128 {
129 // ODF Style Names:
130 const String aTableHeadingName  = String::CreateFromAscii("Table Heading");
131 const String aQuotations        = String::CreateFromAscii("Quotations");
132 const String aCaption           = String::CreateFromAscii("Caption");
133 const String aHeading           = String::CreateFromAscii("Heading");
134 const String aQuotation         = String::CreateFromAscii("Quotation");
135 const String aSourceText        = String::CreateFromAscii("Source Text");
136 
137 // PDF Tag Names:
138 const String aDocumentString = String::CreateFromAscii("Document");
139 const String aDivString = String::CreateFromAscii("Div");
140 const String aSectString = String::CreateFromAscii("Sect");
141 const String aHString = String::CreateFromAscii("H");
142 const String aH1String = String::CreateFromAscii("H1");
143 const String aH2String = String::CreateFromAscii("H2");
144 const String aH3String = String::CreateFromAscii("H3");
145 const String aH4String = String::CreateFromAscii("H4");
146 const String aH5String = String::CreateFromAscii("H5");
147 const String aH6String = String::CreateFromAscii("H6");
148 const String aListString = String::CreateFromAscii("L");
149 const String aListItemString = String::CreateFromAscii("LI");
150 const String aListBodyString = String::CreateFromAscii("LBody");
151 const String aBlockQuoteString = String::CreateFromAscii("BlockQuote");
152 const String aCaptionString = String::CreateFromAscii("Caption");
153 const String aIndexString = String::CreateFromAscii("Index");
154 const String aTOCString = String::CreateFromAscii("TOC");
155 const String aTOCIString = String::CreateFromAscii("TOCI");
156 const String aTableString = String::CreateFromAscii("Table");
157 const String aTRString = String::CreateFromAscii("TR");
158 const String aTDString = String::CreateFromAscii("TD");
159 const String aTHString = String::CreateFromAscii("TH");
160 const String aBibEntryString = String::CreateFromAscii("BibEntry");
161 const String aQuoteString = String::CreateFromAscii("Quote");
162 const String aSpanString = String::CreateFromAscii("Span");
163 const String aCodeString = String::CreateFromAscii("Code");
164 const String aFigureString = String::CreateFromAscii("Figure");
165 const String aFormulaString = String::CreateFromAscii("Formula");
166 const String aLinkString = String::CreateFromAscii("Link");
167 const String aNoteString = String::CreateFromAscii("Note");
168 const String aEmptyString = String::CreateFromAscii("");
169 
170 // returns true if first paragraph in cell frame has 'table heading' style
171 bool lcl_IsHeadlineCell( const SwCellFrm& rCellFrm )
172 {
173     bool bRet = false;
174 
175     const SwCntntFrm *pCnt = rCellFrm.ContainsCntnt();
176     if ( pCnt && pCnt->IsTxtFrm() )
177     {
178         const SwTxtNode* pTxtNode = static_cast<const SwTxtFrm*>(pCnt)->GetTxtNode();
179         const SwFmt* pTxtFmt = pTxtNode->GetFmtColl();
180 
181         String sStyleName;
182         SwStyleNameMapper::FillProgName( pTxtFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
183         bRet = sStyleName == aTableHeadingName;
184     }
185 
186     return bRet;
187 }
188 
189 // List all frames for which the NonStructElement tag is set:
190 bool lcl_IsInNonStructEnv( const SwFrm& rFrm )
191 {
192     bool bRet = false;
193 
194     if ( 0 != rFrm.FindFooterOrHeader() &&
195            !rFrm.IsHeaderFrm() && !rFrm.IsFooterFrm() )
196     {
197         bRet = true;
198     }
199     else if ( rFrm.IsInTab() && !rFrm.IsTabFrm() )
200     {
201         const SwTabFrm* pTabFrm = rFrm.FindTabFrm();
202         if ( rFrm.GetUpper() != pTabFrm &&
203              pTabFrm->IsFollow() && pTabFrm->IsInHeadline( rFrm ) )
204              bRet = true;
205     }
206 
207     return bRet;
208 }
209 
210 // Generate key from frame for reopening tags:
211 void* lcl_GetKeyFromFrame( const SwFrm& rFrm )
212 {
213     void* pKey = 0;
214 
215     if ( rFrm.IsPageFrm() )
216         pKey = (void*)static_cast<const SwPageFrm&>(rFrm).GetFmt()->getIDocumentSettingAccess();
217     else if ( rFrm.IsTxtFrm() )
218         pKey = (void*)static_cast<const SwTxtFrm&>(rFrm).GetTxtNode();
219     else if ( rFrm.IsSctFrm() )
220         pKey = (void*)static_cast<const SwSectionFrm&>(rFrm).GetSection();
221     else if ( rFrm.IsTabFrm() )
222         pKey = (void*)static_cast<const SwTabFrm&>(rFrm).GetTable();
223     else if ( rFrm.IsRowFrm() )
224         pKey = (void*)static_cast<const SwRowFrm&>(rFrm).GetTabLine();
225     else if ( rFrm.IsCellFrm() )
226     {
227         const SwTabFrm* pTabFrm = rFrm.FindTabFrm();
228         const SwTable* pTable = pTabFrm->GetTable();
229         pKey = (void*) & static_cast<const SwCellFrm&>(rFrm).GetTabBox()->FindStartOfRowSpan( *pTable );
230     }
231 
232     return pKey;
233 }
234 
235 bool lcl_HasPreviousParaSameNumRule( const SwTxtNode& rNode )
236 {
237     bool bRet = false;
238     SwNodeIndex aIdx( rNode );
239     const SwDoc* pDoc = rNode.GetDoc();
240     const SwNodes& rNodes = pDoc->GetNodes();
241     const SwNode* pNode = &rNode;
242     const SwNumRule* pNumRule = rNode.GetNumRule();
243 
244     while (! (pNode == rNodes.DocumentSectionStartNode((SwNode*)&rNode) ) )
245     {
246         --aIdx;
247 
248         if (aIdx.GetNode().IsTxtNode())
249         {
250             const SwTxtNode* pPrevTxtNd = aIdx.GetNode().GetTxtNode();
251             const SwNumRule * pPrevNumRule = pPrevTxtNd->GetNumRule();
252 
253             // We find the previous text node. Now check, if the previous text node
254             // has the same numrule like rNode:
255             if ( (pPrevNumRule == pNumRule) &&
256 				 (!pPrevTxtNd->IsOutline() == !rNode.IsOutline()))
257                 bRet = true;
258 
259             break;
260         }
261 
262         pNode = &aIdx.GetNode();
263     }
264     return bRet;
265 }
266 
267 } // end namespace
268 
269 /*
270  * SwTaggedPDFHelper::SwTaggedPDFHelper()
271  */
272 SwTaggedPDFHelper::SwTaggedPDFHelper( const Num_Info* pNumInfo,
273                                       const Frm_Info* pFrmInfo,
274                                       const Por_Info* pPorInfo,
275                                       OutputDevice& rOut )
276   : nEndStructureElement( 0 ),
277     nRestoreCurrentTag( -1 ),
278     mpNumInfo( pNumInfo ),
279     mpFrmInfo( pFrmInfo ),
280     mpPorInfo( pPorInfo )
281 {
282     mpPDFExtOutDevData =
283         PTR_CAST( vcl::PDFExtOutDevData, rOut.GetExtOutDevData() );
284 
285     if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() )
286     {
287 #ifdef DBG_UTIL
288         sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement();
289         lcl_DBGCheckStack();
290 #endif
291         if ( mpNumInfo )
292             BeginNumberedListStructureElements();
293         else if ( mpFrmInfo )
294             BeginBlockStructureElements();
295         else if ( mpPorInfo )
296             BeginInlineStructureElements();
297         else
298             BeginTag( vcl::PDFWriter::NonStructElement, aEmptyString );
299 
300 #ifdef DBG_UTIL
301         nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement();
302         lcl_DBGCheckStack();
303 #endif
304     }
305 }
306 
307 
308 /*
309  * SwTaggedPDFHelper::~SwTaggedPDFHelper()
310  */
311 SwTaggedPDFHelper::~SwTaggedPDFHelper()
312 {
313     if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() )
314     {
315 #ifdef DBG_UTIL
316         sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement();
317         lcl_DBGCheckStack();
318 #endif
319         EndStructureElements();
320 
321 #ifdef DBG_UTIL
322         nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement();
323         lcl_DBGCheckStack();
324 #endif
325 
326     }
327 }
328 
329 /*
330  * SwTaggedPDFHelper::CheckReopenTag()
331  */
332 bool SwTaggedPDFHelper::CheckReopenTag()
333 {
334     bool bRet = false;
335     sal_Int32 nReopenTag = -1;
336     bool bContinue = false; // in some cases we just have to reopen a tag without early returning
337 
338     if ( mpFrmInfo )
339     {
340         const SwFrm& rFrm = mpFrmInfo->mrFrm;
341         const SwFrm* pKeyFrm = 0;
342         void* pKey = 0;
343 
344         // Reopen an existing structure element if
345         // - rFrm is not the first page frame (reopen Document tag)
346         // - rFrm is a follow frame (reopen Master tag)
347         // - rFrm is a fly frame anchored at content (reopen Anchor paragraph tag)
348         // - rFrm is a fly frame anchord at page (reopen Document tag)
349         // - rFrm is a follow flow row (reopen TableRow tag)
350         // - rFrm is a cell frame in a follow flow row (reopen TableData tag)
351         if ( ( rFrm.IsPageFrm() && static_cast<const SwPageFrm&>(rFrm).GetPrev() ) ||
352              ( rFrm.IsFlowFrm() && SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() ) ||
353              ( rFrm.IsRowFrm() && rFrm.IsInFollowFlowRow() ) ||
354              ( rFrm.IsCellFrm() && const_cast<SwFrm&>(rFrm).GetPrevCellLeaf( MAKEPAGE_NONE ) ) )
355         {
356             pKeyFrm = &rFrm;
357         }
358         else if ( rFrm.IsFlyFrm() )
359         {
360             const SwFmtAnchor& rAnchor =
361                 static_cast<const SwFlyFrm*>(&rFrm)->GetFmt()->GetAnchor();
362             if ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
363                 (FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
364                 (FLY_AT_PAGE == rAnchor.GetAnchorId()))
365             {
366                 pKeyFrm = static_cast<const SwFlyFrm&>(rFrm).GetAnchorFrm();
367                 bContinue = true;
368             }
369         }
370 
371         if ( pKeyFrm )
372         {
373             pKey = lcl_GetKeyFromFrame( *pKeyFrm );
374 
375             if ( pKey )
376             {
377                 FrmTagIdMap& rFrmTagIdMap = SwEnhancedPDFExportHelper::GetFrmTagIdMap();
378                 const FrmTagIdMap::const_iterator aIter =  rFrmTagIdMap.find( pKey );
379                 nReopenTag = (*aIter).second;
380             }
381         }
382     }
383 
384     if ( -1 != nReopenTag )
385     {
386         nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement();
387         const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag );
388         ASSERT( bSuccess, "Failed to reopen tag" )
389 
390 #ifdef DBG_UTIL
391         aStructStack.push_back( 99 );
392 #endif
393 
394         bRet = bSuccess;
395     }
396 
397     return bRet && !bContinue;
398 }
399 
400 
401 /*
402  * SwTaggedPDFHelper::CheckRestoreTag()
403  */
404 bool SwTaggedPDFHelper::CheckRestoreTag() const
405 {
406     bool bRet = false;
407     if ( nRestoreCurrentTag != -1 )
408     {
409         const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nRestoreCurrentTag );
410         (void)bSuccess;
411         ASSERT( bSuccess, "Failed to restore reopened tag" )
412 
413 #ifdef DBG_UTIL
414         aStructStack.pop_back();
415 #endif
416 
417         bRet = true;
418     }
419 
420     return bRet;
421 }
422 
423 
424 /*
425  * SwTaggedPDFHelper::BeginTag()
426  */
427 void SwTaggedPDFHelper::BeginTag( vcl::PDFWriter::StructElement eType, const String& rString )
428 {
429     // write new tag
430     const sal_Int32 nId = mpPDFExtOutDevData->BeginStructureElement( eType, rtl::OUString( rString ) );
431     ++nEndStructureElement;
432 
433 #ifdef DBG_UTIL
434     aStructStack.push_back( static_cast<sal_uInt16>(eType) );
435 #endif
436 
437     // Store the id of the current structure element if
438     // - it is a list structure element
439     // - it is a list body element with children
440     // - rFrm is the first page frame
441     // - rFrm is a master frame
442     // - rFrm has objects anchored to it
443     // - rFrm is a row frame or cell frame in a split table row
444 
445     if ( mpNumInfo )
446     {
447         const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(mpNumInfo->mrFrm);
448         const SwTxtNode* pTxtNd = rTxtFrm.GetTxtNode();
449         const SwNodeNum* pNodeNum = pTxtNd->GetNum();
450 
451         if ( vcl::PDFWriter::List == eType )
452         {
453             NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap();
454             rNumListIdMap[ pNodeNum ] = nId;
455         }
456         else if ( vcl::PDFWriter::LIBody == eType )
457         {
458             NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
459             rNumListBodyIdMap[ pNodeNum ] = nId;
460         }
461     }
462     else if ( mpFrmInfo )
463     {
464         const SwFrm& rFrm = mpFrmInfo->mrFrm;
465 
466         if ( ( rFrm.IsPageFrm() && !static_cast<const SwPageFrm&>(rFrm).GetPrev() ) ||
467              ( rFrm.IsFlowFrm() && !SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() && SwFlowFrm::CastFlowFrm(&rFrm)->HasFollow() ) ||
468              ( rFrm.IsTxtFrm() && rFrm.GetDrawObjs() ) ||
469              ( rFrm.IsRowFrm() && rFrm.IsInSplitTableRow() ) ||
470              ( rFrm.IsCellFrm() && const_cast<SwFrm&>(rFrm).GetNextCellLeaf( MAKEPAGE_NONE ) ) )
471         {
472             const void* pKey = lcl_GetKeyFromFrame( rFrm );
473 
474             if ( pKey )
475             {
476                 FrmTagIdMap& rFrmTagIdMap = SwEnhancedPDFExportHelper::GetFrmTagIdMap();
477                 rFrmTagIdMap[ pKey ] = nId;
478             }
479         }
480     }
481 
482     SetAttributes( eType );
483 }
484 
485 
486 /*
487  * SwTaggedPDFHelper::EndTag()
488  */
489 void SwTaggedPDFHelper::EndTag()
490 {
491     mpPDFExtOutDevData->EndStructureElement();
492 
493 #ifdef DBG_UTIL
494     aStructStack.pop_back();
495 #endif
496 }
497 
498 
499 /*
500  * SwTaggedPDFHelper::SetAttributes()
501  *
502  * Sets the attributes according to the structure type.
503  */
504 void SwTaggedPDFHelper::SetAttributes( vcl::PDFWriter::StructElement eType )
505 {
506     vcl::PDFWriter::StructAttributeValue eVal;
507     sal_Int32 nVal;
508 
509     /*
510      * ATTRIBUTES FOR BLSE
511      */
512     if ( mpFrmInfo )
513     {
514         const SwFrm* pFrm = &mpFrmInfo->mrFrm;
515         SWRECTFN( pFrm )
516 
517         bool bPlacement = false;
518         bool bWritingMode = false;
519         bool bSpaceBefore = false;
520         bool bSpaceAfter = false;
521         bool bStartIndent = false;
522         bool bEndIndent = false;
523         bool bTextIndent = false;
524         bool bTextAlign = false;
525         bool bAlternateText = false;
526         bool bWidth = false;
527         bool bHeight = false;
528         bool bBox = false;
529         bool bRowSpan = false;
530 
531         //
532         // Check which attributes to set:
533         //
534         switch ( eType )
535         {
536             case vcl::PDFWriter::Document :
537                 bWritingMode = true;
538                 break;
539 
540             case vcl::PDFWriter::Table :
541                 bPlacement =
542                 bWritingMode =
543                 bSpaceBefore =
544                 bSpaceAfter =
545                 bStartIndent =
546                 bEndIndent =
547                 bWidth =
548                 bHeight =
549                 bBox = true;
550                 break;
551 
552             case vcl::PDFWriter::TableRow :
553                 bPlacement =
554                 bWritingMode = true;
555                 break;
556 
557             case vcl::PDFWriter::TableHeader :
558             case vcl::PDFWriter::TableData :
559                 bPlacement =
560                 bWritingMode =
561                 bWidth =
562                 bHeight =
563                 bRowSpan = true;
564                 break;
565 
566             case vcl::PDFWriter::H1 :
567             case vcl::PDFWriter::H2 :
568             case vcl::PDFWriter::H3 :
569             case vcl::PDFWriter::H4 :
570             case vcl::PDFWriter::H5 :
571             case vcl::PDFWriter::H6 :
572             case vcl::PDFWriter::Paragraph :
573             case vcl::PDFWriter::Heading :
574             case vcl::PDFWriter::Caption :
575             case vcl::PDFWriter::BlockQuote :
576 
577                 bPlacement =
578                 bWritingMode =
579                 bSpaceBefore =
580                 bSpaceAfter =
581                 bStartIndent =
582                 bEndIndent =
583                 bTextIndent =
584                 bTextAlign = true;
585                 break;
586 
587             case vcl::PDFWriter::Formula :
588             case vcl::PDFWriter::Figure :
589                 bPlacement =
590                 bAlternateText =
591                 bWidth =
592                 bHeight =
593                 bBox = true;
594                 break;
595             default :
596                 break;
597         }
598 
599         //
600         // Set the attributes:
601         //
602         if ( bPlacement )
603         {
604             eVal = vcl::PDFWriter::TableHeader == eType ||
605                    vcl::PDFWriter::TableData   == eType ?
606                    vcl::PDFWriter::Inline :
607                    vcl::PDFWriter::Block;
608 
609             mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::Placement, eVal );
610         }
611 
612         if ( bWritingMode )
613         {
614             eVal =  pFrm->IsVertical() ?
615                     vcl::PDFWriter::TbRl :
616                     pFrm->IsRightToLeft() ?
617                     vcl::PDFWriter::RlTb :
618                     vcl::PDFWriter::LrTb;
619 
620             if ( vcl::PDFWriter::LrTb != eVal )
621                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::WritingMode, eVal );
622         }
623 
624         if ( bSpaceBefore )
625         {
626             nVal = (pFrm->*fnRect->fnGetTopMargin)();
627             if ( 0 != nVal )
628                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::SpaceBefore, nVal );
629         }
630 
631         if ( bSpaceAfter )
632         {
633             nVal = (pFrm->*fnRect->fnGetBottomMargin)();
634             if ( 0 != nVal )
635                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::SpaceAfter, nVal );
636         }
637 
638         if ( bStartIndent )
639         {
640             nVal = (pFrm->*fnRect->fnGetLeftMargin)();
641             if ( 0 != nVal )
642                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::StartIndent, nVal );
643         }
644 
645         if ( bEndIndent )
646         {
647             nVal = (pFrm->*fnRect->fnGetRightMargin)();
648             if ( 0 != nVal )
649                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::EndIndent, nVal );
650         }
651 
652         if ( bTextIndent )
653         {
654             ASSERT( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" )
655             const SvxLRSpaceItem &rSpace =
656                 static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode()->GetSwAttrSet().GetLRSpace();
657             nVal =  rSpace.GetTxtFirstLineOfst();
658             if ( 0 != nVal )
659                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::TextIndent, nVal );
660         }
661 
662         if ( bTextAlign )
663         {
664             ASSERT( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" )
665             const SwAttrSet& aSet = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode()->GetSwAttrSet();
666             const SvxAdjust nAdjust = aSet.GetAdjust().GetAdjust();
667             if ( SVX_ADJUST_BLOCK == nAdjust || SVX_ADJUST_CENTER == nAdjust ||
668                  (  (pFrm->IsRightToLeft() && SVX_ADJUST_LEFT == nAdjust) ||
669                    (!pFrm->IsRightToLeft() && SVX_ADJUST_RIGHT == nAdjust) ) )
670             {
671                 eVal = SVX_ADJUST_BLOCK == nAdjust ?
672                        vcl::PDFWriter::Justify :
673                        SVX_ADJUST_CENTER == nAdjust ?
674                        vcl::PDFWriter::Center :
675                        vcl::PDFWriter::End;
676 
677                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextAlign, eVal );
678             }
679         }
680 
681         if ( bAlternateText )
682         {
683             ASSERT( pFrm->IsFlyFrm(), "Frame type <-> tag attribute mismatch" )
684             const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pFrm);
685             if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() )
686             {
687                 const SwNoTxtFrm* pNoTxtFrm   = static_cast<const SwNoTxtFrm*>(pFly->Lower());
688                 const SwNoTxtNode* pNoTxtNode = static_cast<const SwNoTxtNode*>(pNoTxtFrm->GetNode());
689 
690                 const String aAlternateTxt( pNoTxtNode->GetTitle() );
691                 mpPDFExtOutDevData->SetAlternateText( aAlternateTxt );
692             }
693         }
694 
695         if ( bWidth )
696         {
697             nVal = (pFrm->Frm().*fnRect->fnGetWidth)();
698             mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Width, nVal );
699         }
700 
701         if ( bHeight )
702         {
703             nVal = (pFrm->Frm().*fnRect->fnGetHeight)();
704             mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Height, nVal );
705         }
706 
707         if ( bBox )
708         {
709             // BBox only for non-split tables:
710             if ( vcl::PDFWriter::Table != eType ||
711                  ( pFrm->IsTabFrm() &&
712                    !static_cast<const SwTabFrm*>(pFrm)->IsFollow() &&
713                    !static_cast<const SwTabFrm*>(pFrm)->HasFollow() ) )
714                 mpPDFExtOutDevData->SetStructureBoundingBox( pFrm->Frm().SVRect() );
715         }
716 
717         if ( bRowSpan )
718         {
719             const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(pFrm);
720             if ( pThisCell )
721             {
722                 nVal =  pThisCell->GetTabBox()->getRowSpan();
723                 if ( nVal > 1 )
724                     mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::RowSpan, nVal );
725 
726                 // calculate colspan:
727                 const SwTabFrm* pTabFrm = pThisCell->FindTabFrm();
728                 const SwTable* pTable = pTabFrm->GetTable();
729 
730                 SWRECTFNX( pTabFrm )
731 
732                 const TableColumnsMapEntry& rCols = SwEnhancedPDFExportHelper::GetTableColumnsMap()[ pTable ];
733 
734                 const long nLeft  = (pThisCell->Frm().*fnRectX->fnGetLeft)();
735                 const long nRight = (pThisCell->Frm().*fnRectX->fnGetRight)();
736                 const TableColumnsMapEntry::const_iterator aLeftIter =  rCols.find( nLeft );
737                 const TableColumnsMapEntry::const_iterator aRightIter = rCols.find( nRight );
738 
739                 ASSERT( aLeftIter != rCols.end() && aRightIter != rCols.end(), "Colspan trouble" )
740                 if ( aLeftIter != rCols.end() && aRightIter != rCols.end() )
741                 {
742                     nVal = std::distance( aLeftIter, aRightIter );
743                     if ( nVal > 1 )
744                         mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::ColSpan, nVal );
745                 }
746             }
747         }
748     }
749 
750     /*
751      * ATTRIBUTES FOR ILSE
752      */
753     else if ( mpPorInfo )
754     {
755         const SwLinePortion* pPor = &mpPorInfo->mrPor;
756         const SwTxtPaintInfo& rInf = mpPorInfo->mrTxtPainter.GetInfo();
757 
758         bool bActualText = false;
759         bool bBaselineShift = false;
760         bool bTextDecorationType = false;
761         bool bLinkAttribute = false;
762         bool bLanguage = false;
763 
764         //
765         // Check which attributes to set:
766         //
767         switch ( eType )
768         {
769             case vcl::PDFWriter::Span :
770             case vcl::PDFWriter::Quote :
771             case vcl::PDFWriter::Code :
772                 if( POR_HYPHSTR == pPor->GetWhichPor() || POR_SOFTHYPHSTR == pPor->GetWhichPor() )
773                     bActualText = true;
774                 else
775                 {
776                     bBaselineShift =
777                     bTextDecorationType =
778                     bLanguage = true;
779                 }
780                 break;
781 
782             case vcl::PDFWriter::Link :
783                 bTextDecorationType =
784                 bBaselineShift =
785                 bLinkAttribute =
786                 bLanguage = true;
787                 break;
788 
789             default:
790                 break;
791         }
792 
793         if ( bActualText )
794         {
795             const String aActualTxt( rInf.GetTxt(), rInf.GetIdx(), pPor->GetLen() );
796             mpPDFExtOutDevData->SetActualText( aActualTxt );
797         }
798 
799         if ( bBaselineShift )
800         {
801             // TODO: Calculate correct values!
802             nVal = rInf.GetFont()->GetEscapement();
803             if ( nVal > 0 ) nVal = 33;
804             else if ( nVal < 0 ) nVal = -33;
805 
806             if ( 0 != nVal )
807             {
808                 nVal = nVal * pPor->Height() / 100;
809                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::BaselineShift, nVal );
810             }
811         }
812 
813         if ( bTextDecorationType )
814         {
815             if ( UNDERLINE_NONE    != rInf.GetFont()->GetUnderline() )
816                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Underline );
817             if ( UNDERLINE_NONE    != rInf.GetFont()->GetOverline() )
818                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Overline );
819             if ( STRIKEOUT_NONE    != rInf.GetFont()->GetStrikeout() )
820                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::LineThrough );
821             if ( EMPHASISMARK_NONE != rInf.GetFont()->GetEmphasisMark() )
822                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Overline );
823         }
824 
825         if ( bLanguage )
826         {
827 
828             const LanguageType nCurrentLanguage = rInf.GetFont()->GetLanguage();
829             const LanguageType nDefaultLang = SwEnhancedPDFExportHelper::GetDefaultLanguage();
830 
831             if ( nDefaultLang != nCurrentLanguage )
832                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Language, nCurrentLanguage );
833         }
834 
835         if ( bLinkAttribute )
836         {
837             const LinkIdMap& rLinkIdMap = SwEnhancedPDFExportHelper::GetLinkIdMap();
838             SwRect aPorRect;
839             rInf.CalcRect( *pPor, &aPorRect );
840             const Point aPorCenter = aPorRect.Center();
841             LinkIdMap::const_iterator aIter;
842             for ( aIter = rLinkIdMap.begin(); aIter != rLinkIdMap.end(); ++aIter )
843             {
844                 const SwRect& rLinkRect = (*aIter).first;
845                 if ( rLinkRect.IsInside( aPorCenter ) )
846                 {
847                     sal_Int32 nLinkId = (*aIter).second;
848                     mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::LinkAnnotation, nLinkId );
849                     break;
850                 }
851             }
852         }
853     }
854 }
855 
856 /*
857  * SwTaggedPDFHelper::BeginNumberedListStructureElements()
858  */
859 void SwTaggedPDFHelper::BeginNumberedListStructureElements()
860 {
861     ASSERT( mpNumInfo, "List without mpNumInfo?" )
862     if ( !mpNumInfo )
863         return;
864 
865     const SwFrm& rFrm = mpNumInfo->mrFrm;
866     ASSERT( rFrm.IsTxtFrm(), "numbered only for text frames" )
867     const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(rFrm);
868 
869     //
870     // Lowers of NonStructureElements should not be considered:
871     //
872     if ( lcl_IsInNonStructEnv( rTxtFrm ) || rTxtFrm.IsFollow() )
873         return;
874 
875     const SwTxtNode* pTxtNd = rTxtFrm.GetTxtNode();
876     const SwNumRule* pNumRule = pTxtNd->GetNumRule();
877     const SwNodeNum* pNodeNum = pTxtNd->GetNum();
878 
879     const bool bNumbered = !pTxtNd->IsOutline() && pNodeNum && pNodeNum->GetParent() && pNumRule;
880 
881     // Check, if we have to reopen a list or a list body:
882     // First condition:
883     // Paragraph is numbered/bulleted
884     if ( !bNumbered )
885         return;
886 
887     const SwNumberTreeNode* pParent = pNodeNum->GetParent();
888     const bool bSameNumbering = lcl_HasPreviousParaSameNumRule(*pTxtNd);
889 
890     // Second condition: current numbering is not 'interrupted'
891     if ( bSameNumbering )
892     {
893         sal_Int32 nReopenTag = -1;
894 
895         // Two cases:
896         // 1. We have to reopen an existing list body tag:
897         // - If the current node is either the first child of its parent
898         //   and its level > 1 or
899         // - Numbering should restart at the current node and its level > 1
900         // - The current item has no label
901         const bool bNewSubListStart = pParent->GetParent() && (pParent->IsFirst( pNodeNum ) || pTxtNd->IsListRestart() );
902         const bool bNoLabel = !pTxtNd->IsCountedInList() && !pTxtNd->IsListRestart();
903         if ( bNewSubListStart || bNoLabel )
904         {
905             // Fine, we try to reopen the appropriate list body
906             NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
907 
908             if ( bNewSubListStart )
909             {
910                 // The list body tag associated with the parent has to be reopened
911                 // to start a new list inside the list body
912                 NumListBodyIdMap::const_iterator aIter;
913 
914                 do
915                     aIter = rNumListBodyIdMap.find( pParent );
916                 while ( aIter == rNumListBodyIdMap.end() && 0 != ( pParent = pParent->GetParent() ) );
917 
918                 if ( aIter != rNumListBodyIdMap.end() )
919                     nReopenTag = (*aIter).second;
920             }
921             else // if(bNoLabel)
922             {
923                 // The list body tag of a 'counted' predecessor has to be reopened
924                 const SwNumberTreeNode* pPrevious = pNodeNum->GetPred(true);
925                 while ( pPrevious )
926                 {
927                     if ( pPrevious->IsCounted())
928                     {
929                         // get id of list body tag
930                         const NumListBodyIdMap::const_iterator aIter =  rNumListBodyIdMap.find( pPrevious );
931                         if ( aIter != rNumListBodyIdMap.end() )
932                         {
933                             nReopenTag = (*aIter).second;
934                             break;
935                         }
936                     }
937                     pPrevious = pPrevious->GetPred(true);
938                 }
939             }
940         }
941         // 2. We have to reopen an existing list tag:
942         else if ( !pParent->IsFirst( pNodeNum ) && !pTxtNd->IsListRestart() )
943         {
944             // any other than the first node in a list level has to reopen the current
945             // list. The current list is associated in a map with the first child of the list:
946             NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap();
947 
948             // Search backwards and check if any of the previous nodes has a list associated with it:
949             const SwNumberTreeNode* pPrevious = pNodeNum->GetPred(true);
950             while ( pPrevious )
951             {
952                 // get id of list tag
953                 const NumListIdMap::const_iterator aIter =  rNumListIdMap.find( pPrevious );
954                 if ( aIter != rNumListIdMap.end() )
955                 {
956                     nReopenTag = (*aIter).second;
957                     break;
958                 }
959 
960                 pPrevious = pPrevious->GetPred(true);
961             }
962         }
963 
964         if ( -1 != nReopenTag )
965         {
966             nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement();
967             mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag );
968 
969 #ifdef DBG_UTIL
970             aStructStack.push_back( 99 );
971 #endif
972         }
973     }
974     else
975     {
976         // clear list maps in case a list has been interrupted
977         NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap();
978         rNumListIdMap.clear();
979         NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
980         rNumListBodyIdMap.clear();
981     }
982 
983     // New tags:
984     const bool bNewListTag = (pNodeNum->GetParent()->IsFirst( pNodeNum ) || pTxtNd->IsListRestart() || !bSameNumbering);
985     const bool bNewItemTag = bNewListTag || pTxtNd->IsCountedInList(); // If the text node is not counted, we do not start a new list item:
986 
987     if ( bNewListTag )
988         BeginTag( vcl::PDFWriter::List, aListString );
989 
990     if ( bNewItemTag )
991     {
992         BeginTag( vcl::PDFWriter::ListItem, aListItemString );
993         BeginTag( vcl::PDFWriter::LIBody, aListBodyString );
994     }
995 }
996 
997 /*
998  * SwTaggedPDFHelper::BeginBlockStructureElements()
999  */
1000 void SwTaggedPDFHelper::BeginBlockStructureElements()
1001 {
1002     const SwFrm* pFrm = &mpFrmInfo->mrFrm;
1003 
1004     //
1005     // Lowers of NonStructureElements should not be considered:
1006     //
1007     if ( lcl_IsInNonStructEnv( *pFrm ) )
1008         return;
1009 
1010     // Check if we have to reopen an existing structure element.
1011     // This has to be done e.g., if pFrm is a follow frame.
1012     if ( CheckReopenTag() )
1013         return;
1014 
1015     sal_uInt16 nPDFType = USHRT_MAX;
1016     String aPDFType;
1017 
1018     switch ( pFrm->GetType() )
1019     {
1020         /*
1021          * GROUPING ELEMENTS
1022          */
1023 
1024         case FRM_PAGE :
1025             //
1026             // Document: Document
1027             //
1028             nPDFType = vcl::PDFWriter::Document;
1029             aPDFType = aDocumentString;
1030             break;
1031 
1032         case FRM_HEADER :
1033         case FRM_FOOTER :
1034             //
1035             // Header, Footer: NonStructElement
1036             //
1037             nPDFType = vcl::PDFWriter::NonStructElement;
1038             break;
1039 
1040         case FRM_FTNCONT :
1041             //
1042             // Footnote container: Division
1043             //
1044             nPDFType = vcl::PDFWriter::Division;
1045             aPDFType = aDivString;
1046             break;
1047 
1048         case FRM_FTN :
1049             //
1050             // Footnote frame: Note
1051             //
1052             // Note: vcl::PDFWriter::Note is actually a ILSE. Nevertheless
1053             // we treat it like a grouping element!
1054             nPDFType = vcl::PDFWriter::Note;
1055             aPDFType = aNoteString;
1056             break;
1057 
1058         case FRM_SECTION :
1059             //
1060             // Section: TOX, Index, or Sect
1061             //
1062             {
1063                 const SwSection* pSection =
1064                         static_cast<const SwSectionFrm*>(pFrm)->GetSection();
1065                 if ( TOX_CONTENT_SECTION == pSection->GetType() )
1066                 {
1067                     const SwTOXBase* pTOXBase = pSection->GetTOXBase();
1068                     if ( pTOXBase )
1069                     {
1070                         if ( TOX_INDEX == pTOXBase->GetType() )
1071                         {
1072                             nPDFType = vcl::PDFWriter::Index;
1073                             aPDFType = aIndexString;
1074                         }
1075                         else
1076                         {
1077                             nPDFType = vcl::PDFWriter::TOC;
1078                             aPDFType = aTOCString;
1079                         }
1080                     }
1081                 }
1082                 else if ( CONTENT_SECTION == pSection->GetType() )
1083                 {
1084                     nPDFType = vcl::PDFWriter::Section;
1085                     aPDFType = aSectString;
1086                 }
1087             }
1088             break;
1089 
1090         /*
1091          * BLOCK-LEVEL STRUCTURE ELEMENTS
1092          */
1093 
1094         case FRM_TXT :
1095             {
1096                 const SwTxtNode* pTxtNd =
1097                     static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode();
1098 
1099                 const SwFmt* pTxtFmt = pTxtNd->GetFmtColl();
1100                 const SwFmt* pParentTxtFmt = pTxtFmt->DerivedFrom();
1101 
1102                 String sStyleName;
1103                 String sParentStyleName;
1104 
1105                 if ( pTxtFmt)
1106                     SwStyleNameMapper::FillProgName( pTxtFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
1107                 if ( pParentTxtFmt)
1108                     SwStyleNameMapper::FillProgName( pParentTxtFmt->GetName(), sParentStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
1109 
1110                 // This is the default. If the paragraph could not be mapped to
1111                 // any of the standard pdf tags, we write a user defined tag
1112                 // <stylename> with role = P
1113                 nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Paragraph);
1114                 aPDFType = sStyleName;
1115 
1116                 //
1117                 // Quotations: BlockQuote
1118                 //
1119                 if ( sStyleName == aQuotations )
1120                 {
1121                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::BlockQuote);
1122                     aPDFType = aBlockQuoteString;
1123                 }
1124 
1125                 //
1126                 // Caption: Caption
1127                 //
1128                 else if ( sStyleName == aCaption)
1129                 {
1130                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Caption);
1131                     aPDFType = aCaptionString;
1132                 }
1133 
1134                 //
1135                 // Caption: Caption
1136                 //
1137                 else if ( sParentStyleName == aCaption)
1138                 {
1139                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Caption);
1140                     aPDFType = sStyleName.Append(aCaptionString);
1141                 }
1142 
1143                 //
1144                 // Heading: H
1145                 //
1146                 else if ( sStyleName == aHeading )
1147                 {
1148                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Heading);
1149                     aPDFType = aHString;
1150                 }
1151 
1152                 //
1153                 // Heading: H1 - H6
1154                 //
1155                 if ( pTxtNd->IsOutline() )
1156                 {
1157                     //int nRealLevel = pTxtNd->GetOutlineLevel();	//#outline level,zhaojianwei
1158 					int nRealLevel = pTxtNd->GetAttrOutlineLevel()-1;		//<-end,zhaojianwei
1159                    nRealLevel = nRealLevel > 5 ? 5 : nRealLevel;
1160 
1161                     nPDFType =  static_cast<sal_uInt16>(vcl::PDFWriter::H1 + nRealLevel);
1162                     switch(nRealLevel)
1163                     {
1164                         case 0 :
1165                             aPDFType = aH1String;
1166                             break;
1167                         case 1 :
1168                             aPDFType = aH2String;
1169                             break;
1170                         case 2 :
1171                             aPDFType = aH3String;
1172                             break;
1173                         case 3 :
1174                             aPDFType = aH4String;
1175                             break;
1176                         case 4 :
1177                             aPDFType = aH5String;
1178                             break;
1179                         default:
1180                             aPDFType = aH6String;
1181                             break;
1182                     }
1183                 }
1184 
1185                 //
1186                 // Section: TOCI
1187                 //
1188                 else if ( pFrm->IsInSct() )
1189                 {
1190                     const SwSectionFrm* pSctFrm = pFrm->FindSctFrm();
1191                     const SwSection* pSection =
1192                             static_cast<const SwSectionFrm*>(pSctFrm)->GetSection();
1193 
1194                     if ( TOX_CONTENT_SECTION == pSection->GetType() )
1195                     {
1196                         const SwTOXBase* pTOXBase = pSection->GetTOXBase();
1197                         if ( pTOXBase && TOX_INDEX != pTOXBase->GetType() )
1198                         {
1199                             // Special case: Open additional TOCI tag:
1200                             BeginTag( vcl::PDFWriter::TOCI, aTOCIString );
1201                         }
1202                     }
1203                 }
1204             }
1205             break;
1206 
1207         case FRM_TAB :
1208             //
1209             // TabFrm: Table
1210             //
1211             nPDFType = vcl::PDFWriter::Table;
1212             aPDFType = aTableString;
1213 
1214             {
1215                 // set up table column data:
1216                 const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>(pFrm);
1217                 const SwTable* pTable = pTabFrm->GetTable();
1218 
1219                 TableColumnsMap& rTableColumnsMap = SwEnhancedPDFExportHelper::GetTableColumnsMap();
1220                 const TableColumnsMap::const_iterator aIter = rTableColumnsMap.find( pTable );
1221 
1222                 if ( aIter == rTableColumnsMap.end() )
1223                 {
1224                     SWRECTFN( pTabFrm )
1225                     TableColumnsMapEntry& rCols = rTableColumnsMap[ pTable ];
1226 
1227                     const SwTabFrm* pMasterFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm;
1228 
1229                     while ( pMasterFrm )
1230                     {
1231                         const SwRowFrm* pRowFrm = static_cast<const SwRowFrm*>(pMasterFrm->GetLower());
1232 
1233                         while ( pRowFrm )
1234                         {
1235                             const SwFrm* pCellFrm = pRowFrm->GetLower();
1236 
1237                             const long nLeft  = (pCellFrm->Frm().*fnRect->fnGetLeft)();
1238                             rCols.insert( nLeft );
1239 
1240                             while ( pCellFrm )
1241                             {
1242                                 const long nRight = (pCellFrm->Frm().*fnRect->fnGetRight)();
1243                                 rCols.insert( nRight );
1244                                 pCellFrm = pCellFrm->GetNext();
1245                             }
1246                             pRowFrm = static_cast<const SwRowFrm*>(pRowFrm->GetNext());
1247                         }
1248                         pMasterFrm = static_cast<const SwTabFrm*>(pMasterFrm->GetFollow());
1249                     }
1250                 }
1251             }
1252 
1253             break;
1254 
1255         /*
1256          * TABLE ELEMENTS
1257          */
1258 
1259         case FRM_ROW :
1260             //
1261             // RowFrm: TR
1262             //
1263             if ( !static_cast<const SwRowFrm*>(pFrm)->IsRepeatedHeadline() )
1264             {
1265                 nPDFType = vcl::PDFWriter::TableRow;
1266                 aPDFType = aTRString;
1267             }
1268             else
1269             {
1270                 nPDFType = vcl::PDFWriter::NonStructElement;
1271             }
1272             break;
1273 
1274         case FRM_CELL :
1275             //
1276             // CellFrm: TH, TD
1277             //
1278             {
1279                 const SwTabFrm* pTable = static_cast<const SwCellFrm*>(pFrm)->FindTabFrm();
1280                 if ( pTable->IsInHeadline( *pFrm ) || lcl_IsHeadlineCell( *static_cast<const SwCellFrm*>(pFrm) ) )
1281                 {
1282                     nPDFType = vcl::PDFWriter::TableHeader;
1283                     aPDFType = aTHString;
1284                 }
1285                 else
1286                 {
1287                     nPDFType = vcl::PDFWriter::TableData;
1288                     aPDFType = aTDString;
1289                 }
1290             }
1291             break;
1292 
1293         /*
1294          * ILLUSTRATION
1295          */
1296 
1297         case FRM_FLY :
1298             //
1299             // FlyFrm: Figure, Formula, Control
1300             // fly in content or fly at page
1301             {
1302                 bool bFormula = false;
1303                 const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pFrm);
1304                 if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() )
1305                 {
1306                     const SwNoTxtFrm* pNoTxtFrm = static_cast<const SwNoTxtFrm*>(pFly->Lower());
1307                     SwOLENode* pOLENd = const_cast<SwOLENode*>(pNoTxtFrm->GetNode()->GetOLENode());
1308                     if ( pOLENd )
1309                     {
1310                         SwOLEObj& aOLEObj = pOLENd->GetOLEObj();
1311                         uno::Reference< embed::XEmbeddedObject > aRef = aOLEObj.GetOleRef();
1312                         if ( aRef.is() )
1313                         {
1314                             bFormula = 0 != SotExchange::IsMath( SvGlobalName( aRef->getClassID() ) );
1315                         }
1316                     }
1317                     if ( bFormula )
1318                     {
1319                         nPDFType = vcl::PDFWriter::Formula;
1320                         aPDFType = aFormulaString;
1321                     }
1322                     else
1323                     {
1324                         nPDFType = vcl::PDFWriter::Figure;
1325                         aPDFType = aFigureString;
1326                     }
1327                 }
1328                 else
1329                 {
1330                     nPDFType = vcl::PDFWriter::Division;
1331                     aPDFType = aDivString;
1332                 }
1333             }
1334             break;
1335     }
1336 
1337     if ( USHRT_MAX != nPDFType )
1338     {
1339         BeginTag( static_cast<vcl::PDFWriter::StructElement>(nPDFType), aPDFType );
1340     }
1341 }
1342 
1343 
1344 /*
1345  * SwTaggedPDFHelper::EndStructureElements()
1346  */
1347 void SwTaggedPDFHelper::EndStructureElements()
1348 {
1349     while ( nEndStructureElement > 0 )
1350     {
1351         EndTag();
1352         --nEndStructureElement;
1353     }
1354 
1355     CheckRestoreTag();
1356 }
1357 
1358 
1359 /*
1360  * SwTaggedPDFHelper::BeginInlineStructureElements()
1361  */
1362 void SwTaggedPDFHelper::BeginInlineStructureElements()
1363 {
1364     const SwLinePortion* pPor = &mpPorInfo->mrPor;
1365     const SwTxtPaintInfo& rInf = mpPorInfo->mrTxtPainter.GetInfo();
1366     const SwTxtFrm* pFrm = rInf.GetTxtFrm();
1367 
1368     //
1369     // Lowers of NonStructureElements should not be considered:
1370     //
1371     if ( lcl_IsInNonStructEnv( *pFrm ) )
1372         return;
1373 
1374     sal_uInt16 nPDFType = USHRT_MAX;
1375     String aPDFType;
1376 
1377     switch ( pPor->GetWhichPor() )
1378     {
1379         // Check for alternative spelling:
1380         case POR_HYPHSTR :
1381         case POR_SOFTHYPHSTR :
1382             nPDFType = vcl::PDFWriter::Span;
1383             aPDFType = aSpanString;
1384             break;
1385 
1386         case POR_LAY :
1387         case POR_TXT :
1388         case POR_PARA :
1389             {
1390                 SwTxtNode* pNd = (SwTxtNode*)pFrm->GetTxtNode();
1391                 SwTxtAttr const*const pInetFmtAttr =
1392                     pNd->GetTxtAttrAt(rInf.GetIdx(), RES_TXTATR_INETFMT);
1393 
1394                 String sStyleName;
1395                 if ( !pInetFmtAttr )
1396                 {
1397                     ::std::vector<SwTxtAttr *> const charAttrs(
1398                         pNd->GetTxtAttrsAt(rInf.GetIdx(), RES_TXTATR_CHARFMT));
1399                     // TODO: handle more than 1 char style?
1400                     const SwCharFmt* pCharFmt = (charAttrs.size())
1401                         ? (*charAttrs.begin())->GetCharFmt().GetCharFmt() : 0;
1402                     if ( pCharFmt )
1403                         SwStyleNameMapper::FillProgName( pCharFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
1404                 }
1405 
1406                 // Check for Link:
1407 		        if( pInetFmtAttr )
1408 		        {
1409                     nPDFType = vcl::PDFWriter::Link;
1410                     aPDFType = aLinkString;
1411                 }
1412                 // Check for Quote/Code character style:
1413                 else if ( sStyleName == aQuotation )
1414                 {
1415                     nPDFType = vcl::PDFWriter::Quote;
1416                     aPDFType = aQuoteString;
1417                 }
1418                 else if ( sStyleName == aSourceText )
1419                 {
1420                     nPDFType = vcl::PDFWriter::Code;
1421                     aPDFType = aCodeString;
1422                 }
1423                 else
1424                 {
1425                     const LanguageType nCurrentLanguage = rInf.GetFont()->GetLanguage();
1426                     const sal_uInt16 nFont = rInf.GetFont()->GetActual();
1427                     const LanguageType nDefaultLang = SwEnhancedPDFExportHelper::GetDefaultLanguage();
1428 
1429                     if ( UNDERLINE_NONE    != rInf.GetFont()->GetUnderline() ||
1430                          UNDERLINE_NONE    != rInf.GetFont()->GetOverline()  ||
1431                          STRIKEOUT_NONE    != rInf.GetFont()->GetStrikeout() ||
1432                          EMPHASISMARK_NONE != rInf.GetFont()->GetEmphasisMark() ||
1433                          0                 != rInf.GetFont()->GetEscapement() ||
1434                          SW_LATIN          != nFont ||
1435                          nCurrentLanguage  != nDefaultLang ||
1436                          sStyleName.Len()  > 0 )
1437                     {
1438                         nPDFType = vcl::PDFWriter::Span;
1439                         if ( sStyleName.Len() > 0 )
1440                             aPDFType = sStyleName;
1441                         else
1442                             aPDFType = aSpanString;
1443                     }
1444                 }
1445             }
1446             break;
1447 
1448         case POR_FTN :
1449             nPDFType = vcl::PDFWriter::Link;
1450             aPDFType = aLinkString;
1451             break;
1452 
1453         case POR_FLD :
1454             {
1455                 // check field type:
1456                 const xub_StrLen nIdx = static_cast<const SwFldPortion*>(pPor)->IsFollow() ?
1457                                         rInf.GetIdx() - 1 :
1458                                         rInf.GetIdx();
1459                 const SwTxtAttr* pHint = mpPorInfo->mrTxtPainter.GetAttr( nIdx );
1460                 const SwField* pFld = 0;
1461                 if ( pHint && RES_TXTATR_FIELD == pHint->Which() )
1462                 {
1463                     pFld = (SwField*)pHint->GetFld().GetFld();
1464                     if ( RES_GETREFFLD == pFld->Which() )
1465                     {
1466                         nPDFType = vcl::PDFWriter::Link;
1467                         aPDFType = aLinkString;
1468                     }
1469                     else if ( RES_AUTHORITY == pFld->Which() )
1470                     {
1471                         nPDFType = vcl::PDFWriter::BibEntry;
1472                         aPDFType = aBibEntryString;
1473                     }
1474                 }
1475             }
1476             break;
1477 
1478         case POR_TAB :
1479         case POR_TABRIGHT :
1480         case POR_TABCENTER :
1481         case POR_TABDECIMAL :
1482             nPDFType = vcl::PDFWriter::NonStructElement;
1483             break;
1484     }
1485 
1486     if ( USHRT_MAX != nPDFType )
1487     {
1488         BeginTag( static_cast<vcl::PDFWriter::StructElement>(nPDFType), aPDFType );
1489     }
1490 }
1491 
1492 /*
1493  * static SwTaggedPDFHelper::IsExportTaggedPDF
1494  */
1495  bool SwTaggedPDFHelper::IsExportTaggedPDF( const OutputDevice& rOut )
1496  {
1497     vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, rOut.GetExtOutDevData() );
1498     return pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF();
1499  }
1500 
1501 /*
1502  * SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper()
1503  */
1504 SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper( SwEditShell& rSh,
1505                                                       OutputDevice& rOut,
1506                                                       const rtl::OUString& rPageRange,
1507                                                       bool bSkipEmptyPages,
1508                                                       bool bEditEngineOnly )
1509     : mrSh( rSh ),
1510       mrOut( rOut ),
1511       pPageRange( 0 ),
1512       mbSkipEmptyPages( bSkipEmptyPages ),
1513       mbEditEngineOnly( bEditEngineOnly )
1514 {
1515     if ( rPageRange.getLength() )
1516         pPageRange = new MultiSelection( rPageRange );
1517 
1518     aTableColumnsMap.clear();
1519     aLinkIdMap.clear();
1520     aNumListIdMap.clear();
1521     aNumListBodyIdMap.clear();
1522     aFrmTagIdMap.clear();
1523 
1524 #ifdef DBG_UTIL
1525     aStructStack.clear();
1526 #endif
1527 
1528     const sal_uInt8 nScript = (sal_uInt8)GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() );
1529     sal_uInt16 nLangRes = RES_CHRATR_LANGUAGE;
1530 
1531     if ( i18n::ScriptType::ASIAN == nScript )
1532         nLangRes = RES_CHRATR_CJK_LANGUAGE;
1533     else if ( i18n::ScriptType::COMPLEX == nScript )
1534         nLangRes = RES_CHRATR_CTL_LANGUAGE;
1535 
1536     eLanguageDefault = static_cast<const SvxLanguageItem*>(&mrSh.GetDoc()->GetDefault( nLangRes ))->GetLanguage();
1537 
1538     EnhancedPDFExport();
1539 }
1540 
1541 SwEnhancedPDFExportHelper::~SwEnhancedPDFExportHelper()
1542 {
1543     delete pPageRange;
1544 }
1545 
1546 /*
1547  * SwEnhancedPDFExportHelper::EnhancedPDFExport()
1548  */
1549 void SwEnhancedPDFExportHelper::EnhancedPDFExport()
1550 {
1551     vcl::PDFExtOutDevData* pPDFExtOutDevData =
1552         PTR_CAST( vcl::PDFExtOutDevData, mrOut.GetExtOutDevData() );
1553 
1554     if ( !pPDFExtOutDevData )
1555         return;
1556 
1557     //
1558     // set the document locale
1559     //
1560     com::sun::star::lang::Locale aDocLocale = MsLangId::convertLanguageToLocale( SwEnhancedPDFExportHelper::GetDefaultLanguage() );
1561     pPDFExtOutDevData->SetDocumentLocale( aDocLocale );
1562 
1563     //
1564     // Prepare the output device:
1565     //
1566     mrOut.Push( PUSH_MAPMODE );
1567     MapMode aMapMode( mrOut.GetMapMode() );
1568     aMapMode.SetMapUnit( MAP_TWIP );
1569     mrOut.SetMapMode( aMapMode );
1570 
1571     //
1572     // Create new cursor and lock the view:
1573     //
1574     SwDoc* pDoc = mrSh.GetDoc();
1575     mrSh.SwCrsrShell::Push();
1576     mrSh.SwCrsrShell::ClearMark();
1577     const sal_Bool bOldLockView = mrSh.IsViewLocked();
1578     mrSh.LockView( sal_True );
1579 
1580     if ( !mbEditEngineOnly )
1581     {
1582         //
1583         // POSTITS
1584         //
1585         if ( pPDFExtOutDevData->GetIsExportNotes() )
1586         {
1587             SwFieldType* pType = mrSh.GetFldType( RES_POSTITFLD, aEmptyStr );
1588             SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
1589             for( SwFmtFld* pFirst = aIter.First(); pFirst; )
1590             {
1591                 if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() )
1592                 {
1593                     const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode();
1594                     ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1595 
1596                     // 1. Check if the whole paragraph is hidden
1597                     // 2. Move to the field
1598                     // 3. Check for hidden text attribute
1599                     if ( !pTNd->IsHidden() &&
1600                           mrSh.GotoFld( *pFirst ) &&
1601                          !mrSh.SelectHiddenRange() )
1602                     {
1603                         // Link Rectangle
1604                         const SwRect& rNoteRect = mrSh.GetCharRect();
1605 
1606                         // Link PageNum
1607                         const sal_Int32 nNotePageNum = CalcOutputPageNum( rNoteRect );
1608                         if ( -1 != nNotePageNum )
1609 		                    {
1610                             // Link Note
1611                             vcl::PDFNote aNote;
1612 
1613                             // Use the NumberFormatter to get the date string:
1614                             const SwPostItField* pField = (SwPostItField*)pFirst->GetFld();
1615                             SvNumberFormatter* pNumFormatter = pDoc->GetNumberFormatter();
1616                             const Date aDateDiff( pField->GetDate() -
1617                                                  *pNumFormatter->GetNullDate() );
1618                             const sal_uLong nFormat =
1619                                 pNumFormatter->GetStandardFormat( NUMBERFORMAT_DATE, pField->GetLanguage() );
1620                             String sDate;
1621                             Color* pColor;
1622                             pNumFormatter->GetOutputString( aDateDiff.GetDate(), nFormat, sDate, &pColor );
1623 
1624                             // The title should consist of the author and the date:
1625                             String sTitle( pField->GetPar1() );
1626                             sTitle.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
1627                             sTitle += sDate;
1628                             aNote.Title = sTitle;
1629                             // Guess what the contents contains...
1630                             aNote.Contents = pField->GetTxt();
1631 
1632                             // Link Export
1633                             pPDFExtOutDevData->CreateNote( rNoteRect.SVRect(), aNote, nNotePageNum );
1634                         }
1635                     }
1636                 }
1637                 pFirst = aIter.Next();
1638                 mrSh.SwCrsrShell::ClearMark();
1639             }
1640         }
1641 
1642         //
1643         // HYPERLINKS
1644         //
1645         SwGetINetAttrs aArr;
1646         const sal_uInt16 nHyperLinkCount = mrSh.GetINetAttrs( aArr );
1647         for( sal_uInt16 n = 0; n < nHyperLinkCount; ++n )
1648         {
1649             SwGetINetAttr* p = aArr[ n ];
1650             ASSERT( 0 != p, "Enhanced pdf export - SwGetINetAttr is missing" )
1651 
1652             const SwTxtNode* pTNd = p->rINetAttr.GetpTxtNode();
1653             ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1654 
1655             // 1. Check if the whole paragraph is hidden
1656             // 2. Move to the hyperlink
1657             // 3. Check for hidden text attribute
1658             if ( !pTNd->IsHidden() &&
1659                   mrSh.GotoINetAttr( p->rINetAttr ) &&
1660                  !mrSh.SelectHiddenRange() )
1661             {
1662                 // Select the hyperlink:
1663                 mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS );
1664                 if ( mrSh.SwCrsrShell::SelectTxtAttr( RES_TXTATR_INETFMT, sal_True ) )
1665                 {
1666                     // First, we create the destination, because there may be more
1667                     // than one link to this destination:
1668                     String aURL( INetURLObject::decode(
1669                         p->rINetAttr.GetINetFmt().GetValue(),
1670                         INET_HEX_ESCAPE,
1671                         INetURLObject::DECODE_UNAMBIGUOUS,
1672                         RTL_TEXTENCODING_UTF8 ) );
1673 
1674                     // We have to distinguish between intern and real URLs
1675                     const bool bIntern = '#' == aURL.GetChar( 0 );
1676 
1677                     // _GetCrsr() is a SwShellCrsr, which is derived from
1678                     // SwSelPaintRects, therefore the rectangles of the current
1679                     // selection can be easily obtained:
1680                     // Note: We make a copy of the rectangles, because they may
1681                     // be deleted again in JumpToSwMark.
1682                     SwRects aTmp;
1683                     aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 );
1684                     ASSERT( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" )
1685 
1686                     // Create the destination for internal links:
1687                     sal_Int32 nDestId = -1;
1688                     if ( bIntern )
1689                     {
1690                         aURL.Erase( 0, 1 );
1691                         mrSh.SwCrsrShell::ClearMark();
1692                         JumpToSwMark( &mrSh, aURL );
1693 
1694                         // Destination Rectangle
1695                         const SwRect& rDestRect = mrSh.GetCharRect();
1696 
1697                         // Destination PageNum
1698                         const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
1699 
1700                         // Destination Export
1701                         if ( -1 != nDestPageNum )
1702                             nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
1703                     }
1704 
1705                     if ( !bIntern || -1 != nDestId )
1706                     {
1707                         // --> FME 2005-05-09 #i44368# Links in Header/Footer
1708                         const SwPosition aPos( *pTNd );
1709                         const bool bHeaderFooter = pDoc->IsInHeaderFooter( aPos.nNode );
1710                         // <--
1711 
1712                         // Create links for all selected rectangles:
1713                         const sal_uInt16 nNumOfRects = aTmp.Count();
1714                         for ( sal_uInt16 i = 0; i < nNumOfRects; ++i )
1715                         {
1716                             // Link Rectangle
1717                             const SwRect& rLinkRect( aTmp[ i ] );
1718 
1719                             // Link PageNum
1720                             const sal_Int32 nLinkPageNum = CalcOutputPageNum( rLinkRect );
1721 
1722                             if ( -1 != nLinkPageNum )
1723                             {
1724                                 // Link Export
1725                                 const sal_Int32 nLinkId =
1726                                     pPDFExtOutDevData->CreateLink( rLinkRect.SVRect(), nLinkPageNum );
1727 
1728                                 // Store link info for tagged pdf output:
1729                                 const IdMapEntry aLinkEntry( rLinkRect, nLinkId );
1730                                 aLinkIdMap.push_back( aLinkEntry );
1731 
1732                                 // Connect Link and Destination:
1733                                 if ( bIntern )
1734                                     pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId );
1735                                 else
1736                                     pPDFExtOutDevData->SetLinkURL( nLinkId, aURL );
1737 
1738                                 // --> FME 2005-05-09 #i44368# Links in Header/Footer
1739                                 if ( bHeaderFooter )
1740                                     MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, rLinkRect, nDestId, aURL, bIntern );
1741                                 // <--
1742                             }
1743                         }
1744                     }
1745                 }
1746             }
1747             mrSh.SwCrsrShell::ClearMark();
1748         }
1749 
1750         //
1751         // HYPERLINKS (Graphics, Frames, OLEs )
1752         //
1753         const SwSpzFrmFmts* pTbl = pDoc->GetSpzFrmFmts();
1754         const sal_uInt16 nSpzFrmFmtsCount = pTbl->Count();
1755         for( sal_uInt16 n = 0; n < nSpzFrmFmtsCount; ++n )
1756         {
1757             const SwFrmFmt* pFrmFmt = (*pTbl)[n];
1758             const SfxPoolItem* pItem;
1759             if ( RES_DRAWFRMFMT != pFrmFmt->Which() &&
1760                  SFX_ITEM_SET == pFrmFmt->GetAttrSet().GetItemState( RES_URL, sal_True, &pItem ) )
1761             {
1762                 String aURL( static_cast<const SwFmtURL*>(pItem)->GetURL() );
1763                 const bool bIntern = '#' == aURL.GetChar( 0 );
1764 
1765                 // Create the destination for internal links:
1766                 sal_Int32 nDestId = -1;
1767                 if ( bIntern )
1768                 {
1769                     aURL.Erase( 0, 1 );
1770                     mrSh.SwCrsrShell::ClearMark();
1771                     JumpToSwMark( &mrSh, aURL );
1772 
1773                     // Destination Rectangle
1774                     const SwRect& rDestRect = mrSh.GetCharRect();
1775 
1776                     // Destination PageNum
1777                     const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
1778 
1779                     // Destination Export
1780                     if ( -1 != nDestPageNum )
1781                         nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
1782                 }
1783 
1784                 if ( !bIntern || -1 != nDestId )
1785                 {
1786                     Point aNullPt;
1787                     const SwRect aLinkRect = pFrmFmt->FindLayoutRect( sal_False, &aNullPt );
1788 
1789                     // Link PageNum
1790                     const sal_Int32 nLinkPageNum = CalcOutputPageNum( aLinkRect );
1791 
1792                     // Link Export
1793                     if ( -1 != nLinkPageNum )
1794                     {
1795                         const sal_Int32 nLinkId =
1796                             pPDFExtOutDevData->CreateLink( aLinkRect.SVRect(), nLinkPageNum );
1797 
1798                         // Connect Link and Destination:
1799                         if ( bIntern )
1800                             pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId );
1801                         else
1802                             pPDFExtOutDevData->SetLinkURL( nLinkId, aURL );
1803 
1804                         // --> FME 2005-05-09 #i44368# Links in Header/Footer
1805                         const SwFmtAnchor &rAnch = pFrmFmt->GetAnchor();
1806                         if (FLY_AT_PAGE != rAnch.GetAnchorId())
1807                         {
1808                             const SwPosition* pPosition = rAnch.GetCntntAnchor();
1809                             if ( pPosition && pDoc->IsInHeaderFooter( pPosition->nNode ) )
1810                             {
1811                                 const SwTxtNode* pTNd = pPosition->nNode.GetNode().GetTxtNode();
1812                                 if ( pTNd )
1813                                     MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, aLinkRect, nDestId, aURL, bIntern );
1814                             }
1815                         }
1816                         // <--
1817                     }
1818                 }
1819             }
1820             mrSh.SwCrsrShell::ClearMark();
1821         }
1822 
1823         //
1824         // REFERENCES
1825         //
1826         SwFieldType* pType = mrSh.GetFldType( RES_GETREFFLD, aEmptyStr );
1827         SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
1828         for( SwFmtFld* pFirst = aIter.First(); pFirst; )
1829         {
1830             if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() )
1831             {
1832                 const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode();
1833                ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1834 
1835                 // 1. Check if the whole paragraph is hidden
1836                 // 2. Move to the field
1837                 // 3. Check for hidden text attribute
1838                 if ( !pTNd->IsHidden() &&
1839                       mrSh.GotoFld( *pFirst ) &&
1840                      !mrSh.SelectHiddenRange() )
1841                 {
1842                     // Select the field:
1843                     mrSh.SwCrsrShell::SetMark();
1844                     mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS );
1845 
1846                     // Link Rectangles
1847                     SwRects aTmp;
1848                     aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 );
1849                     ASSERT( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" )
1850 
1851                     mrSh.SwCrsrShell::ClearMark();
1852 
1853                     // Destination Rectangle
1854                     const SwGetRefField* pField =
1855                         (SwGetRefField*)pFirst->GetFld();
1856                     const String& rRefName = pField->GetSetRefName();
1857                     mrSh.GotoRefMark( rRefName, pField->GetSubType(), pField->GetSeqNo() );
1858                     const SwRect& rDestRect = mrSh.GetCharRect();
1859 
1860                     // Destination PageNum
1861                     const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
1862 
1863                     if ( -1 != nDestPageNum )
1864                     {
1865                         // Destination Export
1866                         const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
1867 
1868                         // --> FME 2005-05-09 #i44368# Links in Header/Footer
1869                         const SwPosition aPos( *pTNd );
1870                         const bool bHeaderFooter = pDoc->IsInHeaderFooter( aPos.nNode );
1871                         // <--
1872 
1873                         // Create links for all selected rectangles:
1874                         const sal_uInt16 nNumOfRects = aTmp.Count();
1875                         for ( sal_uInt16 i = 0; i < nNumOfRects; ++i )
1876                         {
1877                             // Link rectangle
1878                             const SwRect& rLinkRect( aTmp[ i ] );
1879 
1880                             // Link PageNum
1881                             const sal_Int32 nLinkPageNum = CalcOutputPageNum( rLinkRect );
1882 
1883                             if ( -1 != nLinkPageNum )
1884                             {
1885                                 // Link Export
1886                                 const sal_Int32 nLinkId =
1887                                     pPDFExtOutDevData->CreateLink( rLinkRect.SVRect(), nLinkPageNum );
1888 
1889                                 // Store link info for tagged pdf output:
1890                                 const IdMapEntry aLinkEntry( rLinkRect, nLinkId );
1891                                 aLinkIdMap.push_back( aLinkEntry );
1892 
1893                                 // Connect Link and Destination:
1894                                 pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId );
1895 
1896                                 // --> FME 2005-05-09 #i44368# Links in Header/Footer
1897                                 if ( bHeaderFooter )
1898                                 {
1899                                     const String aDummy;
1900                                     MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, rLinkRect, nDestId, aDummy, true );
1901                                 }
1902                                 // <--
1903                             }
1904                         }
1905                     }
1906                 }
1907             }
1908             pFirst = aIter.Next();
1909             mrSh.SwCrsrShell::ClearMark();
1910         }
1911 
1912         //
1913         // FOOTNOTES
1914         //
1915         const sal_uInt16 nFtnCount = pDoc->GetFtnIdxs().Count();
1916         for ( sal_uInt16 nIdx = 0; nIdx < nFtnCount; ++nIdx )
1917         {
1918             // Set cursor to text node that contains the footnote:
1919             const SwTxtFtn* pTxtFtn = pDoc->GetFtnIdxs()[ nIdx ];
1920             SwTxtNode& rTNd = const_cast<SwTxtNode&>(pTxtFtn->GetTxtNode());
1921 
1922             mrSh._GetCrsr()->GetPoint()->nNode = rTNd;
1923             mrSh._GetCrsr()->GetPoint()->nContent.Assign( &rTNd, *pTxtFtn->GetStart() );
1924 
1925             // 1. Check if the whole paragraph is hidden
1926             // 2. Check for hidden text attribute
1927             if ( static_cast<const SwTxtNode&>(rTNd).IsHidden() ||
1928                  mrSh.SelectHiddenRange() )
1929                 continue;
1930 
1931             SwCrsrSaveState aSaveState( *mrSh._GetCrsr() );
1932 
1933             // Select the footnote:
1934             mrSh.SwCrsrShell::SetMark();
1935             mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS );
1936 
1937             // Link Rectangle
1938             SwRects aTmp;
1939             aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 );
1940             ASSERT( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" )
1941             const SwRect aLinkRect( aTmp[ 0 ] );
1942 
1943             mrSh._GetCrsr()->RestoreSavePos();
1944             mrSh.SwCrsrShell::ClearMark();
1945 
1946             // Goto footnote text:
1947             if ( mrSh.GotoFtnTxt() )
1948             {
1949                 // Link PageNum
1950                 const sal_Int32 nLinkPageNum = CalcOutputPageNum( aLinkRect );
1951 
1952                 if ( -1 != nLinkPageNum )
1953                 {
1954                     // Link Export
1955                     const sal_Int32 nLinkId =
1956                         pPDFExtOutDevData->CreateLink( aLinkRect.SVRect(), nLinkPageNum );
1957 
1958                     // Store link info for tagged pdf output:
1959                     const IdMapEntry aLinkEntry( aLinkRect, nLinkId );
1960                     aLinkIdMap.push_back( aLinkEntry );
1961 
1962                     // Destination Rectangle
1963                     const SwRect& rDestRect = mrSh.GetCharRect();
1964 
1965                     // Destination PageNum
1966                     const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
1967 
1968                     if ( -1 != nDestPageNum )
1969                     {
1970                         // Destination Export
1971                         const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
1972 
1973                         // Connect Link and Destination:
1974                         pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId );
1975                     }
1976                 }
1977             }
1978         }
1979 
1980         //
1981         // OUTLINE
1982         //
1983         if( pPDFExtOutDevData->GetIsExportBookmarks() )
1984         {
1985             typedef std::pair< sal_Int8, sal_Int32 > StackEntry;
1986             std::stack< StackEntry > aOutlineStack;
1987             aOutlineStack.push( StackEntry( -1, -1 ) ); // push default value
1988 
1989             const sal_uInt16 nOutlineCount =
1990                 static_cast<sal_uInt16>(mrSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount());
1991             for ( sal_uInt16 i = 0; i < nOutlineCount; ++i )
1992             {
1993                 // Check if outline is hidden
1994                 const SwTxtNode* pTNd = mrSh.GetNodes().GetOutLineNds()[ i ]->GetTxtNode();
1995                 ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1996 
1997                 if ( pTNd->IsHidden() ||
1998                      // --> FME 2005-01-10 #i40292# Skip empty outlines:
1999                      0 == pTNd->GetTxt().Len() )
2000                      // <--
2001                     continue;
2002 
2003                 // Get parent id from stack:
2004                 const sal_Int8 nLevel = (sal_Int8)mrSh.getIDocumentOutlineNodesAccess()->getOutlineLevel( i );
2005                 sal_Int8 nLevelOnTopOfStack = aOutlineStack.top().first;
2006                 while ( nLevelOnTopOfStack >= nLevel &&
2007                         nLevelOnTopOfStack != -1 )
2008                 {
2009                     aOutlineStack.pop();
2010                     nLevelOnTopOfStack = aOutlineStack.top().first;
2011                 }
2012                 const sal_Int32 nParent = aOutlineStack.top().second;
2013 
2014                 // Destination rectangle
2015                 mrSh.GotoOutline(i);
2016                 const SwRect& rDestRect = mrSh.GetCharRect();
2017 
2018                 // Destination PageNum
2019                 const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
2020 
2021                 if ( -1 != nDestPageNum )
2022                 {
2023                     // Destination Export
2024                     const sal_Int32 nDestId =
2025                         pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
2026 
2027                     // Outline entry text
2028                     const String& rEntry = mrSh.getIDocumentOutlineNodesAccess()->getOutlineText( i );
2029 
2030                     // Create a new outline item:
2031                     const sal_Int32 nOutlineId =
2032                         pPDFExtOutDevData->CreateOutlineItem( nParent, rEntry, nDestId );
2033 
2034                     // Push current level and nOutlineId on stack:
2035                     aOutlineStack.push( StackEntry( nLevel, nOutlineId ) );
2036                 }
2037             }
2038         }
2039 
2040         if( pPDFExtOutDevData->GetIsExportNamedDestinations() )
2041         {
2042             //---> i56629 the iteration to convert the OOo bookmark (#bookmark)
2043             // into PDF named destination, see section 8.2.1 in PDF 1.4 spec
2044             // We need:
2045             // 1. a name for the destination, formed from the standard OOo bookmark name
2046             // 2. the destination, obtained from where the bookmark destination lies
2047             IDocumentMarkAccess* const pMarkAccess = mrSh.GetDoc()->getIDocumentMarkAccess();
2048             for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin();
2049                 ppMark != pMarkAccess->getBookmarksEnd();
2050                 ppMark++)
2051             {
2052                 //get the name
2053                 const ::sw::mark::IMark* pBkmk = ppMark->get();
2054                 mrSh.SwCrsrShell::ClearMark();
2055                 rtl::OUString sBkName = pBkmk->GetName();
2056 
2057                 //jump to it
2058                 JumpToSwMark( &mrSh, sBkName );
2059 
2060                 // Destination Rectangle
2061                 const SwRect& rDestRect = mrSh.GetCharRect();
2062 
2063                 // Destination PageNum
2064                 const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
2065 
2066                 // Destination Export
2067                 if ( -1 != nDestPageNum )
2068                     pPDFExtOutDevData->CreateNamedDest( sBkName, rDestRect.SVRect(), nDestPageNum );
2069             }
2070             mrSh.SwCrsrShell::ClearMark();
2071             //<--- i56629
2072         }
2073     }
2074     else
2075     {
2076         //
2077         // LINKS FROM EDITENGINE
2078         //
2079         std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
2080         std::vector< vcl::PDFExtOutDevBookmarkEntry >::const_iterator aIBeg = rBookmarks.begin();
2081         const std::vector< vcl::PDFExtOutDevBookmarkEntry >::const_iterator aIEnd = rBookmarks.end();
2082         while ( aIBeg != aIEnd )
2083         {
2084             String aBookmarkName( aIBeg->aBookmark );
2085             const bool bIntern = '#' == aBookmarkName.GetChar( 0 );
2086             if ( bIntern )
2087             {
2088                 aBookmarkName.Erase( 0, 1 );
2089                 JumpToSwMark( &mrSh, aBookmarkName );
2090 
2091                 // Destination Rectangle
2092                 const SwRect& rDestRect = mrSh.GetCharRect();
2093 
2094                 // Destination PageNum
2095                 const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
2096 
2097                 if ( -1 != nDestPageNum )
2098                 {
2099                     if ( aIBeg->nLinkId != -1 )
2100                     {
2101                         // Destination Export
2102                         const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
2103 
2104                         // Connect Link and Destination:
2105                         pPDFExtOutDevData->SetLinkDest( aIBeg->nLinkId, nDestId );
2106                     }
2107                     else
2108                     {
2109                         pPDFExtOutDevData->DescribeRegisteredDest( aIBeg->nDestId, rDestRect.SVRect(), nDestPageNum );
2110                     }
2111                 }
2112             }
2113             else
2114                 pPDFExtOutDevData->SetLinkURL( aIBeg->nLinkId, aBookmarkName );
2115 
2116             aIBeg++;
2117         }
2118         rBookmarks.clear();
2119     }
2120 
2121     // Restore view, cursor, and outdev:
2122     mrSh.LockView( bOldLockView );
2123     mrSh.SwCrsrShell::Pop( sal_False );
2124     mrOut.Pop();
2125 }
2126 
2127 /*
2128  * SwEnhancedPDFExportHelper::CalcOutputPageNum()
2129  */
2130 sal_Int32 SwEnhancedPDFExportHelper::CalcOutputPageNum( const SwRect& rRect ) const
2131 {
2132     // Document page numbers are 0, 1, 2, ...
2133     const sal_Int32 nPageNumOfRect = mrSh.GetPageNumAndSetOffsetForPDF( mrOut, rRect );
2134 
2135     // Shortcut:
2136     if ( -1 == nPageNumOfRect || ( !pPageRange && !mbSkipEmptyPages ) )
2137         return nPageNumOfRect;
2138 
2139     // pPageRange page numbers are 1, 2, 3, ...
2140     if ( pPageRange && !pPageRange->IsSelected( nPageNumOfRect + 1 ) )
2141         return -1;
2142 
2143     // What will be the page number of page nPageNumOfRect in the output doc?
2144     sal_Int32 nOutputPageNum = -1;
2145     const SwRootFrm* pRootFrm = mrSh.GetLayout();
2146     const SwPageFrm* pCurrPage = static_cast<const SwPageFrm*>(pRootFrm->Lower());
2147 
2148     for ( sal_Int32 nPageIndex = 0;
2149           nPageIndex <= nPageNumOfRect && pCurrPage;
2150           ++nPageIndex )
2151     {
2152         if ( ( !pPageRange || pPageRange->IsSelected( nPageIndex + 1 ) ) &&
2153              ( !mbSkipEmptyPages || !pCurrPage->IsEmptyPage() ) )
2154             ++nOutputPageNum;
2155 
2156         pCurrPage = static_cast<const SwPageFrm*>(pCurrPage->GetNext());
2157     }
2158 
2159     // pdf export page numbers are 0, 1, 2, ...
2160     return nOutputPageNum;
2161 }
2162 
2163 void SwEnhancedPDFExportHelper::MakeHeaderFooterLinks( vcl::PDFExtOutDevData& rPDFExtOutDevData,
2164                                                        const SwTxtNode& rTNd,
2165                                                        const SwRect& rLinkRect,
2166                                                        sal_Int32 nDestId,
2167                                                        const String& rURL,
2168                                                        bool bIntern ) const
2169 {
2170     // We assume, that the primary link has just been exported. Therefore
2171     // the offset of the link rectangle calculates as follows:
2172     const Point aOffset = rLinkRect.Pos() + mrOut.GetMapMode().GetOrigin();
2173 
2174     SwIterator<SwTxtFrm,SwTxtNode> aIter( rTNd );
2175     for ( SwTxtFrm* pTmpFrm = aIter.First(); pTmpFrm; pTmpFrm = aIter.Next() )
2176         {
2177             // Add offset to current page:
2178             const SwPageFrm* pPageFrm = pTmpFrm->FindPageFrm();
2179             SwRect aHFLinkRect( rLinkRect );
2180             aHFLinkRect.Pos() = pPageFrm->Frm().Pos() + aOffset;
2181 
2182             // #i97135# the gcc_x64 optimizer gets aHFLinkRect != rLinkRect wrong
2183             // fool it by comparing the position only (the width and height are the
2184             // same anyway)
2185             if ( aHFLinkRect.Pos() != rLinkRect.Pos() )
2186             {
2187                 // Link PageNum
2188                 const sal_Int32 nHFLinkPageNum = CalcOutputPageNum( aHFLinkRect );
2189 
2190                 if ( -1 != nHFLinkPageNum )
2191                 {
2192                     // Link Export
2193                     const sal_Int32 nHFLinkId =
2194                         rPDFExtOutDevData.CreateLink( aHFLinkRect.SVRect(), nHFLinkPageNum );
2195 
2196                     // Connect Link and Destination:
2197                     if ( bIntern )
2198                         rPDFExtOutDevData.SetLinkDest( nHFLinkId, nDestId );
2199                     else
2200                         rPDFExtOutDevData.SetLinkURL( nHFLinkId, rURL );
2201                 }
2202             }
2203         }
2204 }
2205 
2206