/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "i18npool/mslangid.hxx" #include #include #include #include #include using namespace ::com::sun::star; // // Some static data structures // TableColumnsMap SwEnhancedPDFExportHelper::aTableColumnsMap; LinkIdMap SwEnhancedPDFExportHelper::aLinkIdMap; NumListIdMap SwEnhancedPDFExportHelper::aNumListIdMap; NumListBodyIdMap SwEnhancedPDFExportHelper::aNumListBodyIdMap; FrmTagIdMap SwEnhancedPDFExportHelper::aFrmTagIdMap; LanguageType SwEnhancedPDFExportHelper::eLanguageDefault = 0; #if OSL_DEBUG_LEVEL > 1 static std::vector< sal_uInt16 > aStructStack; void lcl_DBGCheckStack() { /* NonStructElement = 0 Document = 1 Part = 2 * Article = 3 Section = 4 Division = 5 * BlockQuote = 6 Caption = 7 TOC = 8 * TOCI = 9 Index = 10 Paragraph = 11 * Heading = 12 H1-6 = 13 - 18 List = 19 * ListItem = 20 LILabel = 21 LIBody = 22 * Table = 23 TableRow = 24 TableHeader = 25 * TableData = 26 Span = 27 Quote = 28 * Note = 29 Reference = 30 BibEntry = 31 * Code = 32 Link = 33 Figure = 34 * Formula = 35 Form = 36 Continued frame = 99 */ sal_uInt16 nElement; std::vector< sal_uInt16 >::iterator aIter; for ( aIter = aStructStack.begin(); aIter != aStructStack.end(); ++aIter ) { nElement = *aIter; } } #endif namespace { // ODF Style Names: const String aTableHeadingName = String::CreateFromAscii("Table Heading"); const String aQuotations = String::CreateFromAscii("Quotations"); const String aCaption = String::CreateFromAscii("Caption"); const String aHeading = String::CreateFromAscii("Heading"); const String aQuotation = String::CreateFromAscii("Quotation"); const String aSourceText = String::CreateFromAscii("Source Text"); // PDF Tag Names: const String aDocumentString = String::CreateFromAscii("Document"); const String aDivString = String::CreateFromAscii("Div"); const String aSectString = String::CreateFromAscii("Sect"); const String aHString = String::CreateFromAscii("H"); const String aH1String = String::CreateFromAscii("H1"); const String aH2String = String::CreateFromAscii("H2"); const String aH3String = String::CreateFromAscii("H3"); const String aH4String = String::CreateFromAscii("H4"); const String aH5String = String::CreateFromAscii("H5"); const String aH6String = String::CreateFromAscii("H6"); const String aListString = String::CreateFromAscii("L"); const String aListItemString = String::CreateFromAscii("LI"); const String aListBodyString = String::CreateFromAscii("LBody"); const String aBlockQuoteString = String::CreateFromAscii("BlockQuote"); const String aCaptionString = String::CreateFromAscii("Caption"); const String aIndexString = String::CreateFromAscii("Index"); const String aTOCString = String::CreateFromAscii("TOC"); const String aTOCIString = String::CreateFromAscii("TOCI"); const String aTableString = String::CreateFromAscii("Table"); const String aTRString = String::CreateFromAscii("TR"); const String aTDString = String::CreateFromAscii("TD"); const String aTHString = String::CreateFromAscii("TH"); const String aBibEntryString = String::CreateFromAscii("BibEntry"); const String aQuoteString = String::CreateFromAscii("Quote"); const String aSpanString = String::CreateFromAscii("Span"); const String aCodeString = String::CreateFromAscii("Code"); const String aFigureString = String::CreateFromAscii("Figure"); const String aFormulaString = String::CreateFromAscii("Formula"); const String aLinkString = String::CreateFromAscii("Link"); const String aNoteString = String::CreateFromAscii("Note"); const String aEmptyString = String::CreateFromAscii(""); // returns true if first paragraph in cell frame has 'table heading' style bool lcl_IsHeadlineCell( const SwCellFrm& rCellFrm ) { bool bRet = false; const SwCntntFrm *pCnt = rCellFrm.ContainsCntnt(); if ( pCnt && pCnt->IsTxtFrm() ) { const SwTxtNode* pTxtNode = static_cast(pCnt)->GetTxtNode(); const SwFmt* pTxtFmt = pTxtNode->GetFmtColl(); String sStyleName; SwStyleNameMapper::FillProgName( pTxtFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); bRet = sStyleName == aTableHeadingName; } return bRet; } // List all frames for which the NonStructElement tag is set: bool lcl_IsInNonStructEnv( const SwFrm& rFrm ) { bool bRet = false; if ( 0 != rFrm.FindFooterOrHeader() && !rFrm.IsHeaderFrm() && !rFrm.IsFooterFrm() ) { bRet = true; } else if ( rFrm.IsInTab() && !rFrm.IsTabFrm() ) { const SwTabFrm* pTabFrm = rFrm.FindTabFrm(); if ( rFrm.GetUpper() != pTabFrm && pTabFrm->IsFollow() && pTabFrm->IsInHeadline( rFrm ) ) bRet = true; } return bRet; } // Generate key from frame for reopening tags: void* lcl_GetKeyFromFrame( const SwFrm& rFrm ) { void* pKey = 0; if ( rFrm.IsPageFrm() ) pKey = (void*)static_cast(rFrm).GetFmt()->getIDocumentSettingAccess(); else if ( rFrm.IsTxtFrm() ) pKey = (void*)static_cast(rFrm).GetTxtNode(); else if ( rFrm.IsSctFrm() ) pKey = (void*)static_cast(rFrm).GetSection(); else if ( rFrm.IsTabFrm() ) pKey = (void*)static_cast(rFrm).GetTable(); else if ( rFrm.IsRowFrm() ) pKey = (void*)static_cast(rFrm).GetTabLine(); else if ( rFrm.IsCellFrm() ) { const SwTabFrm* pTabFrm = rFrm.FindTabFrm(); const SwTable* pTable = pTabFrm->GetTable(); pKey = (void*) & static_cast(rFrm).GetTabBox()->FindStartOfRowSpan( *pTable ); } return pKey; } bool lcl_HasPreviousParaSameNumRule( const SwTxtNode& rNode ) { bool bRet = false; SwNodeIndex aIdx( rNode ); const SwDoc* pDoc = rNode.GetDoc(); const SwNodes& rNodes = pDoc->GetNodes(); const SwNode* pNode = &rNode; const SwNumRule* pNumRule = rNode.GetNumRule(); while (! (pNode == rNodes.DocumentSectionStartNode((SwNode*)&rNode) ) ) { --aIdx; if (aIdx.GetNode().IsTxtNode()) { const SwTxtNode* pPrevTxtNd = aIdx.GetNode().GetTxtNode(); const SwNumRule * pPrevNumRule = pPrevTxtNd->GetNumRule(); // We find the previous text node. Now check, if the previous text node // has the same numrule like rNode: if ( (pPrevNumRule == pNumRule) && (!pPrevTxtNd->IsOutline() == !rNode.IsOutline())) bRet = true; break; } pNode = &aIdx.GetNode(); } return bRet; } } // end namespace /* * SwTaggedPDFHelper::SwTaggedPDFHelper() */ SwTaggedPDFHelper::SwTaggedPDFHelper( const Num_Info* pNumInfo, const Frm_Info* pFrmInfo, const Por_Info* pPorInfo, OutputDevice& rOut ) : nEndStructureElement( 0 ), nRestoreCurrentTag( -1 ), mpNumInfo( pNumInfo ), mpFrmInfo( pFrmInfo ), mpPorInfo( pPorInfo ) { mpPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, rOut.GetExtOutDevData() ); if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() ) { #if OSL_DEBUG_LEVEL > 1 sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); lcl_DBGCheckStack(); #endif if ( mpNumInfo ) BeginNumberedListStructureElements(); else if ( mpFrmInfo ) BeginBlockStructureElements(); else if ( mpPorInfo ) BeginInlineStructureElements(); else BeginTag( vcl::PDFWriter::NonStructElement, aEmptyString ); #if OSL_DEBUG_LEVEL > 1 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); lcl_DBGCheckStack(); #endif } } /* * SwTaggedPDFHelper::~SwTaggedPDFHelper() */ SwTaggedPDFHelper::~SwTaggedPDFHelper() { if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() ) { #if OSL_DEBUG_LEVEL > 1 sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); lcl_DBGCheckStack(); #endif EndStructureElements(); #if OSL_DEBUG_LEVEL > 1 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); lcl_DBGCheckStack(); #endif } } /* * SwTaggedPDFHelper::CheckReopenTag() */ bool SwTaggedPDFHelper::CheckReopenTag() { bool bRet = false; sal_Int32 nReopenTag = -1; bool bContinue = false; // in some cases we just have to reopen a tag without early returning if ( mpFrmInfo ) { const SwFrm& rFrm = mpFrmInfo->mrFrm; const SwFrm* pKeyFrm = 0; void* pKey = 0; // Reopen an existing structure element if // - rFrm is not the first page frame (reopen Document tag) // - rFrm is a follow frame (reopen Master tag) // - rFrm is a fly frame anchored at content (reopen Anchor paragraph tag) // - rFrm is a fly frame anchord at page (reopen Document tag) // - rFrm is a follow flow row (reopen TableRow tag) // - rFrm is a cell frame in a follow flow row (reopen TableData tag) if ( ( rFrm.IsPageFrm() && static_cast(rFrm).GetPrev() ) || ( rFrm.IsFlowFrm() && SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() ) || ( rFrm.IsRowFrm() && rFrm.IsInFollowFlowRow() ) || ( rFrm.IsCellFrm() && const_cast(rFrm).GetPrevCellLeaf( MAKEPAGE_NONE ) ) ) { pKeyFrm = &rFrm; } else if ( rFrm.IsFlyFrm() ) { const SwFmtAnchor& rAnchor = static_cast(&rFrm)->GetFmt()->GetAnchor(); if ((FLY_AT_PARA == rAnchor.GetAnchorId()) || (FLY_AT_CHAR == rAnchor.GetAnchorId()) || (FLY_AT_PAGE == rAnchor.GetAnchorId())) { pKeyFrm = static_cast(rFrm).GetAnchorFrm(); bContinue = true; } } if ( pKeyFrm ) { pKey = lcl_GetKeyFromFrame( *pKeyFrm ); if ( pKey ) { FrmTagIdMap& rFrmTagIdMap = SwEnhancedPDFExportHelper::GetFrmTagIdMap(); const FrmTagIdMap::const_iterator aIter = rFrmTagIdMap.find( pKey ); if ( aIter != rFrmTagIdMap.end() ) nReopenTag = (*aIter).second; } } } if ( -1 != nReopenTag ) { nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement(); const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag ); OSL_ENSURE( bSuccess, "Failed to reopen tag" ); #if OSL_DEBUG_LEVEL > 1 aStructStack.push_back( 99 ); #endif bRet = bSuccess; } return bRet && !bContinue; } /* * SwTaggedPDFHelper::CheckRestoreTag() */ bool SwTaggedPDFHelper::CheckRestoreTag() const { bool bRet = false; if ( nRestoreCurrentTag != -1 ) { const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nRestoreCurrentTag ); (void)bSuccess; OSL_ENSURE( bSuccess, "Failed to restore reopened tag" ); #if OSL_DEBUG_LEVEL > 1 aStructStack.pop_back(); #endif bRet = true; } return bRet; } /* * SwTaggedPDFHelper::BeginTag() */ void SwTaggedPDFHelper::BeginTag( vcl::PDFWriter::StructElement eType, const String& rString ) { // write new tag const sal_Int32 nId = mpPDFExtOutDevData->BeginStructureElement( eType, rtl::OUString( rString ) ); ++nEndStructureElement; #if OSL_DEBUG_LEVEL > 1 aStructStack.push_back( static_cast(eType) ); #endif // Store the id of the current structure element if // - it is a list structure element // - it is a list body element with children // - rFrm is the first page frame // - rFrm is a master frame // - rFrm has objects anchored to it // - rFrm is a row frame or cell frame in a split table row if ( mpNumInfo ) { const SwTxtFrm& rTxtFrm = static_cast(mpNumInfo->mrFrm); const SwTxtNode* pTxtNd = rTxtFrm.GetTxtNode(); const SwNodeNum* pNodeNum = pTxtNd->GetNum(); if ( vcl::PDFWriter::List == eType ) { NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap(); rNumListIdMap[ pNodeNum ] = nId; } else if ( vcl::PDFWriter::LIBody == eType ) { NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap(); rNumListBodyIdMap[ pNodeNum ] = nId; } } else if ( mpFrmInfo ) { const SwFrm& rFrm = mpFrmInfo->mrFrm; if ( ( rFrm.IsPageFrm() && !static_cast(rFrm).GetPrev() ) || ( rFrm.IsFlowFrm() && !SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() && SwFlowFrm::CastFlowFrm(&rFrm)->HasFollow() ) || ( rFrm.IsTxtFrm() && rFrm.GetDrawObjs() ) || ( rFrm.IsRowFrm() && rFrm.IsInSplitTableRow() ) || ( rFrm.IsCellFrm() && const_cast(rFrm).GetNextCellLeaf( MAKEPAGE_NONE ) ) ) { const void* pKey = lcl_GetKeyFromFrame( rFrm ); if ( pKey ) { FrmTagIdMap& rFrmTagIdMap = SwEnhancedPDFExportHelper::GetFrmTagIdMap(); rFrmTagIdMap[ pKey ] = nId; } } } SetAttributes( eType ); } /* * SwTaggedPDFHelper::EndTag() */ void SwTaggedPDFHelper::EndTag() { mpPDFExtOutDevData->EndStructureElement(); #if OSL_DEBUG_LEVEL > 1 aStructStack.pop_back(); #endif } /* * SwTaggedPDFHelper::SetAttributes() * * Sets the attributes according to the structure type. */ void SwTaggedPDFHelper::SetAttributes( vcl::PDFWriter::StructElement eType ) { vcl::PDFWriter::StructAttributeValue eVal; sal_Int32 nVal; /* * ATTRIBUTES FOR BLSE */ if ( mpFrmInfo ) { const SwFrm* pFrm = &mpFrmInfo->mrFrm; SWRECTFN( pFrm ) bool bPlacement = false; bool bWritingMode = false; bool bSpaceBefore = false; bool bSpaceAfter = false; bool bStartIndent = false; bool bEndIndent = false; bool bTextIndent = false; bool bTextAlign = false; bool bAlternateText = false; bool bWidth = false; bool bHeight = false; bool bBox = false; bool bRowSpan = false; // // Check which attributes to set: // switch ( eType ) { case vcl::PDFWriter::Document : bWritingMode = true; break; case vcl::PDFWriter::Table : bPlacement = bWritingMode = bSpaceBefore = bSpaceAfter = bStartIndent = bEndIndent = bWidth = bHeight = bBox = true; break; case vcl::PDFWriter::TableRow : bPlacement = bWritingMode = true; break; case vcl::PDFWriter::TableHeader : case vcl::PDFWriter::TableData : bPlacement = bWritingMode = bWidth = bHeight = bRowSpan = true; break; case vcl::PDFWriter::H1 : case vcl::PDFWriter::H2 : case vcl::PDFWriter::H3 : case vcl::PDFWriter::H4 : case vcl::PDFWriter::H5 : case vcl::PDFWriter::H6 : case vcl::PDFWriter::Paragraph : case vcl::PDFWriter::Heading : case vcl::PDFWriter::Caption : case vcl::PDFWriter::BlockQuote : bPlacement = bWritingMode = bSpaceBefore = bSpaceAfter = bStartIndent = bEndIndent = bTextIndent = bTextAlign = true; break; case vcl::PDFWriter::Formula : case vcl::PDFWriter::Figure : bPlacement = bAlternateText = bWidth = bHeight = bBox = true; break; default : break; } // // Set the attributes: // if ( bPlacement ) { eVal = vcl::PDFWriter::TableHeader == eType || vcl::PDFWriter::TableData == eType ? vcl::PDFWriter::Inline : vcl::PDFWriter::Block; mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::Placement, eVal ); } if ( bWritingMode ) { eVal = pFrm->IsVertical() ? vcl::PDFWriter::TbRl : pFrm->IsRightToLeft() ? vcl::PDFWriter::RlTb : vcl::PDFWriter::LrTb; if ( vcl::PDFWriter::LrTb != eVal ) mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::WritingMode, eVal ); } if ( bSpaceBefore ) { nVal = (pFrm->*fnRect->fnGetTopMargin)(); if ( 0 != nVal ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::SpaceBefore, nVal ); } if ( bSpaceAfter ) { nVal = (pFrm->*fnRect->fnGetBottomMargin)(); if ( 0 != nVal ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::SpaceAfter, nVal ); } if ( bStartIndent ) { nVal = (pFrm->*fnRect->fnGetLeftMargin)(); if ( 0 != nVal ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::StartIndent, nVal ); } if ( bEndIndent ) { nVal = (pFrm->*fnRect->fnGetRightMargin)(); if ( 0 != nVal ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::EndIndent, nVal ); } if ( bTextIndent ) { OSL_ENSURE( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" ); const SvxLRSpaceItem &rSpace = static_cast(pFrm)->GetTxtNode()->GetSwAttrSet().GetLRSpace(); nVal = rSpace.GetTxtFirstLineOfst(); if ( 0 != nVal ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::TextIndent, nVal ); } if ( bTextAlign ) { OSL_ENSURE( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" ); const SwAttrSet& aSet = static_cast(pFrm)->GetTxtNode()->GetSwAttrSet(); const SvxAdjust nAdjust = aSet.GetAdjust().GetAdjust(); if ( SVX_ADJUST_BLOCK == nAdjust || SVX_ADJUST_CENTER == nAdjust || ( (pFrm->IsRightToLeft() && SVX_ADJUST_LEFT == nAdjust) || (!pFrm->IsRightToLeft() && SVX_ADJUST_RIGHT == nAdjust) ) ) { eVal = SVX_ADJUST_BLOCK == nAdjust ? vcl::PDFWriter::Justify : SVX_ADJUST_CENTER == nAdjust ? vcl::PDFWriter::Center : vcl::PDFWriter::End; mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextAlign, eVal ); } } if ( bAlternateText ) { OSL_ENSURE( pFrm->IsFlyFrm(), "Frame type <-> tag attribute mismatch" ); const SwFlyFrm* pFly = static_cast(pFrm); if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() ) { const SwNoTxtFrm* pNoTxtFrm = static_cast(pFly->Lower()); const SwNoTxtNode* pNoTxtNode = static_cast(pNoTxtFrm->GetNode()); const String aAlternateTxt( pNoTxtNode->GetTitle() ); mpPDFExtOutDevData->SetAlternateText( aAlternateTxt ); } } if ( bWidth ) { nVal = (pFrm->Frm().*fnRect->fnGetWidth)(); mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Width, nVal ); } if ( bHeight ) { nVal = (pFrm->Frm().*fnRect->fnGetHeight)(); mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Height, nVal ); } if ( bBox ) { // BBox only for non-split tables: if ( vcl::PDFWriter::Table != eType || ( pFrm->IsTabFrm() && !static_cast(pFrm)->IsFollow() && !static_cast(pFrm)->HasFollow() ) ) mpPDFExtOutDevData->SetStructureBoundingBox( pFrm->Frm().SVRect() ); } if ( bRowSpan ) { const SwCellFrm* pThisCell = dynamic_cast(pFrm); if ( pThisCell ) { nVal = pThisCell->GetTabBox()->getRowSpan(); if ( nVal > 1 ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::RowSpan, nVal ); // calculate colspan: const SwTabFrm* pTabFrm = pThisCell->FindTabFrm(); const SwTable* pTable = pTabFrm->GetTable(); SWRECTFNX( pTabFrm ) const TableColumnsMapEntry& rCols = SwEnhancedPDFExportHelper::GetTableColumnsMap()[ pTable ]; const long nLeft = (pThisCell->Frm().*fnRectX->fnGetLeft)(); const long nRight = (pThisCell->Frm().*fnRectX->fnGetRight)(); const TableColumnsMapEntry::const_iterator aLeftIter = rCols.find( nLeft ); const TableColumnsMapEntry::const_iterator aRightIter = rCols.find( nRight ); OSL_ENSURE( aLeftIter != rCols.end() && aRightIter != rCols.end(), "Colspan trouble" ); if ( aLeftIter != rCols.end() && aRightIter != rCols.end() ) { nVal = std::distance( aLeftIter, aRightIter ); if ( nVal > 1 ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::ColSpan, nVal ); } } } } /* * ATTRIBUTES FOR ILSE */ else if ( mpPorInfo ) { const SwLinePortion* pPor = &mpPorInfo->mrPor; const SwTxtPaintInfo& rInf = mpPorInfo->mrTxtPainter.GetInfo(); bool bActualText = false; bool bBaselineShift = false; bool bTextDecorationType = false; bool bLinkAttribute = false; bool bLanguage = false; // // Check which attributes to set: // switch ( eType ) { case vcl::PDFWriter::Span : case vcl::PDFWriter::Quote : case vcl::PDFWriter::Code : if( POR_HYPHSTR == pPor->GetWhichPor() || POR_SOFTHYPHSTR == pPor->GetWhichPor() ) bActualText = true; else { bBaselineShift = bTextDecorationType = bLanguage = true; } break; case vcl::PDFWriter::Link : bTextDecorationType = bBaselineShift = bLinkAttribute = bLanguage = true; break; default: break; } if ( bActualText ) { const String aActualTxt( rInf.GetTxt(), rInf.GetIdx(), pPor->GetLen() ); mpPDFExtOutDevData->SetActualText( aActualTxt ); } if ( bBaselineShift ) { // TODO: Calculate correct values! nVal = rInf.GetFont()->GetEscapement(); if ( nVal > 0 ) nVal = 33; else if ( nVal < 0 ) nVal = -33; if ( 0 != nVal ) { nVal = nVal * pPor->Height() / 100; mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::BaselineShift, nVal ); } } if ( bTextDecorationType ) { if ( UNDERLINE_NONE != rInf.GetFont()->GetUnderline() ) mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Underline ); if ( UNDERLINE_NONE != rInf.GetFont()->GetOverline() ) mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Overline ); if ( STRIKEOUT_NONE != rInf.GetFont()->GetStrikeout() ) mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::LineThrough ); if ( EMPHASISMARK_NONE != rInf.GetFont()->GetEmphasisMark() ) mpPDFExtOutDevData->SetStructureAttribute( vcl::PDFWriter::TextDecorationType, vcl::PDFWriter::Overline ); } if ( bLanguage ) { const LanguageType nCurrentLanguage = rInf.GetFont()->GetLanguage(); const LanguageType nDefaultLang = SwEnhancedPDFExportHelper::GetDefaultLanguage(); if ( nDefaultLang != nCurrentLanguage ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::Language, nCurrentLanguage ); } if ( bLinkAttribute ) { const LinkIdMap& rLinkIdMap = SwEnhancedPDFExportHelper::GetLinkIdMap(); SwRect aPorRect; rInf.CalcRect( *pPor, &aPorRect ); const Point aPorCenter = aPorRect.Center(); LinkIdMap::const_iterator aIter; for ( aIter = rLinkIdMap.begin(); aIter != rLinkIdMap.end(); ++aIter ) { const SwRect& rLinkRect = (*aIter).first; if ( rLinkRect.IsInside( aPorCenter ) ) { sal_Int32 nLinkId = (*aIter).second; mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::LinkAnnotation, nLinkId ); break; } } } } } /* * SwTaggedPDFHelper::BeginNumberedListStructureElements() */ void SwTaggedPDFHelper::BeginNumberedListStructureElements() { OSL_ENSURE( mpNumInfo, "List without mpNumInfo?" ); if ( !mpNumInfo ) return; const SwFrm& rFrm = mpNumInfo->mrFrm; OSL_ENSURE( rFrm.IsTxtFrm(), "numbered only for text frames" ); const SwTxtFrm& rTxtFrm = static_cast(rFrm); // // Lowers of NonStructureElements should not be considered: // if ( lcl_IsInNonStructEnv( rTxtFrm ) || rTxtFrm.IsFollow() ) return; const SwTxtNode* pTxtNd = rTxtFrm.GetTxtNode(); const SwNumRule* pNumRule = pTxtNd->GetNumRule(); const SwNodeNum* pNodeNum = pTxtNd->GetNum(); const bool bNumbered = !pTxtNd->IsOutline() && pNodeNum && pNodeNum->GetParent() && pNumRule; // Check, if we have to reopen a list or a list body: // First condition: // Paragraph is numbered/bulleted if ( !bNumbered ) return; const SwNumberTreeNode* pParent = pNodeNum->GetParent(); const bool bSameNumbering = lcl_HasPreviousParaSameNumRule(*pTxtNd); // Second condition: current numbering is not 'interrupted' if ( bSameNumbering ) { sal_Int32 nReopenTag = -1; // Two cases: // 1. We have to reopen an existing list body tag: // - If the current node is either the first child of its parent // and its level > 1 or // - Numbering should restart at the current node and its level > 1 // - The current item has no label const bool bNewSubListStart = pParent->GetParent() && (pParent->IsFirst( pNodeNum ) || pTxtNd->IsListRestart() ); const bool bNoLabel = !pTxtNd->IsCountedInList() && !pTxtNd->IsListRestart(); if ( bNewSubListStart || bNoLabel ) { // Fine, we try to reopen the appropriate list body NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap(); if ( bNewSubListStart ) { // The list body tag associated with the parent has to be reopened // to start a new list inside the list body NumListBodyIdMap::const_iterator aIter; do aIter = rNumListBodyIdMap.find( pParent ); while ( aIter == rNumListBodyIdMap.end() && 0 != ( pParent = pParent->GetParent() ) ); if ( aIter != rNumListBodyIdMap.end() ) nReopenTag = (*aIter).second; } else // if(bNoLabel) { // The list body tag of a 'counted' predecessor has to be reopened const SwNumberTreeNode* pPrevious = pNodeNum->GetPred(true); while ( pPrevious ) { if ( pPrevious->IsCounted()) { // get id of list body tag const NumListBodyIdMap::const_iterator aIter = rNumListBodyIdMap.find( pPrevious ); if ( aIter != rNumListBodyIdMap.end() ) { nReopenTag = (*aIter).second; break; } } pPrevious = pPrevious->GetPred(true); } } } // 2. We have to reopen an existing list tag: else if ( !pParent->IsFirst( pNodeNum ) && !pTxtNd->IsListRestart() ) { // any other than the first node in a list level has to reopen the current // list. The current list is associated in a map with the first child of the list: NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap(); // Search backwards and check if any of the previous nodes has a list associated with it: const SwNumberTreeNode* pPrevious = pNodeNum->GetPred(true); while ( pPrevious ) { // get id of list tag const NumListIdMap::const_iterator aIter = rNumListIdMap.find( pPrevious ); if ( aIter != rNumListIdMap.end() ) { nReopenTag = (*aIter).second; break; } pPrevious = pPrevious->GetPred(true); } } if ( -1 != nReopenTag ) { nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement(); mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag ); #if OSL_DEBUG_LEVEL > 1 aStructStack.push_back( 99 ); #endif } } else { // clear list maps in case a list has been interrupted NumListIdMap& rNumListIdMap = SwEnhancedPDFExportHelper::GetNumListIdMap(); rNumListIdMap.clear(); NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap(); rNumListBodyIdMap.clear(); } // New tags: const bool bNewListTag = (pNodeNum->GetParent()->IsFirst( pNodeNum ) || pTxtNd->IsListRestart() || !bSameNumbering); const bool bNewItemTag = bNewListTag || pTxtNd->IsCountedInList(); // If the text node is not counted, we do not start a new list item: if ( bNewListTag ) BeginTag( vcl::PDFWriter::List, aListString ); if ( bNewItemTag ) { BeginTag( vcl::PDFWriter::ListItem, aListItemString ); BeginTag( vcl::PDFWriter::LIBody, aListBodyString ); } } /* * SwTaggedPDFHelper::BeginBlockStructureElements() */ void SwTaggedPDFHelper::BeginBlockStructureElements() { const SwFrm* pFrm = &mpFrmInfo->mrFrm; // // Lowers of NonStructureElements should not be considered: // if ( lcl_IsInNonStructEnv( *pFrm ) ) return; // Check if we have to reopen an existing structure element. // This has to be done e.g., if pFrm is a follow frame. if ( CheckReopenTag() ) return; sal_uInt16 nPDFType = USHRT_MAX; String aPDFType; switch ( pFrm->GetType() ) { /* * GROUPING ELEMENTS */ case FRM_PAGE : // // Document: Document // nPDFType = vcl::PDFWriter::Document; aPDFType = aDocumentString; break; case FRM_HEADER : case FRM_FOOTER : // // Header, Footer: NonStructElement // nPDFType = vcl::PDFWriter::NonStructElement; break; case FRM_FTNCONT : // // Footnote container: Division // nPDFType = vcl::PDFWriter::Division; aPDFType = aDivString; break; case FRM_FTN : // // Footnote frame: Note // // Note: vcl::PDFWriter::Note is actually a ILSE. Nevertheless // we treat it like a grouping element! nPDFType = vcl::PDFWriter::Note; aPDFType = aNoteString; break; case FRM_SECTION : // // Section: TOX, Index, or Sect // { const SwSection* pSection = static_cast(pFrm)->GetSection(); if ( TOX_CONTENT_SECTION == pSection->GetType() ) { const SwTOXBase* pTOXBase = pSection->GetTOXBase(); if ( pTOXBase ) { if ( TOX_INDEX == pTOXBase->GetType() ) { nPDFType = vcl::PDFWriter::Index; aPDFType = aIndexString; } else { nPDFType = vcl::PDFWriter::TOC; aPDFType = aTOCString; } } } else if ( CONTENT_SECTION == pSection->GetType() ) { nPDFType = vcl::PDFWriter::Section; aPDFType = aSectString; } } break; /* * BLOCK-LEVEL STRUCTURE ELEMENTS */ case FRM_TXT : { const SwTxtNode* pTxtNd = static_cast(pFrm)->GetTxtNode(); const SwFmt* pTxtFmt = pTxtNd->GetFmtColl(); const SwFmt* pParentTxtFmt = pTxtFmt ? pTxtFmt->DerivedFrom() : NULL; String sStyleName; String sParentStyleName; if ( pTxtFmt) SwStyleNameMapper::FillProgName( pTxtFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); if ( pParentTxtFmt) SwStyleNameMapper::FillProgName( pParentTxtFmt->GetName(), sParentStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); // This is the default. If the paragraph could not be mapped to // any of the standard pdf tags, we write a user defined tag // with role = P nPDFType = static_cast(vcl::PDFWriter::Paragraph); aPDFType = sStyleName; // // Quotations: BlockQuote // if ( sStyleName == aQuotations ) { nPDFType = static_cast(vcl::PDFWriter::BlockQuote); aPDFType = aBlockQuoteString; } // // Caption: Caption // else if ( sStyleName == aCaption) { nPDFType = static_cast(vcl::PDFWriter::Caption); aPDFType = aCaptionString; } // // Caption: Caption // else if ( sParentStyleName == aCaption) { nPDFType = static_cast(vcl::PDFWriter::Caption); aPDFType = sStyleName.Append(aCaptionString); } // // Heading: H // else if ( sStyleName == aHeading ) { nPDFType = static_cast(vcl::PDFWriter::Heading); aPDFType = aHString; } // // Heading: H1 - H6 // if ( pTxtNd->IsOutline() ) { //int nRealLevel = pTxtNd->GetOutlineLevel(); //#outline level,zhaojianwei int nRealLevel = pTxtNd->GetAttrOutlineLevel()-1; //<-end,zhaojianwei nRealLevel = nRealLevel > 5 ? 5 : nRealLevel; nPDFType = static_cast(vcl::PDFWriter::H1 + nRealLevel); switch(nRealLevel) { case 0 : aPDFType = aH1String; break; case 1 : aPDFType = aH2String; break; case 2 : aPDFType = aH3String; break; case 3 : aPDFType = aH4String; break; case 4 : aPDFType = aH5String; break; default: aPDFType = aH6String; break; } } // // Section: TOCI // else if ( pFrm->IsInSct() ) { const SwSectionFrm* pSctFrm = pFrm->FindSctFrm(); const SwSection* pSection = static_cast(pSctFrm)->GetSection(); if ( TOX_CONTENT_SECTION == pSection->GetType() ) { const SwTOXBase* pTOXBase = pSection->GetTOXBase(); if ( pTOXBase && TOX_INDEX != pTOXBase->GetType() ) { // Special case: Open additional TOCI tag: BeginTag( vcl::PDFWriter::TOCI, aTOCIString ); } } } } break; case FRM_TAB : // // TabFrm: Table // nPDFType = vcl::PDFWriter::Table; aPDFType = aTableString; { // set up table column data: const SwTabFrm* pTabFrm = static_cast(pFrm); const SwTable* pTable = pTabFrm->GetTable(); TableColumnsMap& rTableColumnsMap = SwEnhancedPDFExportHelper::GetTableColumnsMap(); const TableColumnsMap::const_iterator aIter = rTableColumnsMap.find( pTable ); if ( aIter == rTableColumnsMap.end() ) { SWRECTFN( pTabFrm ) TableColumnsMapEntry& rCols = rTableColumnsMap[ pTable ]; const SwTabFrm* pMasterFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm; while ( pMasterFrm ) { const SwRowFrm* pRowFrm = static_cast(pMasterFrm->GetLower()); while ( pRowFrm ) { const SwFrm* pCellFrm = pRowFrm->GetLower(); const long nLeft = (pCellFrm->Frm().*fnRect->fnGetLeft)(); rCols.insert( nLeft ); while ( pCellFrm ) { const long nRight = (pCellFrm->Frm().*fnRect->fnGetRight)(); rCols.insert( nRight ); pCellFrm = pCellFrm->GetNext(); } pRowFrm = static_cast(pRowFrm->GetNext()); } pMasterFrm = static_cast(pMasterFrm->GetFollow()); } } } break; /* * TABLE ELEMENTS */ case FRM_ROW : // // RowFrm: TR // if ( !static_cast(pFrm)->IsRepeatedHeadline() ) { nPDFType = vcl::PDFWriter::TableRow; aPDFType = aTRString; } else { nPDFType = vcl::PDFWriter::NonStructElement; } break; case FRM_CELL : // // CellFrm: TH, TD // { const SwTabFrm* pTable = static_cast(pFrm)->FindTabFrm(); if ( pTable->IsInHeadline( *pFrm ) || lcl_IsHeadlineCell( *static_cast(pFrm) ) ) { nPDFType = vcl::PDFWriter::TableHeader; aPDFType = aTHString; } else { nPDFType = vcl::PDFWriter::TableData; aPDFType = aTDString; } } break; /* * ILLUSTRATION */ case FRM_FLY : // // FlyFrm: Figure, Formula, Control // fly in content or fly at page { bool bFormula = false; const SwFlyFrm* pFly = static_cast(pFrm); if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() ) { const SwNoTxtFrm* pNoTxtFrm = static_cast(pFly->Lower()); SwOLENode* pOLENd = const_cast(pNoTxtFrm->GetNode()->GetOLENode()); if ( pOLENd ) { SwOLEObj& aOLEObj = pOLENd->GetOLEObj(); uno::Reference< embed::XEmbeddedObject > aRef = aOLEObj.GetOleRef(); if ( aRef.is() ) { bFormula = 0 != SotExchange::IsMath( SvGlobalName( aRef->getClassID() ) ); } } if ( bFormula ) { nPDFType = vcl::PDFWriter::Formula; aPDFType = aFormulaString; } else { nPDFType = vcl::PDFWriter::Figure; aPDFType = aFigureString; } } else { nPDFType = vcl::PDFWriter::Division; aPDFType = aDivString; } } break; } if ( USHRT_MAX != nPDFType ) { BeginTag( static_cast(nPDFType), aPDFType ); } } /* * SwTaggedPDFHelper::EndStructureElements() */ void SwTaggedPDFHelper::EndStructureElements() { while ( nEndStructureElement > 0 ) { EndTag(); --nEndStructureElement; } CheckRestoreTag(); } /* * SwTaggedPDFHelper::BeginInlineStructureElements() */ void SwTaggedPDFHelper::BeginInlineStructureElements() { const SwLinePortion* pPor = &mpPorInfo->mrPor; const SwTxtPaintInfo& rInf = mpPorInfo->mrTxtPainter.GetInfo(); const SwTxtFrm* pFrm = rInf.GetTxtFrm(); // // Lowers of NonStructureElements should not be considered: // if ( lcl_IsInNonStructEnv( *pFrm ) ) return; sal_uInt16 nPDFType = USHRT_MAX; String aPDFType; switch ( pPor->GetWhichPor() ) { // Check for alternative spelling: case POR_HYPHSTR : case POR_SOFTHYPHSTR : nPDFType = vcl::PDFWriter::Span; aPDFType = aSpanString; break; case POR_LAY : case POR_TXT : case POR_PARA : { SwTxtNode* pNd = (SwTxtNode*)pFrm->GetTxtNode(); SwTxtAttr const*const pInetFmtAttr = pNd->GetTxtAttrAt(rInf.GetIdx(), RES_TXTATR_INETFMT); String sStyleName; if ( !pInetFmtAttr ) { ::std::vector const charAttrs( pNd->GetTxtAttrsAt(rInf.GetIdx(), RES_TXTATR_CHARFMT)); // TODO: handle more than 1 char style? const SwCharFmt* pCharFmt = (charAttrs.size()) ? (*charAttrs.begin())->GetCharFmt().GetCharFmt() : 0; if ( pCharFmt ) SwStyleNameMapper::FillProgName( pCharFmt->GetName(), sStyleName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); } // Check for Link: if( pInetFmtAttr ) { nPDFType = vcl::PDFWriter::Link; aPDFType = aLinkString; } // Check for Quote/Code character style: else if ( sStyleName == aQuotation ) { nPDFType = vcl::PDFWriter::Quote; aPDFType = aQuoteString; } else if ( sStyleName == aSourceText ) { nPDFType = vcl::PDFWriter::Code; aPDFType = aCodeString; } else { const LanguageType nCurrentLanguage = rInf.GetFont()->GetLanguage(); const sal_uInt16 nFont = rInf.GetFont()->GetActual(); const LanguageType nDefaultLang = SwEnhancedPDFExportHelper::GetDefaultLanguage(); if ( UNDERLINE_NONE != rInf.GetFont()->GetUnderline() || UNDERLINE_NONE != rInf.GetFont()->GetOverline() || STRIKEOUT_NONE != rInf.GetFont()->GetStrikeout() || EMPHASISMARK_NONE != rInf.GetFont()->GetEmphasisMark() || 0 != rInf.GetFont()->GetEscapement() || SW_LATIN != nFont || nCurrentLanguage != nDefaultLang || sStyleName.Len() > 0 ) { nPDFType = vcl::PDFWriter::Span; if ( sStyleName.Len() > 0 ) aPDFType = sStyleName; else aPDFType = aSpanString; } } } break; case POR_FTN : nPDFType = vcl::PDFWriter::Link; aPDFType = aLinkString; break; case POR_FLD : { // check field type: const xub_StrLen nIdx = static_cast(pPor)->IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx(); const SwTxtAttr* pHint = mpPorInfo->mrTxtPainter.GetAttr( nIdx ); const SwField* pFld = 0; if ( pHint && RES_TXTATR_FIELD == pHint->Which() ) { pFld = (SwField*)pHint->GetFld().GetFld(); if ( RES_GETREFFLD == pFld->Which() ) { nPDFType = vcl::PDFWriter::Link; aPDFType = aLinkString; } else if ( RES_AUTHORITY == pFld->Which() ) { nPDFType = vcl::PDFWriter::BibEntry; aPDFType = aBibEntryString; } } } break; case POR_TAB : case POR_TABRIGHT : case POR_TABCENTER : case POR_TABDECIMAL : nPDFType = vcl::PDFWriter::NonStructElement; break; } if ( USHRT_MAX != nPDFType ) { BeginTag( static_cast(nPDFType), aPDFType ); } } /* * static SwTaggedPDFHelper::IsExportTaggedPDF */ bool SwTaggedPDFHelper::IsExportTaggedPDF( const OutputDevice& rOut ) { vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, rOut.GetExtOutDevData() ); return pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF(); } /* * SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper() */ SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper( SwEditShell& rSh, OutputDevice& rOut, const rtl::OUString& rPageRange, bool bSkipEmptyPages, bool bEditEngineOnly ) : mrSh( rSh ), mrOut( rOut ), pPageRange( 0 ), mbSkipEmptyPages( bSkipEmptyPages ), mbEditEngineOnly( bEditEngineOnly ) { if ( rPageRange.getLength() ) pPageRange = new MultiSelection( rPageRange ); aTableColumnsMap.clear(); aLinkIdMap.clear(); aNumListIdMap.clear(); aNumListBodyIdMap.clear(); aFrmTagIdMap.clear(); #if OSL_DEBUG_LEVEL > 1 aStructStack.clear(); #endif const sal_uInt8 nScript = (sal_uInt8)GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() ); sal_uInt16 nLangRes = RES_CHRATR_LANGUAGE; if ( i18n::ScriptType::ASIAN == nScript ) nLangRes = RES_CHRATR_CJK_LANGUAGE; else if ( i18n::ScriptType::COMPLEX == nScript ) nLangRes = RES_CHRATR_CTL_LANGUAGE; eLanguageDefault = static_cast(&mrSh.GetDoc()->GetDefault( nLangRes ))->GetLanguage(); EnhancedPDFExport(); } SwEnhancedPDFExportHelper::~SwEnhancedPDFExportHelper() { delete pPageRange; } /* * SwEnhancedPDFExportHelper::EnhancedPDFExport() */ void SwEnhancedPDFExportHelper::EnhancedPDFExport() { vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, mrOut.GetExtOutDevData() ); if ( !pPDFExtOutDevData ) return; // // set the document locale // com::sun::star::lang::Locale aDocLocale = MsLangId::convertLanguageToLocale( SwEnhancedPDFExportHelper::GetDefaultLanguage() ); pPDFExtOutDevData->SetDocumentLocale( aDocLocale ); // // Prepare the output device: // mrOut.Push( PUSH_MAPMODE ); MapMode aMapMode( mrOut.GetMapMode() ); aMapMode.SetMapUnit( MAP_TWIP ); mrOut.SetMapMode( aMapMode ); // // Create new cursor and lock the view: // SwDoc* pDoc = mrSh.GetDoc(); mrSh.SwCrsrShell::Push(); mrSh.SwCrsrShell::ClearMark(); const sal_Bool bOldLockView = mrSh.IsViewLocked(); mrSh.LockView( sal_True ); if ( !mbEditEngineOnly ) { // // POSTITS // if ( pPDFExtOutDevData->GetIsExportNotes() ) { SwFieldType* pType = mrSh.GetFldType( RES_POSTITFLD, aEmptyStr ); SwIterator aIter( *pType ); for( SwFmtFld* pFirst = aIter.First(); pFirst; ) { if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() ) { const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode(); OSL_ENSURE( 0 != pTNd, "Enhanced pdf export - text node is missing" ); // 1. Check if the whole paragraph is hidden // 2. Move to the field // 3. Check for hidden text attribute if ( !pTNd->IsHidden() && mrSh.GotoFld( *pFirst ) && !mrSh.SelectHiddenRange() ) { // Link Rectangle const SwRect& rNoteRect = mrSh.GetCharRect(); // Link PageNum const sal_Int32 nNotePageNum = CalcOutputPageNum( rNoteRect ); if ( -1 != nNotePageNum ) { // Link Note vcl::PDFNote aNote; // Use the NumberFormatter to get the date string: const SwPostItField* pField = (SwPostItField*)pFirst->GetFld(); SvNumberFormatter* pNumFormatter = pDoc->GetNumberFormatter(); const Date aDateDiff( pField->GetDate() - *pNumFormatter->GetNullDate() ); const sal_uLong nFormat = pNumFormatter->GetStandardFormat( NUMBERFORMAT_DATE, pField->GetLanguage() ); String sDate; Color* pColor; pNumFormatter->GetOutputString( aDateDiff.GetDate(), nFormat, sDate, &pColor ); // The title should consist of the author and the date: String sTitle( pField->GetPar1() ); sTitle.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) ); sTitle += sDate; aNote.Title = sTitle; // Guess what the contents contains... aNote.Contents = pField->GetTxt(); // Link Export pPDFExtOutDevData->CreateNote( rNoteRect.SVRect(), aNote, nNotePageNum ); } } } pFirst = aIter.Next(); mrSh.SwCrsrShell::ClearMark(); } } // // HYPERLINKS // SwGetINetAttrs aArr; const sal_uInt16 nHyperLinkCount = mrSh.GetINetAttrs( aArr ); for( sal_uInt16 n = 0; n < nHyperLinkCount; ++n ) { SwGetINetAttr* p = aArr[ n ]; OSL_ENSURE( 0 != p, "Enhanced pdf export - SwGetINetAttr is missing" ); const SwTxtNode* pTNd = p->rINetAttr.GetpTxtNode(); OSL_ENSURE( 0 != pTNd, "Enhanced pdf export - text node is missing" ); // 1. Check if the whole paragraph is hidden // 2. Move to the hyperlink // 3. Check for hidden text attribute if ( !pTNd->IsHidden() && mrSh.GotoINetAttr( p->rINetAttr ) && !mrSh.SelectHiddenRange() ) { // Select the hyperlink: mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS ); if ( mrSh.SwCrsrShell::SelectTxtAttr( RES_TXTATR_INETFMT, sal_True ) ) { // First, we create the destination, because there may be more // than one link to this destination: String aURL( INetURLObject::decode( p->rINetAttr.GetINetFmt().GetValue(), INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS, RTL_TEXTENCODING_UTF8 ) ); // We have to distinguish between intern and real URLs const bool bIntern = '#' == aURL.GetChar( 0 ); // _GetCrsr() is a SwShellCrsr, which is derived from // SwSelPaintRects, therefore the rectangles of the current // selection can be easily obtained: // Note: We make a copy of the rectangles, because they may // be deleted again in JumpToSwMark. SwRects aTmp; aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 ); OSL_ENSURE( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" ); // Create the destination for internal links: sal_Int32 nDestId = -1; if ( bIntern ) { aURL.Erase( 0, 1 ); mrSh.SwCrsrShell::ClearMark(); JumpToSwMark( &mrSh, aURL ); // Destination Rectangle const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); // Destination Export if ( -1 != nDestPageNum ) nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum ); } if ( !bIntern || -1 != nDestId ) { // #i44368# Links in Header/Footer const SwPosition aPos( *pTNd ); const bool bHeaderFooter = pDoc->IsInHeaderFooter( aPos.nNode ); // Create links for all selected rectangles: const sal_uInt16 nNumOfRects = aTmp.Count(); for ( sal_uInt16 i = 0; i < nNumOfRects; ++i ) { // Link Rectangle const SwRect& rLinkRect( aTmp[ i ] ); // Link PageNum const sal_Int32 nLinkPageNum = CalcOutputPageNum( rLinkRect ); if ( -1 != nLinkPageNum ) { // Link Export const sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink( rLinkRect.SVRect(), nLinkPageNum ); // Store link info for tagged pdf output: const IdMapEntry aLinkEntry( rLinkRect, nLinkId ); aLinkIdMap.push_back( aLinkEntry ); // Connect Link and Destination: if ( bIntern ) pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId ); else pPDFExtOutDevData->SetLinkURL( nLinkId, aURL ); // #i44368# Links in Header/Footer if ( bHeaderFooter ) MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, rLinkRect, nDestId, aURL, bIntern ); } } } } } mrSh.SwCrsrShell::ClearMark(); } // // HYPERLINKS (Graphics, Frames, OLEs ) // const SwSpzFrmFmts* pTbl = pDoc->GetSpzFrmFmts(); const sal_uInt16 nSpzFrmFmtsCount = pTbl->Count(); for( sal_uInt16 n = 0; n < nSpzFrmFmtsCount; ++n ) { const SwFrmFmt* pFrmFmt = (*pTbl)[n]; const SfxPoolItem* pItem; if ( RES_DRAWFRMFMT != pFrmFmt->Which() && SFX_ITEM_SET == pFrmFmt->GetAttrSet().GetItemState( RES_URL, sal_True, &pItem ) ) { String aURL( static_cast(pItem)->GetURL() ); const bool bIntern = '#' == aURL.GetChar( 0 ); // Create the destination for internal links: sal_Int32 nDestId = -1; if ( bIntern ) { aURL.Erase( 0, 1 ); mrSh.SwCrsrShell::ClearMark(); JumpToSwMark( &mrSh, aURL ); // Destination Rectangle const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); // Destination Export if ( -1 != nDestPageNum ) nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum ); } if ( !bIntern || -1 != nDestId ) { Point aNullPt; const SwRect aLinkRect = pFrmFmt->FindLayoutRect( sal_False, &aNullPt ); // Link PageNum const sal_Int32 nLinkPageNum = CalcOutputPageNum( aLinkRect ); // Link Export if ( -1 != nLinkPageNum ) { const sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink( aLinkRect.SVRect(), nLinkPageNum ); // Connect Link and Destination: if ( bIntern ) pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId ); else pPDFExtOutDevData->SetLinkURL( nLinkId, aURL ); // #i44368# Links in Header/Footer const SwFmtAnchor &rAnch = pFrmFmt->GetAnchor(); if (FLY_AT_PAGE != rAnch.GetAnchorId()) { const SwPosition* pPosition = rAnch.GetCntntAnchor(); if ( pPosition && pDoc->IsInHeaderFooter( pPosition->nNode ) ) { const SwTxtNode* pTNd = pPosition->nNode.GetNode().GetTxtNode(); if ( pTNd ) MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, aLinkRect, nDestId, aURL, bIntern ); } } } } } mrSh.SwCrsrShell::ClearMark(); } // // REFERENCES // SwFieldType* pType = mrSh.GetFldType( RES_GETREFFLD, aEmptyStr ); SwIterator aIter( *pType ); for( SwFmtFld* pFirst = aIter.First(); pFirst; ) { if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() ) { const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode(); OSL_ENSURE( 0 != pTNd, "Enhanced pdf export - text node is missing" ); // 1. Check if the whole paragraph is hidden // 2. Move to the field // 3. Check for hidden text attribute if ( !pTNd->IsHidden() && mrSh.GotoFld( *pFirst ) && !mrSh.SelectHiddenRange() ) { // Select the field: mrSh.SwCrsrShell::SetMark(); mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS ); // Link Rectangles SwRects aTmp; aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 ); OSL_ENSURE( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" ); mrSh.SwCrsrShell::ClearMark(); // Destination Rectangle const SwGetRefField* pField = (SwGetRefField*)pFirst->GetFld(); const String& rRefName = pField->GetSetRefName(); mrSh.GotoRefMark( rRefName, pField->GetSubType(), pField->GetSeqNo() ); const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); if ( -1 != nDestPageNum ) { // Destination Export const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum ); // #i44368# Links in Header/Footer const SwPosition aPos( *pTNd ); const bool bHeaderFooter = pDoc->IsInHeaderFooter( aPos.nNode ); // Create links for all selected rectangles: const sal_uInt16 nNumOfRects = aTmp.Count(); for ( sal_uInt16 i = 0; i < nNumOfRects; ++i ) { // Link rectangle const SwRect& rLinkRect( aTmp[ i ] ); // Link PageNum const sal_Int32 nLinkPageNum = CalcOutputPageNum( rLinkRect ); if ( -1 != nLinkPageNum ) { // Link Export const sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink( rLinkRect.SVRect(), nLinkPageNum ); // Store link info for tagged pdf output: const IdMapEntry aLinkEntry( rLinkRect, nLinkId ); aLinkIdMap.push_back( aLinkEntry ); // Connect Link and Destination: pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId ); // #i44368# Links in Header/Footer if ( bHeaderFooter ) { const String aDummy; MakeHeaderFooterLinks( *pPDFExtOutDevData, *pTNd, rLinkRect, nDestId, aDummy, true ); } } } } } } pFirst = aIter.Next(); mrSh.SwCrsrShell::ClearMark(); } // // FOOTNOTES // const sal_uInt16 nFtnCount = pDoc->GetFtnIdxs().Count(); for ( sal_uInt16 nIdx = 0; nIdx < nFtnCount; ++nIdx ) { // Set cursor to text node that contains the footnote: const SwTxtFtn* pTxtFtn = pDoc->GetFtnIdxs()[ nIdx ]; SwTxtNode& rTNd = const_cast(pTxtFtn->GetTxtNode()); mrSh._GetCrsr()->GetPoint()->nNode = rTNd; mrSh._GetCrsr()->GetPoint()->nContent.Assign( &rTNd, *pTxtFtn->GetStart() ); // 1. Check if the whole paragraph is hidden // 2. Check for hidden text attribute if ( static_cast(rTNd).IsHidden() || mrSh.SelectHiddenRange() ) continue; SwCrsrSaveState aSaveState( *mrSh._GetCrsr() ); // Select the footnote: mrSh.SwCrsrShell::SetMark(); mrSh.SwCrsrShell::Right( 1, CRSR_SKIP_CHARS ); // Link Rectangle SwRects aTmp; aTmp.Insert( mrSh.SwCrsrShell::_GetCrsr(), 0 ); OSL_ENSURE( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" ); const SwRect aLinkRect( aTmp[ 0 ] ); mrSh._GetCrsr()->RestoreSavePos(); mrSh.SwCrsrShell::ClearMark(); // Goto footnote text: if ( mrSh.GotoFtnTxt() ) { // Link PageNum const sal_Int32 nLinkPageNum = CalcOutputPageNum( aLinkRect ); if ( -1 != nLinkPageNum ) { // Link Export const sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink( aLinkRect.SVRect(), nLinkPageNum ); // Store link info for tagged pdf output: const IdMapEntry aLinkEntry( aLinkRect, nLinkId ); aLinkIdMap.push_back( aLinkEntry ); // Destination Rectangle const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); if ( -1 != nDestPageNum ) { // Destination Export const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum ); // Connect Link and Destination: pPDFExtOutDevData->SetLinkDest( nLinkId, nDestId ); } } } } // // OUTLINE // if( pPDFExtOutDevData->GetIsExportBookmarks() ) { typedef std::pair< sal_Int8, sal_Int32 > StackEntry; std::stack< StackEntry > aOutlineStack; aOutlineStack.push( StackEntry( -1, -1 ) ); // push default value const sal_uInt16 nOutlineCount = static_cast(mrSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount()); for ( sal_uInt16 i = 0; i < nOutlineCount; ++i ) { // Check if outline is hidden const SwTxtNode* pTNd = mrSh.GetNodes().GetOutLineNds()[ i ]->GetTxtNode(); OSL_ENSURE( 0 != pTNd, "Enhanced pdf export - text node is missing" ); if ( pTNd->IsHidden() || // #i40292# Skip empty outlines: 0 == pTNd->GetTxt().Len() ) continue; // Get parent id from stack: const sal_Int8 nLevel = (sal_Int8)mrSh.getIDocumentOutlineNodesAccess()->getOutlineLevel( i ); sal_Int8 nLevelOnTopOfStack = aOutlineStack.top().first; while ( nLevelOnTopOfStack >= nLevel && nLevelOnTopOfStack != -1 ) { aOutlineStack.pop(); nLevelOnTopOfStack = aOutlineStack.top().first; } const sal_Int32 nParent = aOutlineStack.top().second; // Destination rectangle mrSh.GotoOutline(i); const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); if ( -1 != nDestPageNum ) { // Destination Export const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum ); // Outline entry text const String& rEntry = mrSh.getIDocumentOutlineNodesAccess()->getOutlineText( i ); // Create a new outline item: const sal_Int32 nOutlineId = pPDFExtOutDevData->CreateOutlineItem( nParent, rEntry, nDestId ); // Push current level and nOutlineId on stack: aOutlineStack.push( StackEntry( nLevel, nOutlineId ) ); } } } if( pPDFExtOutDevData->GetIsExportNamedDestinations() ) { // #i56629# the iteration to convert the OOo bookmark (#bookmark) // into PDF named destination, see section 8.2.1 in PDF 1.4 spec // We need: // 1. a name for the destination, formed from the standard OOo bookmark name // 2. the destination, obtained from where the bookmark destination lies IDocumentMarkAccess* const pMarkAccess = mrSh.GetDoc()->getIDocumentMarkAccess(); for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin(); ppMark != pMarkAccess->getBookmarksEnd(); ppMark++) { //get the name const ::sw::mark::IMark* pBkmk = ppMark->get(); mrSh.SwCrsrShell::ClearMark(); rtl::OUString sBkName = pBkmk->GetName(); //jump to it JumpToSwMark( &mrSh, sBkName ); // Destination Rectangle const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); // Destination Export if ( -1 != nDestPageNum ) pPDFExtOutDevData->CreateNamedDest( sBkName, rDestRect.SVRect(), nDestPageNum ); } mrSh.SwCrsrShell::ClearMark(); //<--- i56629 } } else { // // LINKS FROM EDITENGINE // std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks(); std::vector< vcl::PDFExtOutDevBookmarkEntry >::const_iterator aIBeg = rBookmarks.begin(); const std::vector< vcl::PDFExtOutDevBookmarkEntry >::const_iterator aIEnd = rBookmarks.end(); while ( aIBeg != aIEnd ) { String aBookmarkName( aIBeg->aBookmark ); const bool bIntern = '#' == aBookmarkName.GetChar( 0 ); if ( bIntern ) { aBookmarkName.Erase( 0, 1 ); JumpToSwMark( &mrSh, aBookmarkName ); // Destination Rectangle const SwRect& rDestRect = mrSh.GetCharRect(); // Destination PageNum const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect ); if ( -1 != nDestPageNum ) { if ( aIBeg->nLinkId != -1 ) { // Destination Export const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum ); // Connect Link and Destination: pPDFExtOutDevData->SetLinkDest( aIBeg->nLinkId, nDestId ); } else { pPDFExtOutDevData->DescribeRegisteredDest( aIBeg->nDestId, rDestRect.SVRect(), nDestPageNum ); } } } else pPDFExtOutDevData->SetLinkURL( aIBeg->nLinkId, aBookmarkName ); ++aIBeg; } rBookmarks.clear(); } // Restore view, cursor, and outdev: mrSh.LockView( bOldLockView ); mrSh.SwCrsrShell::Pop( sal_False ); mrOut.Pop(); } /* * SwEnhancedPDFExportHelper::CalcOutputPageNum() */ sal_Int32 SwEnhancedPDFExportHelper::CalcOutputPageNum( const SwRect& rRect ) const { // Document page numbers are 0, 1, 2, ... const sal_Int32 nPageNumOfRect = mrSh.GetPageNumAndSetOffsetForPDF( mrOut, rRect ); // Shortcut: if ( -1 == nPageNumOfRect || ( !pPageRange && !mbSkipEmptyPages ) ) return nPageNumOfRect; // pPageRange page numbers are 1, 2, 3, ... if ( pPageRange && !pPageRange->IsSelected( nPageNumOfRect + 1 ) ) return -1; // What will be the page number of page nPageNumOfRect in the output doc? sal_Int32 nOutputPageNum = -1; const SwRootFrm* pRootFrm = mrSh.GetLayout(); const SwPageFrm* pCurrPage = static_cast(pRootFrm->Lower()); for ( sal_Int32 nPageIndex = 0; nPageIndex <= nPageNumOfRect && pCurrPage; ++nPageIndex ) { if ( ( !pPageRange || pPageRange->IsSelected( nPageIndex + 1 ) ) && ( !mbSkipEmptyPages || !pCurrPage->IsEmptyPage() ) ) ++nOutputPageNum; pCurrPage = static_cast(pCurrPage->GetNext()); } // pdf export page numbers are 0, 1, 2, ... return nOutputPageNum; } void SwEnhancedPDFExportHelper::MakeHeaderFooterLinks( vcl::PDFExtOutDevData& rPDFExtOutDevData, const SwTxtNode& rTNd, const SwRect& rLinkRect, sal_Int32 nDestId, const String& rURL, bool bIntern ) const { // We assume, that the primary link has just been exported. Therefore // the offset of the link rectangle calculates as follows: const Point aOffset = rLinkRect.Pos() + mrOut.GetMapMode().GetOrigin(); SwIterator aIter( rTNd ); for ( SwTxtFrm* pTmpFrm = aIter.First(); pTmpFrm; pTmpFrm = aIter.Next() ) { // Add offset to current page: const SwPageFrm* pPageFrm = pTmpFrm->FindPageFrm(); SwRect aHFLinkRect( rLinkRect ); aHFLinkRect.Pos() = pPageFrm->Frm().Pos() + aOffset; // #i97135# the gcc_x64 optimizer gets aHFLinkRect != rLinkRect wrong // fool it by comparing the position only (the width and height are the // same anyway) if ( aHFLinkRect.Pos() != rLinkRect.Pos() ) { // Link PageNum const sal_Int32 nHFLinkPageNum = CalcOutputPageNum( aHFLinkRect ); if ( -1 != nHFLinkPageNum ) { // Link Export const sal_Int32 nHFLinkId = rPDFExtOutDevData.CreateLink( aHFLinkRect.SVRect(), nHFLinkPageNum ); // Connect Link and Destination: if ( bIntern ) rPDFExtOutDevData.SetLinkDest( nHFLinkId, nDestId ); else rPDFExtOutDevData.SetLinkURL( nHFLinkId, rURL ); } } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */