1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 #include <com/sun/star/embed/XEmbeddedObject.hpp> 27 #include <com/sun/star/i18n/ScriptType.hdl> 28 #include <EnhancedPDFExportHelper.hxx> 29 #include <hintids.hxx> 30 31 #include <vcl/outdev.hxx> 32 #include <tools/multisel.hxx> 33 #include <editeng/adjitem.hxx> 34 #include <editeng/lrspitem.hxx> 35 #include <editeng/langitem.hxx> 36 #include <editeng/scripttypeitem.hxx> 37 #include <tools/urlobj.hxx> 38 #include <svl/zforlist.hxx> 39 #include <swatrset.hxx> 40 #include <frmatr.hxx> 41 #include <paratr.hxx> 42 #include <ndtxt.hxx> 43 #include <ndole.hxx> 44 #include <section.hxx> 45 #include <tox.hxx> 46 #include <fmtfld.hxx> 47 #include <txtinet.hxx> 48 #include <fmtinfmt.hxx> 49 #include <fchrfmt.hxx> 50 #include <charfmt.hxx> 51 #include <fmtanchr.hxx> 52 #include <fmturl.hxx> 53 #include <editsh.hxx> 54 #include <viscrs.hxx> 55 #include <txtfld.hxx> 56 #include <reffld.hxx> 57 #include <doc.hxx> 58 #include <docary.hxx> 59 #include <crsskip.hxx> 60 #include <mdiexp.hxx> 61 #include <docufld.hxx> 62 #include <ftnidx.hxx> 63 #include <txtftn.hxx> 64 #include <fmtftn.hxx> 65 #include <rootfrm.hxx> 66 #include <pagefrm.hxx> 67 #include <txtfrm.hxx> 68 #include <tabfrm.hxx> 69 #include <rowfrm.hxx> 70 #include <cellfrm.hxx> 71 #include <sectfrm.hxx> 72 #include <flyfrm.hxx> 73 #include <notxtfrm.hxx> 74 #include <porfld.hxx> 75 #include <SwStyleNameMapper.hxx> 76 #include <itrpaint.hxx> 77 #include "i18npool/mslangid.hxx" 78 #include <IMark.hxx> 79 #include <SwNodeNum.hxx> 80 #include <switerator.hxx> 81 #include <stack> 82 83 #include <tools/globname.hxx> 84 85 using namespace ::com::sun::star; 86 87 // 88 // Some static data structures 89 // 90 TableColumnsMap SwEnhancedPDFExportHelper::aTableColumnsMap; 91 LinkIdMap SwEnhancedPDFExportHelper::aLinkIdMap; 92 NumListIdMap SwEnhancedPDFExportHelper::aNumListIdMap; 93 NumListBodyIdMap SwEnhancedPDFExportHelper::aNumListBodyIdMap; 94 FrmTagIdMap SwEnhancedPDFExportHelper::aFrmTagIdMap; 95 96 LanguageType SwEnhancedPDFExportHelper::eLanguageDefault = 0; 97 98 #ifdef DBG_UTIL 99 100 static std::vector< sal_uInt16 > aStructStack; 101 102 void lcl_DBGCheckStack() 103 { 104 /* NonStructElement = 0 Document = 1 Part = 2 105 * Article = 3 Section = 4 Division = 5 106 * BlockQuote = 6 Caption = 7 TOC = 8 107 * TOCI = 9 Index = 10 Paragraph = 11 108 * Heading = 12 H1-6 = 13 - 18 List = 19 109 * ListItem = 20 LILabel = 21 LIBody = 22 110 * Table = 23 TableRow = 24 TableHeader = 25 111 * TableData = 26 Span = 27 Quote = 28 112 * Note = 29 Reference = 30 BibEntry = 31 113 * Code = 32 Link = 33 Figure = 34 114 * Formula = 35 Form = 36 Continued frame = 99 115 */ 116 117 sal_uInt16 nElement; 118 std::vector< sal_uInt16 >::iterator aIter; 119 for ( aIter = aStructStack.begin(); aIter != aStructStack.end(); ++aIter ) 120 { 121 nElement = *aIter; 122 } 123 } 124 125 #endif 126 127 namespace 128 { 129 // ODF Style Names: 130 const String aTableHeadingName = String::CreateFromAscii("Table Heading"); 131 const String aQuotations = String::CreateFromAscii("Quotations"); 132 const String aCaption = String::CreateFromAscii("Caption"); 133 const String aHeading = String::CreateFromAscii("Heading"); 134 const String aQuotation = String::CreateFromAscii("Quotation"); 135 const String aSourceText = String::CreateFromAscii("Source Text"); 136 137 // PDF Tag Names: 138 const String aDocumentString = String::CreateFromAscii("Document"); 139 const String aDivString = String::CreateFromAscii("Div"); 140 const String aSectString = String::CreateFromAscii("Sect"); 141 const String aHString = String::CreateFromAscii("H"); 142 const String aH1String = String::CreateFromAscii("H1"); 143 const String aH2String = String::CreateFromAscii("H2"); 144 const String aH3String = String::CreateFromAscii("H3"); 145 const String aH4String = String::CreateFromAscii("H4"); 146 const String aH5String = String::CreateFromAscii("H5"); 147 const String aH6String = String::CreateFromAscii("H6"); 148 const String aListString = String::CreateFromAscii("L"); 149 const String aListItemString = String::CreateFromAscii("LI"); 150 const String aListBodyString = String::CreateFromAscii("LBody"); 151 const String aBlockQuoteString = String::CreateFromAscii("BlockQuote"); 152 const String aCaptionString = String::CreateFromAscii("Caption"); 153 const String aIndexString = String::CreateFromAscii("Index"); 154 const String aTOCString = String::CreateFromAscii("TOC"); 155 const String aTOCIString = String::CreateFromAscii("TOCI"); 156 const String aTableString = String::CreateFromAscii("Table"); 157 const String aTRString = String::CreateFromAscii("TR"); 158 const String aTDString = String::CreateFromAscii("TD"); 159 const String aTHString = String::CreateFromAscii("TH"); 160 const String aBibEntryString = String::CreateFromAscii("BibEntry"); 161 const String aQuoteString = String::CreateFromAscii("Quote"); 162 const String aSpanString = String::CreateFromAscii("Span"); 163 const String aCodeString = String::CreateFromAscii("Code"); 164 const String aFigureString = String::CreateFromAscii("Figure"); 165 const String aFormulaString = String::CreateFromAscii("Formula"); 166 const String aLinkString = String::CreateFromAscii("Link"); 167 const String aNoteString = String::CreateFromAscii("Note"); 168 const String aEmptyString = String::CreateFromAscii(""); 169 170 // returns true if first paragraph in cell frame has 'table heading' style 171 bool lcl_IsHeadlineCell( const SwCellFrm& rCellFrm ) 172 { 173 bool bRet = false; 174 175 const SwCntntFrm *pCnt = rCellFrm.ContainsCntnt(); 176 if ( pCnt && pCnt->IsTxtFrm() ) 177 { 178 const SwTxtNode* pTxtNode = static_cast<const SwTxtFrm*>(pCnt)->GetTxtNode(); 179 const SwFmt* pTxtFmt = pTxtNode->GetFmtColl(); 180 181 String sStyleName; 182 SwStyleNameMapper::FillProgName( pTxtFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); 183 bRet = sStyleName == aTableHeadingName; 184 } 185 186 return bRet; 187 } 188 189 // List all frames for which the NonStructElement tag is set: 190 bool lcl_IsInNonStructEnv( const SwFrm& rFrm ) 191 { 192 bool bRet = false; 193 194 if ( 0 != rFrm.FindFooterOrHeader() && 195 !rFrm.IsHeaderFrm() && !rFrm.IsFooterFrm() ) 196 { 197 bRet = true; 198 } 199 else if ( rFrm.IsInTab() && !rFrm.IsTabFrm() ) 200 { 201 const SwTabFrm* pTabFrm = rFrm.FindTabFrm(); 202 if ( rFrm.GetUpper() != pTabFrm && 203 pTabFrm->IsFollow() && pTabFrm->IsInHeadline( rFrm ) ) 204 bRet = true; 205 } 206 207 return bRet; 208 } 209 210 // Generate key from frame for reopening tags: 211 void* lcl_GetKeyFromFrame( const SwFrm& rFrm ) 212 { 213 void* pKey = 0; 214 215 if ( rFrm.IsPageFrm() ) 216 pKey = (void*)static_cast<const SwPageFrm&>(rFrm).GetFmt()->getIDocumentSettingAccess(); 217 else if ( rFrm.IsTxtFrm() ) 218 pKey = (void*)static_cast<const SwTxtFrm&>(rFrm).GetTxtNode(); 219 else if ( rFrm.IsSctFrm() ) 220 pKey = (void*)static_cast<const SwSectionFrm&>(rFrm).GetSection(); 221 else if ( rFrm.IsTabFrm() ) 222 pKey = (void*)static_cast<const SwTabFrm&>(rFrm).GetTable(); 223 else if ( rFrm.IsRowFrm() ) 224 pKey = (void*)static_cast<const SwRowFrm&>(rFrm).GetTabLine(); 225 else if ( rFrm.IsCellFrm() ) 226 { 227 const SwTabFrm* pTabFrm = rFrm.FindTabFrm(); 228 const SwTable* pTable = pTabFrm->GetTable(); 229 pKey = (void*) & static_cast<const SwCellFrm&>(rFrm).GetTabBox()->FindStartOfRowSpan( *pTable ); 230 } 231 232 return pKey; 233 } 234 235 bool lcl_HasPreviousParaSameNumRule( const SwTxtNode& rNode ) 236 { 237 bool bRet = false; 238 SwNodeIndex aIdx( rNode ); 239 const SwDoc* pDoc = rNode.GetDoc(); 240 const SwNodes& rNodes = pDoc->GetNodes(); 241 const SwNode* pNode = &rNode; 242 const SwNumRule* pNumRule = rNode.GetNumRule(); 243 244 while (! (pNode == rNodes.DocumentSectionStartNode((SwNode*)&rNode) ) ) 245 { 246 --aIdx; 247 248 if (aIdx.GetNode().IsTxtNode()) 249 { 250 const SwTxtNode* pPrevTxtNd = aIdx.GetNode().GetTxtNode(); 251 const SwNumRule * pPrevNumRule = pPrevTxtNd->GetNumRule(); 252 253 // We find the previous text node. Now check, if the previous text node 254 // has the same numrule like rNode: 255 if ( (pPrevNumRule == pNumRule) && 256 (!pPrevTxtNd->IsOutline() == !rNode.IsOutline())) 257 bRet = true; 258 259 break; 260 } 261 262 pNode = &aIdx.GetNode(); 263 } 264 return bRet; 265 } 266 267 } // end namespace 268 269 /* 270 * SwTaggedPDFHelper::SwTaggedPDFHelper() 271 */ 272 SwTaggedPDFHelper::SwTaggedPDFHelper( const Num_Info* pNumInfo, 273 const Frm_Info* pFrmInfo, 274 const Por_Info* pPorInfo, 275 OutputDevice& rOut ) 276 : nEndStructureElement( 0 ), 277 nRestoreCurrentTag( -1 ), 278 mpNumInfo( pNumInfo ), 279 mpFrmInfo( pFrmInfo ), 280 mpPorInfo( pPorInfo ) 281 { 282 mpPDFExtOutDevData = 283 PTR_CAST( vcl::PDFExtOutDevData, rOut.GetExtOutDevData() ); 284 285 if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() ) 286 { 287 #ifdef DBG_UTIL 288 sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); 289 lcl_DBGCheckStack(); 290 #endif 291 if ( mpNumInfo ) 292 BeginNumberedListStructureElements(); 293 else if ( mpFrmInfo ) 294 BeginBlockStructureElements(); 295 else if ( mpPorInfo ) 296 BeginInlineStructureElements(); 297 else 298 BeginTag( vcl::PDFWriter::NonStructElement, aEmptyString ); 299 300 #ifdef DBG_UTIL 301 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); 302 lcl_DBGCheckStack(); 303 #endif 304 } 305 } 306 307 308 /* 309 * SwTaggedPDFHelper::~SwTaggedPDFHelper() 310 */ 311 SwTaggedPDFHelper::~SwTaggedPDFHelper() 312 { 313 if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() ) 314 { 315 #ifdef DBG_UTIL 316 sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); 317 lcl_DBGCheckStack(); 318 #endif 319 EndStructureElements(); 320 321 #ifdef DBG_UTIL 322 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); 323 lcl_DBGCheckStack(); 324 #endif 325 326 } 327 } 328 329 /* 330 * SwTaggedPDFHelper::CheckReopenTag() 331 */ 332 bool SwTaggedPDFHelper::CheckReopenTag() 333 { 334 bool bRet = false; 335 sal_Int32 nReopenTag = -1; 336 bool bContinue = false; // in some cases we just have to reopen a tag without early returning 337 338 if ( mpFrmInfo ) 339 { 340 const SwFrm& rFrm = mpFrmInfo->mrFrm; 341 const SwFrm* pKeyFrm = 0; 342 void* pKey = 0; 343 344 // Reopen an existing structure element if 345 // - rFrm is not the first page frame (reopen Document tag) 346 // - rFrm is a follow frame (reopen Master tag) 347 // - rFrm is a fly frame anchored at content (reopen Anchor paragraph tag) 348 // - rFrm is a fly frame anchord at page (reopen Document tag) 349 // - rFrm is a follow flow row (reopen TableRow tag) 350 // - rFrm is a cell frame in a follow flow row (reopen TableData tag) 351 if ( ( rFrm.IsPageFrm() && static_cast<const SwPageFrm&>(rFrm).GetPrev() ) || 352 ( rFrm.IsFlowFrm() && SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() ) || 353 ( rFrm.IsRowFrm() && rFrm.IsInFollowFlowRow() ) || 354 ( rFrm.IsCellFrm() && const_cast<SwFrm&>(rFrm).GetPrevCellLeaf( MAKEPAGE_NONE ) ) ) 355 { 356 pKeyFrm = &rFrm; 357 } 358 else if ( rFrm.IsFlyFrm() ) 359 { 360 const SwFmtAnchor& rAnchor = 361 static_cast<const SwFlyFrm*>(&rFrm)->GetFmt()->GetAnchor(); 362 if ((FLY_AT_PARA == rAnchor.GetAnchorId()) || 363 (FLY_AT_CHAR == rAnchor.GetAnchorId()) || 364 (FLY_AT_PAGE == rAnchor.GetAnchorId())) 365 { 366 pKeyFrm = static_cast<const SwFlyFrm&>(rFrm).GetAnchorFrm(); 367 bContinue = true; 368 } 369 } 370 371 if ( pKeyFrm ) 372 { 373 pKey = lcl_GetKeyFromFrame( *pKeyFrm ); 374 375 if ( pKey ) 376 { 377 FrmTagIdMap& rFrmTagIdMap = SwEnhancedPDFExportHelper::GetFrmTagIdMap(); 378 const FrmTagIdMap::const_iterator aIter = rFrmTagIdMap.find( pKey ); 379 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 */ 405 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 1542 SwEnhancedPDFExportHelper::~SwEnhancedPDFExportHelper() 1543 { 1544 delete pPageRange; 1545 } 1546 1547 /* 1548 * SwEnhancedPDFExportHelper::EnhancedPDFExport() 1549 */ 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 */ 2130 sal_Int32 SwEnhancedPDFExportHelper::CalcOutputPageNum( const SwRect& rRect ) const 2131 { 2132 // Document page numbers are 0, 1, 2, ... 2133 const sal_Int32 nPageNumOfRect = mrSh.GetPageNumAndSetOffsetForPDF( mrOut, rRect ); 2134 2135 // Shortcut: 2136 if ( -1 == nPageNumOfRect || ( !pPageRange && !mbSkipEmptyPages ) ) 2137 return nPageNumOfRect; 2138 2139 // pPageRange page numbers are 1, 2, 3, ... 2140 if ( pPageRange && !pPageRange->IsSelected( nPageNumOfRect + 1 ) ) 2141 return -1; 2142 2143 // What will be the page number of page nPageNumOfRect in the output doc? 2144 sal_Int32 nOutputPageNum = -1; 2145 const SwRootFrm* pRootFrm = mrSh.GetLayout(); 2146 const SwPageFrm* pCurrPage = static_cast<const SwPageFrm*>(pRootFrm->Lower()); 2147 2148 for ( sal_Int32 nPageIndex = 0; 2149 nPageIndex <= nPageNumOfRect && pCurrPage; 2150 ++nPageIndex ) 2151 { 2152 if ( ( !pPageRange || pPageRange->IsSelected( nPageIndex + 1 ) ) && 2153 ( !mbSkipEmptyPages || !pCurrPage->IsEmptyPage() ) ) 2154 ++nOutputPageNum; 2155 2156 pCurrPage = static_cast<const SwPageFrm*>(pCurrPage->GetNext()); 2157 } 2158 2159 // pdf export page numbers are 0, 1, 2, ... 2160 return nOutputPageNum; 2161 } 2162 2163 void SwEnhancedPDFExportHelper::MakeHeaderFooterLinks( vcl::PDFExtOutDevData& rPDFExtOutDevData, 2164 const SwTxtNode& rTNd, 2165 const SwRect& rLinkRect, 2166 sal_Int32 nDestId, 2167 const String& rURL, 2168 bool bIntern ) const 2169 { 2170 // We assume, that the primary link has just been exported. Therefore 2171 // the offset of the link rectangle calculates as follows: 2172 const Point aOffset = rLinkRect.Pos() + mrOut.GetMapMode().GetOrigin(); 2173 2174 SwIterator<SwTxtFrm,SwTxtNode> aIter( rTNd ); 2175 for ( SwTxtFrm* pTmpFrm = aIter.First(); pTmpFrm; pTmpFrm = aIter.Next() ) 2176 { 2177 // Add offset to current page: 2178 const SwPageFrm* pPageFrm = pTmpFrm->FindPageFrm(); 2179 SwRect aHFLinkRect( rLinkRect ); 2180 aHFLinkRect.Pos() = pPageFrm->Frm().Pos() + aOffset; 2181 2182 // #i97135# the gcc_x64 optimizer gets aHFLinkRect != rLinkRect wrong 2183 // fool it by comparing the position only (the width and height are the 2184 // same anyway) 2185 if ( aHFLinkRect.Pos() != rLinkRect.Pos() ) 2186 { 2187 // Link PageNum 2188 const sal_Int32 nHFLinkPageNum = CalcOutputPageNum( aHFLinkRect ); 2189 2190 if ( -1 != nHFLinkPageNum ) 2191 { 2192 // Link Export 2193 const sal_Int32 nHFLinkId = 2194 rPDFExtOutDevData.CreateLink( aHFLinkRect.SVRect(), nHFLinkPageNum ); 2195 2196 // Connect Link and Destination: 2197 if ( bIntern ) 2198 rPDFExtOutDevData.SetLinkDest( nHFLinkId, nDestId ); 2199 else 2200 rPDFExtOutDevData.SetLinkURL( nHFLinkId, rURL ); 2201 } 2202 } 2203 } 2204 } 2205 2206