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