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