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