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