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 
lcl_DBGCheckStack()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
lcl_IsHeadlineCell(const SwCellFrm & rCellFrm)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:
lcl_IsInNonStructEnv(const SwFrm & rFrm)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:
lcl_GetKeyFromFrame(const SwFrm & rFrm)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 
lcl_HasPreviousParaSameNumRule(const SwTxtNode & rNode)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  */
SwTaggedPDFHelper(const Num_Info * pNumInfo,const Frm_Info * pFrmInfo,const Por_Info * pPorInfo,OutputDevice & rOut)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  */
~SwTaggedPDFHelper()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  */
CheckReopenTag()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                 if( aIter != rFrmTagIdMap.end())
380                     nReopenTag = (*aIter).second;
381             }
382         }
383     }
384 
385     if ( -1 != nReopenTag )
386     {
387         nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement();
388         const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag );
389         ASSERT( bSuccess, "Failed to reopen tag" )
390 
391 #ifdef DBG_UTIL
392         aStructStack.push_back( 99 );
393 #endif
394 
395         bRet = bSuccess;
396     }
397 
398     return bRet && !bContinue;
399 }
400 
401 
402 /*
403  * SwTaggedPDFHelper::CheckRestoreTag()
404  */
CheckRestoreTag() const405 bool SwTaggedPDFHelper::CheckRestoreTag() const
406 {
407     bool bRet = false;
408     if ( nRestoreCurrentTag != -1 )
409     {
410         const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nRestoreCurrentTag );
411         (void)bSuccess;
412         ASSERT( bSuccess, "Failed to restore reopened tag" )
413 
414 #ifdef DBG_UTIL
415         aStructStack.pop_back();
416 #endif
417 
418         bRet = true;
419     }
420 
421     return bRet;
422 }
423 
424 
425 /*
426  * SwTaggedPDFHelper::BeginTag()
427  */
BeginTag(vcl::PDFWriter::StructElement eType,const String & rString)428 void SwTaggedPDFHelper::BeginTag( vcl::PDFWriter::StructElement eType, const String& rString )
429 {
430     // write new tag
431     const sal_Int32 nId = mpPDFExtOutDevData->BeginStructureElement( eType, rtl::OUString( rString ) );
432     ++nEndStructureElement;
433 
434 #ifdef DBG_UTIL
435     aStructStack.push_back( static_cast<sal_uInt16>(eType) );
436 #endif
437 
438     // Store the id of the current structure element if
439     // - it is a list structure element
440     // - it is a list body element with children
441     // - rFrm is the first page frame
442     // - rFrm is a master frame
443     // - rFrm has objects anchored to it
444     // - rFrm is a row frame or cell frame in a split table row
445 
446     if ( mpNumInfo )
447     {
448         const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(mpNumInfo->mrFrm);
449         const SwTxtNode* pTxtNd = rTxtFrm.GetTxtNode();
450         const SwNodeNum* pNodeNum = pTxtNd->GetNum();
451 
452         if ( vcl::PDFWriter::List == eType )
453         {
454             NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap();
455             rNumListIdMap[ pNodeNum ] = nId;
456         }
457         else if ( vcl::PDFWriter::LIBody == eType )
458         {
459             NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
460             rNumListBodyIdMap[ pNodeNum ] = nId;
461         }
462     }
463     else if ( mpFrmInfo )
464     {
465         const SwFrm& rFrm = mpFrmInfo->mrFrm;
466 
467         if ( ( rFrm.IsPageFrm() && !static_cast<const SwPageFrm&>(rFrm).GetPrev() ) ||
468              ( rFrm.IsFlowFrm() && !SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() && SwFlowFrm::CastFlowFrm(&rFrm)->HasFollow() ) ||
469              ( rFrm.IsTxtFrm() && rFrm.GetDrawObjs() ) ||
470              ( rFrm.IsRowFrm() && rFrm.IsInSplitTableRow() ) ||
471              ( rFrm.IsCellFrm() && const_cast<SwFrm&>(rFrm).GetNextCellLeaf( MAKEPAGE_NONE ) ) )
472         {
473             const void* pKey = lcl_GetKeyFromFrame( rFrm );
474 
475             if ( pKey )
476             {
477                 FrmTagIdMap& rFrmTagIdMap = SwEnhancedPDFExportHelper::GetFrmTagIdMap();
478                 rFrmTagIdMap[ pKey ] = nId;
479             }
480         }
481     }
482 
483     SetAttributes( eType );
484 }
485 
486 
487 /*
488  * SwTaggedPDFHelper::EndTag()
489  */
EndTag()490 void SwTaggedPDFHelper::EndTag()
491 {
492     mpPDFExtOutDevData->EndStructureElement();
493 
494 #ifdef DBG_UTIL
495     aStructStack.pop_back();
496 #endif
497 }
498 
499 
500 /*
501  * SwTaggedPDFHelper::SetAttributes()
502  *
503  * Sets the attributes according to the structure type.
504  */
SetAttributes(vcl::PDFWriter::StructElement eType)505 void SwTaggedPDFHelper::SetAttributes( vcl::PDFWriter::StructElement eType )
506 {
507     vcl::PDFWriter::StructAttributeValue eVal;
508     sal_Int32 nVal;
509 
510     /*
511      * ATTRIBUTES FOR BLSE
512      */
513     if ( mpFrmInfo )
514     {
515         const SwFrm* pFrm = &mpFrmInfo->mrFrm;
516         SWRECTFN( pFrm )
517 
518         bool bPlacement = false;
519         bool bWritingMode = false;
520         bool bSpaceBefore = false;
521         bool bSpaceAfter = false;
522         bool bStartIndent = false;
523         bool bEndIndent = false;
524         bool bTextIndent = false;
525         bool bTextAlign = false;
526         bool bAlternateText = false;
527         bool bWidth = false;
528         bool bHeight = false;
529         bool bBox = false;
530         bool bRowSpan = false;
531 
532         //
533         // Check which attributes to set:
534         //
535         switch ( eType )
536         {
537             case vcl::PDFWriter::Document :
538                 bWritingMode = true;
539                 break;
540 
541             case vcl::PDFWriter::Table :
542                 bPlacement =
543                 bWritingMode =
544                 bSpaceBefore =
545                 bSpaceAfter =
546                 bStartIndent =
547                 bEndIndent =
548                 bWidth =
549                 bHeight =
550                 bBox = true;
551                 break;
552 
553             case vcl::PDFWriter::TableRow :
554                 bPlacement =
555                 bWritingMode = true;
556                 break;
557 
558             case vcl::PDFWriter::TableHeader :
559             case vcl::PDFWriter::TableData :
560                 bPlacement =
561                 bWritingMode =
562                 bWidth =
563                 bHeight =
564                 bRowSpan = true;
565                 break;
566 
567             case vcl::PDFWriter::H1 :
568             case vcl::PDFWriter::H2 :
569             case vcl::PDFWriter::H3 :
570             case vcl::PDFWriter::H4 :
571             case vcl::PDFWriter::H5 :
572             case vcl::PDFWriter::H6 :
573             case vcl::PDFWriter::Paragraph :
574             case vcl::PDFWriter::Heading :
575             case vcl::PDFWriter::Caption :
576             case vcl::PDFWriter::BlockQuote :
577 
578                 bPlacement =
579                 bWritingMode =
580                 bSpaceBefore =
581                 bSpaceAfter =
582                 bStartIndent =
583                 bEndIndent =
584                 bTextIndent =
585                 bTextAlign = true;
586                 break;
587 
588             case vcl::PDFWriter::Formula :
589             case vcl::PDFWriter::Figure :
590                 bPlacement =
591                 bAlternateText =
592                 bWidth =
593                 bHeight =
594                 bBox = true;
595                 break;
596             default :
597                 break;
598         }
599 
600         //
601         // Set the attributes:
602         //
603         if ( bPlacement )
604         {
605             eVal = vcl::PDFWriter::TableHeader == eType ||
606                    vcl::PDFWriter::TableData   == eType ?
607                    vcl::PDFWriter::Inline :
608                    vcl::PDFWriter::Block;
609 
610             mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::Placement, eVal );
611         }
612 
613         if ( bWritingMode )
614         {
615             eVal =  pFrm->IsVertical() ?
616                     vcl::PDFWriter::TbRl :
617                     pFrm->IsRightToLeft() ?
618                     vcl::PDFWriter::RlTb :
619                     vcl::PDFWriter::LrTb;
620 
621             if ( vcl::PDFWriter::LrTb != eVal )
622                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::WritingMode, eVal );
623         }
624 
625         if ( bSpaceBefore )
626         {
627             nVal = (pFrm->*fnRect->fnGetTopMargin)();
628             if ( 0 != nVal )
629                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::SpaceBefore, nVal );
630         }
631 
632         if ( bSpaceAfter )
633         {
634             nVal = (pFrm->*fnRect->fnGetBottomMargin)();
635             if ( 0 != nVal )
636                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::SpaceAfter, nVal );
637         }
638 
639         if ( bStartIndent )
640         {
641             nVal = (pFrm->*fnRect->fnGetLeftMargin)();
642             if ( 0 != nVal )
643                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::StartIndent, nVal );
644         }
645 
646         if ( bEndIndent )
647         {
648             nVal = (pFrm->*fnRect->fnGetRightMargin)();
649             if ( 0 != nVal )
650                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::EndIndent, nVal );
651         }
652 
653         if ( bTextIndent )
654         {
655             ASSERT( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" )
656             const SvxLRSpaceItem &rSpace =
657                 static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode()->GetSwAttrSet().GetLRSpace();
658             nVal =  rSpace.GetTxtFirstLineOfst();
659             if ( 0 != nVal )
660                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::TextIndent, nVal );
661         }
662 
663         if ( bTextAlign )
664         {
665             ASSERT( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" )
666             const SwAttrSet& aSet = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode()->GetSwAttrSet();
667             const SvxAdjust nAdjust = aSet.GetAdjust().GetAdjust();
668             if ( SVX_ADJUST_BLOCK == nAdjust || SVX_ADJUST_CENTER == nAdjust ||
669                  (  (pFrm->IsRightToLeft() && SVX_ADJUST_LEFT == nAdjust) ||
670                    (!pFrm->IsRightToLeft() && SVX_ADJUST_RIGHT == nAdjust) ) )
671             {
672                 eVal = SVX_ADJUST_BLOCK == nAdjust ?
673                        vcl::PDFWriter::Justify :
674                        SVX_ADJUST_CENTER == nAdjust ?
675                        vcl::PDFWriter::Center :
676                        vcl::PDFWriter::End;
677 
678                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextAlign, eVal );
679             }
680         }
681 
682         if ( bAlternateText )
683         {
684             ASSERT( pFrm->IsFlyFrm(), "Frame type <-> tag attribute mismatch" )
685             const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pFrm);
686             if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() )
687             {
688                 const SwNoTxtFrm* pNoTxtFrm   = static_cast<const SwNoTxtFrm*>(pFly->Lower());
689                 const SwNoTxtNode* pNoTxtNode = static_cast<const SwNoTxtNode*>(pNoTxtFrm->GetNode());
690 
691                 const String aAlternateTxt( pNoTxtNode->GetTitle() );
692                 mpPDFExtOutDevData->SetAlternateText( aAlternateTxt );
693             }
694         }
695 
696         if ( bWidth )
697         {
698             nVal = (pFrm->Frm().*fnRect->fnGetWidth)();
699             mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Width, nVal );
700         }
701 
702         if ( bHeight )
703         {
704             nVal = (pFrm->Frm().*fnRect->fnGetHeight)();
705             mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Height, nVal );
706         }
707 
708         if ( bBox )
709         {
710             // BBox only for non-split tables:
711             if ( vcl::PDFWriter::Table != eType ||
712                  ( pFrm->IsTabFrm() &&
713                    !static_cast<const SwTabFrm*>(pFrm)->IsFollow() &&
714                    !static_cast<const SwTabFrm*>(pFrm)->HasFollow() ) )
715                 mpPDFExtOutDevData->SetStructureBoundingBox( pFrm->Frm().SVRect() );
716         }
717 
718         if ( bRowSpan )
719         {
720             const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(pFrm);
721             if ( pThisCell )
722             {
723                 nVal =  pThisCell->GetTabBox()->getRowSpan();
724                 if ( nVal > 1 )
725                     mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::RowSpan, nVal );
726 
727                 // calculate colspan:
728                 const SwTabFrm* pTabFrm = pThisCell->FindTabFrm();
729                 const SwTable* pTable = pTabFrm->GetTable();
730 
731                 SWRECTFNX( pTabFrm )
732 
733                 const TableColumnsMapEntry& rCols = SwEnhancedPDFExportHelper::GetTableColumnsMap()[ pTable ];
734 
735                 const long nLeft  = (pThisCell->Frm().*fnRectX->fnGetLeft)();
736                 const long nRight = (pThisCell->Frm().*fnRectX->fnGetRight)();
737                 const TableColumnsMapEntry::const_iterator aLeftIter =  rCols.find( nLeft );
738                 const TableColumnsMapEntry::const_iterator aRightIter = rCols.find( nRight );
739 
740                 ASSERT( aLeftIter != rCols.end() && aRightIter != rCols.end(), "Colspan trouble" )
741                 if ( aLeftIter != rCols.end() && aRightIter != rCols.end() )
742                 {
743                     nVal = std::distance( aLeftIter, aRightIter );
744                     if ( nVal > 1 )
745                         mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::ColSpan, nVal );
746                 }
747             }
748         }
749     }
750 
751     /*
752      * ATTRIBUTES FOR ILSE
753      */
754     else if ( mpPorInfo )
755     {
756         const SwLinePortion* pPor = &mpPorInfo->mrPor;
757         const SwTxtPaintInfo& rInf = mpPorInfo->mrTxtPainter.GetInfo();
758 
759         bool bActualText = false;
760         bool bBaselineShift = false;
761         bool bTextDecorationType = false;
762         bool bLinkAttribute = false;
763         bool bLanguage = false;
764 
765         //
766         // Check which attributes to set:
767         //
768         switch ( eType )
769         {
770             case vcl::PDFWriter::Span :
771             case vcl::PDFWriter::Quote :
772             case vcl::PDFWriter::Code :
773                 if( POR_HYPHSTR == pPor->GetWhichPor() || POR_SOFTHYPHSTR == pPor->GetWhichPor() )
774                     bActualText = true;
775                 else
776                 {
777                     bBaselineShift =
778                     bTextDecorationType =
779                     bLanguage = true;
780                 }
781                 break;
782 
783             case vcl::PDFWriter::Link :
784                 bTextDecorationType =
785                 bBaselineShift =
786                 bLinkAttribute =
787                 bLanguage = true;
788                 break;
789 
790             default:
791                 break;
792         }
793 
794         if ( bActualText )
795         {
796             const String aActualTxt( rInf.GetTxt(), rInf.GetIdx(), pPor->GetLen() );
797             mpPDFExtOutDevData->SetActualText( aActualTxt );
798         }
799 
800         if ( bBaselineShift )
801         {
802             // TODO: Calculate correct values!
803             nVal = rInf.GetFont()->GetEscapement();
804             if ( nVal > 0 ) nVal = 33;
805             else if ( nVal < 0 ) nVal = -33;
806 
807             if ( 0 != nVal )
808             {
809                 nVal = nVal * pPor->Height() / 100;
810                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::BaselineShift, nVal );
811             }
812         }
813 
814         if ( bTextDecorationType )
815         {
816             if ( UNDERLINE_NONE    != rInf.GetFont()->GetUnderline() )
817                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Underline );
818             if ( UNDERLINE_NONE    != rInf.GetFont()->GetOverline() )
819                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Overline );
820             if ( STRIKEOUT_NONE    != rInf.GetFont()->GetStrikeout() )
821                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::LineThrough );
822             if ( EMPHASISMARK_NONE != rInf.GetFont()->GetEmphasisMark() )
823                 mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Overline );
824         }
825 
826         if ( bLanguage )
827         {
828 
829             const LanguageType nCurrentLanguage = rInf.GetFont()->GetLanguage();
830             const LanguageType nDefaultLang = SwEnhancedPDFExportHelper::GetDefaultLanguage();
831 
832             if ( nDefaultLang != nCurrentLanguage )
833                 mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Language, nCurrentLanguage );
834         }
835 
836         if ( bLinkAttribute )
837         {
838             const LinkIdMap& rLinkIdMap = SwEnhancedPDFExportHelper::GetLinkIdMap();
839             SwRect aPorRect;
840             rInf.CalcRect( *pPor, &aPorRect );
841             const Point aPorCenter = aPorRect.Center();
842             LinkIdMap::const_iterator aIter;
843             for ( aIter = rLinkIdMap.begin(); aIter != rLinkIdMap.end(); ++aIter )
844             {
845                 const SwRect& rLinkRect = (*aIter).first;
846                 if ( rLinkRect.IsInside( aPorCenter ) )
847                 {
848                     sal_Int32 nLinkId = (*aIter).second;
849                     mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::LinkAnnotation, nLinkId );
850                     break;
851                 }
852             }
853         }
854     }
855 }
856 
857 /*
858  * SwTaggedPDFHelper::BeginNumberedListStructureElements()
859  */
BeginNumberedListStructureElements()860 void SwTaggedPDFHelper::BeginNumberedListStructureElements()
861 {
862     ASSERT( mpNumInfo, "List without mpNumInfo?" )
863     if ( !mpNumInfo )
864         return;
865 
866     const SwFrm& rFrm = mpNumInfo->mrFrm;
867     ASSERT( rFrm.IsTxtFrm(), "numbered only for text frames" )
868     const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(rFrm);
869 
870     //
871     // Lowers of NonStructureElements should not be considered:
872     //
873     if ( lcl_IsInNonStructEnv( rTxtFrm ) || rTxtFrm.IsFollow() )
874         return;
875 
876     const SwTxtNode* pTxtNd = rTxtFrm.GetTxtNode();
877     const SwNumRule* pNumRule = pTxtNd->GetNumRule();
878     const SwNodeNum* pNodeNum = pTxtNd->GetNum();
879 
880     const bool bNumbered = !pTxtNd->IsOutline() && pNodeNum && pNodeNum->GetParent() && pNumRule;
881 
882     // Check, if we have to reopen a list or a list body:
883     // First condition:
884     // Paragraph is numbered/bulleted
885     if ( !bNumbered )
886         return;
887 
888     const SwNumberTreeNode* pParent = pNodeNum->GetParent();
889     const bool bSameNumbering = lcl_HasPreviousParaSameNumRule(*pTxtNd);
890 
891     // Second condition: current numbering is not 'interrupted'
892     if ( bSameNumbering )
893     {
894         sal_Int32 nReopenTag = -1;
895 
896         // Two cases:
897         // 1. We have to reopen an existing list body tag:
898         // - If the current node is either the first child of its parent
899         //   and its level > 1 or
900         // - Numbering should restart at the current node and its level > 1
901         // - The current item has no label
902         const bool bNewSubListStart = pParent->GetParent() && (pParent->IsFirst( pNodeNum ) || pTxtNd->IsListRestart() );
903         const bool bNoLabel = !pTxtNd->IsCountedInList() && !pTxtNd->IsListRestart();
904         if ( bNewSubListStart || bNoLabel )
905         {
906             // Fine, we try to reopen the appropriate list body
907             NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
908 
909             if ( bNewSubListStart )
910             {
911                 // The list body tag associated with the parent has to be reopened
912                 // to start a new list inside the list body
913                 NumListBodyIdMap::const_iterator aIter;
914 
915                 do
916                     aIter = rNumListBodyIdMap.find( pParent );
917                 while ( aIter == rNumListBodyIdMap.end() && 0 != ( pParent = pParent->GetParent() ) );
918 
919                 if ( aIter != rNumListBodyIdMap.end() )
920                     nReopenTag = (*aIter).second;
921             }
922             else // if(bNoLabel)
923             {
924                 // The list body tag of a 'counted' predecessor has to be reopened
925                 const SwNumberTreeNode* pPrevious = pNodeNum->GetPred(true);
926                 while ( pPrevious )
927                 {
928                     if ( pPrevious->IsCounted())
929                     {
930                         // get id of list body tag
931                         const NumListBodyIdMap::const_iterator aIter =  rNumListBodyIdMap.find( pPrevious );
932                         if ( aIter != rNumListBodyIdMap.end() )
933                         {
934                             nReopenTag = (*aIter).second;
935                             break;
936                         }
937                     }
938                     pPrevious = pPrevious->GetPred(true);
939                 }
940             }
941         }
942         // 2. We have to reopen an existing list tag:
943         else if ( !pParent->IsFirst( pNodeNum ) && !pTxtNd->IsListRestart() )
944         {
945             // any other than the first node in a list level has to reopen the current
946             // list. The current list is associated in a map with the first child of the list:
947             NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap();
948 
949             // Search backwards and check if any of the previous nodes has a list associated with it:
950             const SwNumberTreeNode* pPrevious = pNodeNum->GetPred(true);
951             while ( pPrevious )
952             {
953                 // get id of list tag
954                 const NumListIdMap::const_iterator aIter =  rNumListIdMap.find( pPrevious );
955                 if ( aIter != rNumListIdMap.end() )
956                 {
957                     nReopenTag = (*aIter).second;
958                     break;
959                 }
960 
961                 pPrevious = pPrevious->GetPred(true);
962             }
963         }
964 
965         if ( -1 != nReopenTag )
966         {
967             nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement();
968             mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag );
969 
970 #ifdef DBG_UTIL
971             aStructStack.push_back( 99 );
972 #endif
973         }
974     }
975     else
976     {
977         // clear list maps in case a list has been interrupted
978         NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap();
979         rNumListIdMap.clear();
980         NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
981         rNumListBodyIdMap.clear();
982     }
983 
984     // New tags:
985     const bool bNewListTag = (pNodeNum->GetParent()->IsFirst( pNodeNum ) || pTxtNd->IsListRestart() || !bSameNumbering);
986     const bool bNewItemTag = bNewListTag || pTxtNd->IsCountedInList(); // If the text node is not counted, we do not start a new list item:
987 
988     if ( bNewListTag )
989         BeginTag( vcl::PDFWriter::List, aListString );
990 
991     if ( bNewItemTag )
992     {
993         BeginTag( vcl::PDFWriter::ListItem, aListItemString );
994         BeginTag( vcl::PDFWriter::LIBody, aListBodyString );
995     }
996 }
997 
998 /*
999  * SwTaggedPDFHelper::BeginBlockStructureElements()
1000  */
BeginBlockStructureElements()1001 void SwTaggedPDFHelper::BeginBlockStructureElements()
1002 {
1003     const SwFrm* pFrm = &mpFrmInfo->mrFrm;
1004 
1005     //
1006     // Lowers of NonStructureElements should not be considered:
1007     //
1008     if ( lcl_IsInNonStructEnv( *pFrm ) )
1009         return;
1010 
1011     // Check if we have to reopen an existing structure element.
1012     // This has to be done e.g., if pFrm is a follow frame.
1013     if ( CheckReopenTag() )
1014         return;
1015 
1016     sal_uInt16 nPDFType = USHRT_MAX;
1017     String aPDFType;
1018 
1019     switch ( pFrm->GetType() )
1020     {
1021         /*
1022          * GROUPING ELEMENTS
1023          */
1024 
1025         case FRM_PAGE :
1026             //
1027             // Document: Document
1028             //
1029             nPDFType = vcl::PDFWriter::Document;
1030             aPDFType = aDocumentString;
1031             break;
1032 
1033         case FRM_HEADER :
1034         case FRM_FOOTER :
1035             //
1036             // Header, Footer: NonStructElement
1037             //
1038             nPDFType = vcl::PDFWriter::NonStructElement;
1039             break;
1040 
1041         case FRM_FTNCONT :
1042             //
1043             // Footnote container: Division
1044             //
1045             nPDFType = vcl::PDFWriter::Division;
1046             aPDFType = aDivString;
1047             break;
1048 
1049         case FRM_FTN :
1050             //
1051             // Footnote frame: Note
1052             //
1053             // Note: vcl::PDFWriter::Note is actually a ILSE. Nevertheless
1054             // we treat it like a grouping element!
1055             nPDFType = vcl::PDFWriter::Note;
1056             aPDFType = aNoteString;
1057             break;
1058 
1059         case FRM_SECTION :
1060             //
1061             // Section: TOX, Index, or Sect
1062             //
1063             {
1064                 const SwSection* pSection =
1065                         static_cast<const SwSectionFrm*>(pFrm)->GetSection();
1066                 if ( TOX_CONTENT_SECTION == pSection->GetType() )
1067                 {
1068                     const SwTOXBase* pTOXBase = pSection->GetTOXBase();
1069                     if ( pTOXBase )
1070                     {
1071                         if ( TOX_INDEX == pTOXBase->GetType() )
1072                         {
1073                             nPDFType = vcl::PDFWriter::Index;
1074                             aPDFType = aIndexString;
1075                         }
1076                         else
1077                         {
1078                             nPDFType = vcl::PDFWriter::TOC;
1079                             aPDFType = aTOCString;
1080                         }
1081                     }
1082                 }
1083                 else if ( CONTENT_SECTION == pSection->GetType() )
1084                 {
1085                     nPDFType = vcl::PDFWriter::Section;
1086                     aPDFType = aSectString;
1087                 }
1088             }
1089             break;
1090 
1091         /*
1092          * BLOCK-LEVEL STRUCTURE ELEMENTS
1093          */
1094 
1095         case FRM_TXT :
1096             {
1097                 const SwTxtNode* pTxtNd =
1098                     static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode();
1099 
1100                 const SwFmt* pTxtFmt = pTxtNd->GetFmtColl();
1101                 const SwFmt* pParentTxtFmt = pTxtFmt->DerivedFrom();
1102 
1103                 String sStyleName;
1104                 String sParentStyleName;
1105 
1106                 if ( pTxtFmt)
1107                     SwStyleNameMapper::FillProgName( pTxtFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
1108                 if ( pParentTxtFmt)
1109                     SwStyleNameMapper::FillProgName( pParentTxtFmt->GetName(), sParentStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
1110 
1111                 // This is the default. If the paragraph could not be mapped to
1112                 // any of the standard pdf tags, we write a user defined tag
1113                 // <stylename> with role = P
1114                 nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Paragraph);
1115                 aPDFType = sStyleName;
1116 
1117                 //
1118                 // Quotations: BlockQuote
1119                 //
1120                 if ( sStyleName == aQuotations )
1121                 {
1122                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::BlockQuote);
1123                     aPDFType = aBlockQuoteString;
1124                 }
1125 
1126                 //
1127                 // Caption: Caption
1128                 //
1129                 else if ( sStyleName == aCaption)
1130                 {
1131                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Caption);
1132                     aPDFType = aCaptionString;
1133                 }
1134 
1135                 //
1136                 // Caption: Caption
1137                 //
1138                 else if ( sParentStyleName == aCaption)
1139                 {
1140                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Caption);
1141                     aPDFType = sStyleName.Append(aCaptionString);
1142                 }
1143 
1144                 //
1145                 // Heading: H
1146                 //
1147                 else if ( sStyleName == aHeading )
1148                 {
1149                     nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Heading);
1150                     aPDFType = aHString;
1151                 }
1152 
1153                 //
1154                 // Heading: H1 - H6
1155                 //
1156                 if ( pTxtNd->IsOutline() )
1157                 {
1158                     //int nRealLevel = pTxtNd->GetOutlineLevel();	//#outline level,zhaojianwei
1159 					int nRealLevel = pTxtNd->GetAttrOutlineLevel()-1;		//<-end,zhaojianwei
1160                    nRealLevel = nRealLevel > 5 ? 5 : nRealLevel;
1161 
1162                     nPDFType =  static_cast<sal_uInt16>(vcl::PDFWriter::H1 + nRealLevel);
1163                     switch(nRealLevel)
1164                     {
1165                         case 0 :
1166                             aPDFType = aH1String;
1167                             break;
1168                         case 1 :
1169                             aPDFType = aH2String;
1170                             break;
1171                         case 2 :
1172                             aPDFType = aH3String;
1173                             break;
1174                         case 3 :
1175                             aPDFType = aH4String;
1176                             break;
1177                         case 4 :
1178                             aPDFType = aH5String;
1179                             break;
1180                         default:
1181                             aPDFType = aH6String;
1182                             break;
1183                     }
1184                 }
1185 
1186                 //
1187                 // Section: TOCI
1188                 //
1189                 else if ( pFrm->IsInSct() )
1190                 {
1191                     const SwSectionFrm* pSctFrm = pFrm->FindSctFrm();
1192                     const SwSection* pSection =
1193                             static_cast<const SwSectionFrm*>(pSctFrm)->GetSection();
1194 
1195                     if ( TOX_CONTENT_SECTION == pSection->GetType() )
1196                     {
1197                         const SwTOXBase* pTOXBase = pSection->GetTOXBase();
1198                         if ( pTOXBase && TOX_INDEX != pTOXBase->GetType() )
1199                         {
1200                             // Special case: Open additional TOCI tag:
1201                             BeginTag( vcl::PDFWriter::TOCI, aTOCIString );
1202                         }
1203                     }
1204                 }
1205             }
1206             break;
1207 
1208         case FRM_TAB :
1209             //
1210             // TabFrm: Table
1211             //
1212             nPDFType = vcl::PDFWriter::Table;
1213             aPDFType = aTableString;
1214 
1215             {
1216                 // set up table column data:
1217                 const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>(pFrm);
1218                 const SwTable* pTable = pTabFrm->GetTable();
1219 
1220                 TableColumnsMap& rTableColumnsMap = SwEnhancedPDFExportHelper::GetTableColumnsMap();
1221                 const TableColumnsMap::const_iterator aIter = rTableColumnsMap.find( pTable );
1222 
1223                 if ( aIter == rTableColumnsMap.end() )
1224                 {
1225                     SWRECTFN( pTabFrm )
1226                     TableColumnsMapEntry& rCols = rTableColumnsMap[ pTable ];
1227 
1228                     const SwTabFrm* pMasterFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm;
1229 
1230                     while ( pMasterFrm )
1231                     {
1232                         const SwRowFrm* pRowFrm = static_cast<const SwRowFrm*>(pMasterFrm->GetLower());
1233 
1234                         while ( pRowFrm )
1235                         {
1236                             const SwFrm* pCellFrm = pRowFrm->GetLower();
1237 
1238                             const long nLeft  = (pCellFrm->Frm().*fnRect->fnGetLeft)();
1239                             rCols.insert( nLeft );
1240 
1241                             while ( pCellFrm )
1242                             {
1243                                 const long nRight = (pCellFrm->Frm().*fnRect->fnGetRight)();
1244                                 rCols.insert( nRight );
1245                                 pCellFrm = pCellFrm->GetNext();
1246                             }
1247                             pRowFrm = static_cast<const SwRowFrm*>(pRowFrm->GetNext());
1248                         }
1249                         pMasterFrm = static_cast<const SwTabFrm*>(pMasterFrm->GetFollow());
1250                     }
1251                 }
1252             }
1253 
1254             break;
1255 
1256         /*
1257          * TABLE ELEMENTS
1258          */
1259 
1260         case FRM_ROW :
1261             //
1262             // RowFrm: TR
1263             //
1264             if ( !static_cast<const SwRowFrm*>(pFrm)->IsRepeatedHeadline() )
1265             {
1266                 nPDFType = vcl::PDFWriter::TableRow;
1267                 aPDFType = aTRString;
1268             }
1269             else
1270             {
1271                 nPDFType = vcl::PDFWriter::NonStructElement;
1272             }
1273             break;
1274 
1275         case FRM_CELL :
1276             //
1277             // CellFrm: TH, TD
1278             //
1279             {
1280                 const SwTabFrm* pTable = static_cast<const SwCellFrm*>(pFrm)->FindTabFrm();
1281                 if ( pTable->IsInHeadline( *pFrm ) || lcl_IsHeadlineCell( *static_cast<const SwCellFrm*>(pFrm) ) )
1282                 {
1283                     nPDFType = vcl::PDFWriter::TableHeader;
1284                     aPDFType = aTHString;
1285                 }
1286                 else
1287                 {
1288                     nPDFType = vcl::PDFWriter::TableData;
1289                     aPDFType = aTDString;
1290                 }
1291             }
1292             break;
1293 
1294         /*
1295          * ILLUSTRATION
1296          */
1297 
1298         case FRM_FLY :
1299             //
1300             // FlyFrm: Figure, Formula, Control
1301             // fly in content or fly at page
1302             {
1303                 bool bFormula = false;
1304                 const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pFrm);
1305                 if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() )
1306                 {
1307                     const SwNoTxtFrm* pNoTxtFrm = static_cast<const SwNoTxtFrm*>(pFly->Lower());
1308                     SwOLENode* pOLENd = const_cast<SwOLENode*>(pNoTxtFrm->GetNode()->GetOLENode());
1309                     if ( pOLENd )
1310                     {
1311                         SwOLEObj& aOLEObj = pOLENd->GetOLEObj();
1312                         uno::Reference< embed::XEmbeddedObject > aRef = aOLEObj.GetOleRef();
1313                         if ( aRef.is() )
1314                         {
1315                             bFormula = 0 != SotExchange::IsMath( SvGlobalName( aRef->getClassID() ) );
1316                         }
1317                     }
1318                     if ( bFormula )
1319                     {
1320                         nPDFType = vcl::PDFWriter::Formula;
1321                         aPDFType = aFormulaString;
1322                     }
1323                     else
1324                     {
1325                         nPDFType = vcl::PDFWriter::Figure;
1326                         aPDFType = aFigureString;
1327                     }
1328                 }
1329                 else
1330                 {
1331                     nPDFType = vcl::PDFWriter::Division;
1332                     aPDFType = aDivString;
1333                 }
1334             }
1335             break;
1336     }
1337 
1338     if ( USHRT_MAX != nPDFType )
1339     {
1340         BeginTag( static_cast<vcl::PDFWriter::StructElement>(nPDFType), aPDFType );
1341     }
1342 }
1343 
1344 
1345 /*
1346  * SwTaggedPDFHelper::EndStructureElements()
1347  */
EndStructureElements()1348 void SwTaggedPDFHelper::EndStructureElements()
1349 {
1350     while ( nEndStructureElement > 0 )
1351     {
1352         EndTag();
1353         --nEndStructureElement;
1354     }
1355 
1356     CheckRestoreTag();
1357 }
1358 
1359 
1360 /*
1361  * SwTaggedPDFHelper::BeginInlineStructureElements()
1362  */
BeginInlineStructureElements()1363 void SwTaggedPDFHelper::BeginInlineStructureElements()
1364 {
1365     const SwLinePortion* pPor = &mpPorInfo->mrPor;
1366     const SwTxtPaintInfo& rInf = mpPorInfo->mrTxtPainter.GetInfo();
1367     const SwTxtFrm* pFrm = rInf.GetTxtFrm();
1368 
1369     //
1370     // Lowers of NonStructureElements should not be considered:
1371     //
1372     if ( lcl_IsInNonStructEnv( *pFrm ) )
1373         return;
1374 
1375     sal_uInt16 nPDFType = USHRT_MAX;
1376     String aPDFType;
1377 
1378     switch ( pPor->GetWhichPor() )
1379     {
1380         // Check for alternative spelling:
1381         case POR_HYPHSTR :
1382         case POR_SOFTHYPHSTR :
1383             nPDFType = vcl::PDFWriter::Span;
1384             aPDFType = aSpanString;
1385             break;
1386 
1387         case POR_LAY :
1388         case POR_TXT :
1389         case POR_PARA :
1390             {
1391                 SwTxtNode* pNd = (SwTxtNode*)pFrm->GetTxtNode();
1392                 SwTxtAttr const*const pInetFmtAttr =
1393                     pNd->GetTxtAttrAt(rInf.GetIdx(), RES_TXTATR_INETFMT);
1394 
1395                 String sStyleName;
1396                 if ( !pInetFmtAttr )
1397                 {
1398                     ::std::vector<SwTxtAttr *> const charAttrs(
1399                         pNd->GetTxtAttrsAt(rInf.GetIdx(), RES_TXTATR_CHARFMT));
1400                     // TODO: handle more than 1 char style?
1401                     const SwCharFmt* pCharFmt = (charAttrs.size())
1402                         ? (*charAttrs.begin())->GetCharFmt().GetCharFmt() : 0;
1403                     if ( pCharFmt )
1404                         SwStyleNameMapper::FillProgName( pCharFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
1405                 }
1406 
1407                 // Check for Link:
1408 		        if( pInetFmtAttr )
1409 		        {
1410                     nPDFType = vcl::PDFWriter::Link;
1411                     aPDFType = aLinkString;
1412                 }
1413                 // Check for Quote/Code character style:
1414                 else if ( sStyleName == aQuotation )
1415                 {
1416                     nPDFType = vcl::PDFWriter::Quote;
1417                     aPDFType = aQuoteString;
1418                 }
1419                 else if ( sStyleName == aSourceText )
1420                 {
1421                     nPDFType = vcl::PDFWriter::Code;
1422                     aPDFType = aCodeString;
1423                 }
1424                 else
1425                 {
1426                     const LanguageType nCurrentLanguage = rInf.GetFont()->GetLanguage();
1427                     const sal_uInt16 nFont = rInf.GetFont()->GetActual();
1428                     const LanguageType nDefaultLang = SwEnhancedPDFExportHelper::GetDefaultLanguage();
1429 
1430                     if ( UNDERLINE_NONE    != rInf.GetFont()->GetUnderline() ||
1431                          UNDERLINE_NONE    != rInf.GetFont()->GetOverline()  ||
1432                          STRIKEOUT_NONE    != rInf.GetFont()->GetStrikeout() ||
1433                          EMPHASISMARK_NONE != rInf.GetFont()->GetEmphasisMark() ||
1434                          0                 != rInf.GetFont()->GetEscapement() ||
1435                          SW_LATIN          != nFont ||
1436                          nCurrentLanguage  != nDefaultLang ||
1437                          sStyleName.Len()  > 0 )
1438                     {
1439                         nPDFType = vcl::PDFWriter::Span;
1440                         if ( sStyleName.Len() > 0 )
1441                             aPDFType = sStyleName;
1442                         else
1443                             aPDFType = aSpanString;
1444                     }
1445                 }
1446             }
1447             break;
1448 
1449         case POR_FTN :
1450             nPDFType = vcl::PDFWriter::Link;
1451             aPDFType = aLinkString;
1452             break;
1453 
1454         case POR_FLD :
1455             {
1456                 // check field type:
1457                 const xub_StrLen nIdx = static_cast<const SwFldPortion*>(pPor)->IsFollow() ?
1458                                         rInf.GetIdx() - 1 :
1459                                         rInf.GetIdx();
1460                 const SwTxtAttr* pHint = mpPorInfo->mrTxtPainter.GetAttr( nIdx );
1461                 const SwField* pFld = 0;
1462                 if ( pHint && RES_TXTATR_FIELD == pHint->Which() )
1463                 {
1464                     pFld = (SwField*)pHint->GetFmtFld().GetField();
1465                     if ( RES_GETREFFLD == pFld->Which() )
1466                     {
1467                         nPDFType = vcl::PDFWriter::Link;
1468                         aPDFType = aLinkString;
1469                     }
1470                     else if ( RES_AUTHORITY == pFld->Which() )
1471                     {
1472                         nPDFType = vcl::PDFWriter::BibEntry;
1473                         aPDFType = aBibEntryString;
1474                     }
1475                 }
1476             }
1477             break;
1478 
1479         case POR_TAB :
1480         case POR_TABRIGHT :
1481         case POR_TABCENTER :
1482         case POR_TABDECIMAL :
1483             nPDFType = vcl::PDFWriter::NonStructElement;
1484             break;
1485     }
1486 
1487     if ( USHRT_MAX != nPDFType )
1488     {
1489         BeginTag( static_cast<vcl::PDFWriter::StructElement>(nPDFType), aPDFType );
1490     }
1491 }
1492 
1493 /*
1494  * static SwTaggedPDFHelper::IsExportTaggedPDF
1495  */
IsExportTaggedPDF(const OutputDevice & rOut)1496  bool SwTaggedPDFHelper::IsExportTaggedPDF( const OutputDevice& rOut )
1497  {
1498     vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, rOut.GetExtOutDevData() );
1499     return pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF();
1500  }
1501 
1502 /*
1503  * SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper()
1504  */
SwEnhancedPDFExportHelper(SwEditShell & rSh,OutputDevice & rOut,const rtl::OUString & rPageRange,bool bSkipEmptyPages,bool bEditEngineOnly)1505 SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper( SwEditShell& rSh,
1506                                                       OutputDevice& rOut,
1507                                                       const rtl::OUString& rPageRange,
1508                                                       bool bSkipEmptyPages,
1509                                                       bool bEditEngineOnly )
1510     : mrSh( rSh ),
1511       mrOut( rOut ),
1512       pPageRange( 0 ),
1513       mbSkipEmptyPages( bSkipEmptyPages ),
1514       mbEditEngineOnly( bEditEngineOnly )
1515 {
1516     if ( rPageRange.getLength() )
1517         pPageRange = new MultiSelection( rPageRange );
1518 
1519     aTableColumnsMap.clear();
1520     aLinkIdMap.clear();
1521     aNumListIdMap.clear();
1522     aNumListBodyIdMap.clear();
1523     aFrmTagIdMap.clear();
1524 
1525 #ifdef DBG_UTIL
1526     aStructStack.clear();
1527 #endif
1528 
1529     const sal_uInt8 nScript = (sal_uInt8)GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() );
1530     sal_uInt16 nLangRes = RES_CHRATR_LANGUAGE;
1531 
1532     if ( i18n::ScriptType::ASIAN == nScript )
1533         nLangRes = RES_CHRATR_CJK_LANGUAGE;
1534     else if ( i18n::ScriptType::COMPLEX == nScript )
1535         nLangRes = RES_CHRATR_CTL_LANGUAGE;
1536 
1537     eLanguageDefault = static_cast<const SvxLanguageItem*>(&mrSh.GetDoc()->GetDefault( nLangRes ))->GetLanguage();
1538 
1539     EnhancedPDFExport();
1540 }
1541 
~SwEnhancedPDFExportHelper()1542 SwEnhancedPDFExportHelper::~SwEnhancedPDFExportHelper()
1543 {
1544     delete pPageRange;
1545 }
1546 
1547 /*
1548  * SwEnhancedPDFExportHelper::EnhancedPDFExport()
1549  */
EnhancedPDFExport()1550 void SwEnhancedPDFExportHelper::EnhancedPDFExport()
1551 {
1552     vcl::PDFExtOutDevData* pPDFExtOutDevData =
1553         PTR_CAST( vcl::PDFExtOutDevData, mrOut.GetExtOutDevData() );
1554 
1555     if ( !pPDFExtOutDevData )
1556         return;
1557 
1558     //
1559     // set the document locale
1560     //
1561     com::sun::star::lang::Locale aDocLocale = MsLangId::convertLanguageToLocale( SwEnhancedPDFExportHelper::GetDefaultLanguage() );
1562     pPDFExtOutDevData->SetDocumentLocale( aDocLocale );
1563 
1564     //
1565     // Prepare the output device:
1566     //
1567     mrOut.Push( PUSH_MAPMODE );
1568     MapMode aMapMode( mrOut.GetMapMode() );
1569     aMapMode.SetMapUnit( MAP_TWIP );
1570     mrOut.SetMapMode( aMapMode );
1571 
1572     //
1573     // Create new cursor and lock the view:
1574     //
1575     SwDoc* pDoc = mrSh.GetDoc();
1576     mrSh.SwCrsrShell::Push();
1577     mrSh.SwCrsrShell::ClearMark();
1578     const sal_Bool bOldLockView = mrSh.IsViewLocked();
1579     mrSh.LockView( sal_True );
1580 
1581     if ( !mbEditEngineOnly )
1582     {
1583         //
1584         // POSTITS
1585         //
1586         if ( pPDFExtOutDevData->GetIsExportNotes() )
1587         {
1588             SwFieldType* pType = mrSh.GetFldType( RES_POSTITFLD, aEmptyStr );
1589             SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
1590             for( SwFmtFld* pFirst = aIter.First(); pFirst; )
1591             {
1592                 if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() )
1593                 {
1594                     const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode();
1595                     ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1596 
1597                     // 1. Check if the whole paragraph is hidden
1598                     // 2. Move to the field
1599                     // 3. Check for hidden text attribute
1600                     if ( !pTNd->IsHidden() &&
1601                           mrSh.GotoFld( *pFirst ) &&
1602                          !mrSh.SelectHiddenRange() )
1603                     {
1604                         // Link Rectangle
1605                         const SwRect& rNoteRect = mrSh.GetCharRect();
1606 
1607                         // Link PageNum
1608                         const sal_Int32 nNotePageNum = CalcOutputPageNum( rNoteRect );
1609                         if ( -1 != nNotePageNum )
1610 		                    {
1611                             // Link Note
1612                             vcl::PDFNote aNote;
1613 
1614                             // Use the NumberFormatter to get the date string:
1615                             const SwPostItField* pField = (SwPostItField*)pFirst->GetField();
1616                             SvNumberFormatter* pNumFormatter = pDoc->GetNumberFormatter();
1617                             const Date aDateDiff( pField->GetDate() -
1618                                                  *pNumFormatter->GetNullDate() );
1619                             const sal_uLong nFormat =
1620                                 pNumFormatter->GetStandardFormat( NUMBERFORMAT_DATE, pField->GetLanguage() );
1621                             String sDate;
1622                             Color* pColor;
1623                             pNumFormatter->GetOutputString( aDateDiff.GetDate(), nFormat, sDate, &pColor );
1624 
1625                             // The title should consist of the author and the date:
1626                             String sTitle( pField->GetPar1() );
1627                             sTitle.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
1628                             sTitle += sDate;
1629                             aNote.Title = sTitle;
1630                             // Guess what the contents contains...
1631                             aNote.Contents = pField->GetContent();
1632 
1633                             // Link Export
1634                             pPDFExtOutDevData->CreateNote( rNoteRect.SVRect(), aNote, nNotePageNum );
1635                         }
1636                     }
1637                 }
1638                 pFirst = aIter.Next();
1639                 mrSh.SwCrsrShell::ClearMark();
1640             }
1641         }
1642 
1643         //
1644         // HYPERLINKS
1645         //
1646         SwGetINetAttrs aArr;
1647         const sal_uInt16 nHyperLinkCount = mrSh.GetINetAttrs( aArr );
1648         for( sal_uInt16 n = 0; n < nHyperLinkCount; ++n )
1649         {
1650             SwGetINetAttr* p = aArr[ n ];
1651             ASSERT( 0 != p, "Enhanced pdf export - SwGetINetAttr is missing" )
1652 
1653             const SwTxtNode* pTNd = p->rINetAttr.GetpTxtNode();
1654             ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1655 
1656             // 1. Check if the whole paragraph is hidden
1657             // 2. Move to the hyperlink
1658             // 3. Check for hidden text attribute
1659             if ( !pTNd->IsHidden() &&
1660                   mrSh.GotoINetAttr( p->rINetAttr ) &&
1661                  !mrSh.SelectHiddenRange() )
1662             {
1663                 // Select the hyperlink:
1664                 mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS );
1665                 if ( mrSh.SwCrsrShell::SelectTxtAttr( RES_TXTATR_INETFMT, sal_True ) )
1666                 {
1667                     // First, we create the destination, because there may be more
1668                     // than one link to this destination:
1669                     String aURL( INetURLObject::decode(
1670                         p->rINetAttr.GetINetFmt().GetValue(),
1671                         INET_HEX_ESCAPE,
1672                         INetURLObject::DECODE_UNAMBIGUOUS,
1673                         RTL_TEXTENCODING_UTF8 ) );
1674 
1675                     // We have to distinguish between intern and real URLs
1676                     const bool bIntern = '#' == aURL.GetChar( 0 );
1677 
1678                     // _GetCrsr() is a SwShellCrsr, which is derived from
1679                     // SwSelPaintRects, therefore the rectangles of the current
1680                     // selection can be easily obtained:
1681                     // Note: We make a copy of the rectangles, because they may
1682                     // be deleted again in JumpToSwMark.
1683                     SwRects aTmp;
1684                     aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 );
1685                     ASSERT( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" )
1686 
1687                     // Create the destination for internal links:
1688                     sal_Int32 nDestId = -1;
1689                     if ( bIntern )
1690                     {
1691                         aURL.Erase( 0, 1 );
1692                         mrSh.SwCrsrShell::ClearMark();
1693                         JumpToSwMark( &mrSh, aURL );
1694 
1695                         // Destination Rectangle
1696                         const SwRect& rDestRect = mrSh.GetCharRect();
1697 
1698                         // Destination PageNum
1699                         const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
1700 
1701                         // Destination Export
1702                         if ( -1 != nDestPageNum )
1703                             nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
1704                     }
1705 
1706                     if ( !bIntern || -1 != nDestId )
1707                     {
1708                         // --> FME 2005-05-09 #i44368# Links in Header/Footer
1709                         const SwPosition aPos( *pTNd );
1710                         const bool bHeaderFooter = pDoc->IsInHeaderFooter( aPos.nNode );
1711                         // <--
1712 
1713                         // Create links for all selected rectangles:
1714                         const sal_uInt16 nNumOfRects = aTmp.Count();
1715                         for ( sal_uInt16 i = 0; i < nNumOfRects; ++i )
1716                         {
1717                             // Link Rectangle
1718                             const SwRect& rLinkRect( aTmp[ i ] );
1719 
1720                             // Link PageNum
1721                             const sal_Int32 nLinkPageNum = CalcOutputPageNum( rLinkRect );
1722 
1723                             if ( -1 != nLinkPageNum )
1724                             {
1725                                 // Link Export
1726                                 const sal_Int32 nLinkId =
1727                                     pPDFExtOutDevData->CreateLink( rLinkRect.SVRect(), nLinkPageNum );
1728 
1729                                 // Store link info for tagged pdf output:
1730                                 const IdMapEntry aLinkEntry( rLinkRect, nLinkId );
1731                                 aLinkIdMap.push_back( aLinkEntry );
1732 
1733                                 // Connect Link and Destination:
1734                                 if ( bIntern )
1735                                     pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId );
1736                                 else
1737                                     pPDFExtOutDevData->SetLinkURL( nLinkId, aURL );
1738 
1739                                 // --> FME 2005-05-09 #i44368# Links in Header/Footer
1740                                 if ( bHeaderFooter )
1741                                     MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, rLinkRect, nDestId, aURL, bIntern );
1742                                 // <--
1743                             }
1744                         }
1745                     }
1746                 }
1747             }
1748             mrSh.SwCrsrShell::ClearMark();
1749         }
1750 
1751         //
1752         // HYPERLINKS (Graphics, Frames, OLEs )
1753         //
1754         const SwSpzFrmFmts* pTbl = pDoc->GetSpzFrmFmts();
1755         const sal_uInt16 nSpzFrmFmtsCount = pTbl->Count();
1756         for( sal_uInt16 n = 0; n < nSpzFrmFmtsCount; ++n )
1757         {
1758             const SwFrmFmt* pFrmFmt = (*pTbl)[n];
1759             const SfxPoolItem* pItem;
1760             if ( RES_DRAWFRMFMT != pFrmFmt->Which() &&
1761                  SFX_ITEM_SET == pFrmFmt->GetAttrSet().GetItemState( RES_URL, sal_True, &pItem ) )
1762             {
1763                 String aURL( static_cast<const SwFmtURL*>(pItem)->GetURL() );
1764                 const bool bIntern = '#' == aURL.GetChar( 0 );
1765 
1766                 // Create the destination for internal links:
1767                 sal_Int32 nDestId = -1;
1768                 if ( bIntern )
1769                 {
1770                     aURL.Erase( 0, 1 );
1771                     mrSh.SwCrsrShell::ClearMark();
1772                     JumpToSwMark( &mrSh, aURL );
1773 
1774                     // Destination Rectangle
1775                     const SwRect& rDestRect = mrSh.GetCharRect();
1776 
1777                     // Destination PageNum
1778                     const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
1779 
1780                     // Destination Export
1781                     if ( -1 != nDestPageNum )
1782                         nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
1783                 }
1784 
1785                 if ( !bIntern || -1 != nDestId )
1786                 {
1787                     Point aNullPt;
1788                     const SwRect aLinkRect = pFrmFmt->FindLayoutRect( sal_False, &aNullPt );
1789 
1790                     // Link PageNum
1791                     const sal_Int32 nLinkPageNum = CalcOutputPageNum( aLinkRect );
1792 
1793                     // Link Export
1794                     if ( -1 != nLinkPageNum )
1795                     {
1796                         const sal_Int32 nLinkId =
1797                             pPDFExtOutDevData->CreateLink( aLinkRect.SVRect(), nLinkPageNum );
1798 
1799                         // Connect Link and Destination:
1800                         if ( bIntern )
1801                             pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId );
1802                         else
1803                             pPDFExtOutDevData->SetLinkURL( nLinkId, aURL );
1804 
1805                         // --> FME 2005-05-09 #i44368# Links in Header/Footer
1806                         const SwFmtAnchor &rAnch = pFrmFmt->GetAnchor();
1807                         if (FLY_AT_PAGE != rAnch.GetAnchorId())
1808                         {
1809                             const SwPosition* pPosition = rAnch.GetCntntAnchor();
1810                             if ( pPosition && pDoc->IsInHeaderFooter( pPosition->nNode ) )
1811                             {
1812                                 const SwTxtNode* pTNd = pPosition->nNode.GetNode().GetTxtNode();
1813                                 if ( pTNd )
1814                                     MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, aLinkRect, nDestId, aURL, bIntern );
1815                             }
1816                         }
1817                         // <--
1818                     }
1819                 }
1820             }
1821             mrSh.SwCrsrShell::ClearMark();
1822         }
1823 
1824         //
1825         // REFERENCES
1826         //
1827         SwFieldType* pType = mrSh.GetFldType( RES_GETREFFLD, aEmptyStr );
1828         SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
1829         for( SwFmtFld* pFirst = aIter.First(); pFirst; )
1830         {
1831             if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() )
1832             {
1833                 const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode();
1834                ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" )
1835 
1836                 // 1. Check if the whole paragraph is hidden
1837                 // 2. Move to the field
1838                 // 3. Check for hidden text attribute
1839                 if ( !pTNd->IsHidden() &&
1840                       mrSh.GotoFld( *pFirst ) &&
1841                      !mrSh.SelectHiddenRange() )
1842                 {
1843                     // Select the field:
1844                     mrSh.SwCrsrShell::SetMark();
1845                     mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS );
1846 
1847                     // Link Rectangles
1848                     SwRects aTmp;
1849                     aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 );
1850                     ASSERT( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" )
1851 
1852                     mrSh.SwCrsrShell::ClearMark();
1853 
1854                     // Destination Rectangle
1855                     const SwGetRefField* pField = (SwGetRefField*)pFirst->GetField();
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  */
CalcOutputPageNum(const SwRect & rRect) const2130 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 
MakeHeaderFooterLinks(vcl::PDFExtOutDevData & rPDFExtOutDevData,const SwTxtNode & rTNd,const SwRect & rLinkRect,sal_Int32 nDestId,const String & rURL,bool bIntern) const2163 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