| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| #include <com/sun/star/embed/XEmbeddedObject.hpp> |
| #include <com/sun/star/i18n/ScriptType.hdl> |
| #include <EnhancedPDFExportHelper.hxx> |
| #include <hintids.hxx> |
| |
| #include <vcl/outdev.hxx> |
| #include <tools/multisel.hxx> |
| #include <editeng/adjitem.hxx> |
| #include <editeng/lrspitem.hxx> |
| #include <editeng/langitem.hxx> |
| #include <editeng/scripttypeitem.hxx> |
| #include <tools/urlobj.hxx> |
| #include <svl/zforlist.hxx> |
| #include <swatrset.hxx> |
| #include <frmatr.hxx> |
| #include <paratr.hxx> |
| #include <ndtxt.hxx> |
| #include <ndole.hxx> |
| #include <section.hxx> |
| #include <tox.hxx> |
| #include <fmtfld.hxx> |
| #include <txtinet.hxx> |
| #include <fmtinfmt.hxx> |
| #include <fchrfmt.hxx> |
| #include <charfmt.hxx> |
| #include <fmtanchr.hxx> |
| #include <fmturl.hxx> |
| #include <editsh.hxx> |
| #include <viscrs.hxx> |
| #include <txtfld.hxx> |
| #include <reffld.hxx> |
| #include <doc.hxx> |
| #include <docary.hxx> |
| #include <crsskip.hxx> |
| #include <mdiexp.hxx> |
| #include <docufld.hxx> |
| #include <ftnidx.hxx> |
| #include <txtftn.hxx> |
| #include <fmtftn.hxx> |
| #include <rootfrm.hxx> |
| #include <pagefrm.hxx> |
| #include <txtfrm.hxx> |
| #include <tabfrm.hxx> |
| #include <rowfrm.hxx> |
| #include <cellfrm.hxx> |
| #include <sectfrm.hxx> |
| #include <flyfrm.hxx> |
| #include <notxtfrm.hxx> |
| #include <porfld.hxx> |
| #include <SwStyleNameMapper.hxx> |
| #include <itrpaint.hxx> |
| #include "i18npool/mslangid.hxx" |
| #include <IMark.hxx> |
| #include <SwNodeNum.hxx> |
| #include <switerator.hxx> |
| #include <stack> |
| |
| #include <tools/globname.hxx> |
| |
| 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; |
| |
| #ifdef DBG_UTIL |
| |
| 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<const SwTxtFrm*>(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<const SwPageFrm&>(rFrm).GetFmt()->getIDocumentSettingAccess(); |
| else if ( rFrm.IsTxtFrm() ) |
| pKey = (void*)static_cast<const SwTxtFrm&>(rFrm).GetTxtNode(); |
| else if ( rFrm.IsSctFrm() ) |
| pKey = (void*)static_cast<const SwSectionFrm&>(rFrm).GetSection(); |
| else if ( rFrm.IsTabFrm() ) |
| pKey = (void*)static_cast<const SwTabFrm&>(rFrm).GetTable(); |
| else if ( rFrm.IsRowFrm() ) |
| pKey = (void*)static_cast<const SwRowFrm&>(rFrm).GetTabLine(); |
| else if ( rFrm.IsCellFrm() ) |
| { |
| const SwTabFrm* pTabFrm = rFrm.FindTabFrm(); |
| const SwTable* pTable = pTabFrm->GetTable(); |
| pKey = (void*) & static_cast<const SwCellFrm&>(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() ) |
| { |
| #ifdef DBG_UTIL |
| 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 ); |
| |
| #ifdef DBG_UTIL |
| nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); |
| lcl_DBGCheckStack(); |
| #endif |
| } |
| } |
| |
| |
| /* |
| * SwTaggedPDFHelper::~SwTaggedPDFHelper() |
| */ |
| SwTaggedPDFHelper::~SwTaggedPDFHelper() |
| { |
| if ( mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF() ) |
| { |
| #ifdef DBG_UTIL |
| sal_Int32 nCurrentStruct = mpPDFExtOutDevData->GetCurrentStructureElement(); |
| lcl_DBGCheckStack(); |
| #endif |
| EndStructureElements(); |
| |
| #ifdef DBG_UTIL |
| 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<const SwPageFrm&>(rFrm).GetPrev() ) || |
| ( rFrm.IsFlowFrm() && SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() ) || |
| ( rFrm.IsRowFrm() && rFrm.IsInFollowFlowRow() ) || |
| ( rFrm.IsCellFrm() && const_cast<SwFrm&>(rFrm).GetPrevCellLeaf( MAKEPAGE_NONE ) ) ) |
| { |
| pKeyFrm = &rFrm; |
| } |
| else if ( rFrm.IsFlyFrm() ) |
| { |
| const SwFmtAnchor& rAnchor = |
| static_cast<const SwFlyFrm*>(&rFrm)->GetFmt()->GetAnchor(); |
| if ((FLY_AT_PARA == rAnchor.GetAnchorId()) || |
| (FLY_AT_CHAR == rAnchor.GetAnchorId()) || |
| (FLY_AT_PAGE == rAnchor.GetAnchorId())) |
| { |
| pKeyFrm = static_cast<const SwFlyFrm&>(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 ); |
| ASSERT( bSuccess, "Failed to reopen tag" ) |
| |
| #ifdef DBG_UTIL |
| 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; |
| ASSERT( bSuccess, "Failed to restore reopened tag" ) |
| |
| #ifdef DBG_UTIL |
| 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; |
| |
| #ifdef DBG_UTIL |
| aStructStack.push_back( static_cast<sal_uInt16>(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<const SwTxtFrm&>(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<const SwPageFrm&>(rFrm).GetPrev() ) || |
| ( rFrm.IsFlowFrm() && !SwFlowFrm::CastFlowFrm(&rFrm)->IsFollow() && SwFlowFrm::CastFlowFrm(&rFrm)->HasFollow() ) || |
| ( rFrm.IsTxtFrm() && rFrm.GetDrawObjs() ) || |
| ( rFrm.IsRowFrm() && rFrm.IsInSplitTableRow() ) || |
| ( rFrm.IsCellFrm() && const_cast<SwFrm&>(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(); |
| |
| #ifdef DBG_UTIL |
| 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 ) |
| { |
| ASSERT( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" ) |
| const SvxLRSpaceItem &rSpace = |
| static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode()->GetSwAttrSet().GetLRSpace(); |
| nVal = rSpace.GetTxtFirstLineOfst(); |
| if ( 0 != nVal ) |
| mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::TextIndent, nVal ); |
| } |
| |
| if ( bTextAlign ) |
| { |
| ASSERT( pFrm->IsTxtFrm(), "Frame type <-> tag attribute mismatch" ) |
| const SwAttrSet& aSet = static_cast<const SwTxtFrm*>(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 ) |
| { |
| ASSERT( pFrm->IsFlyFrm(), "Frame type <-> tag attribute mismatch" ) |
| const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pFrm); |
| if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() ) |
| { |
| const SwNoTxtFrm* pNoTxtFrm = static_cast<const SwNoTxtFrm*>(pFly->Lower()); |
| const SwNoTxtNode* pNoTxtNode = static_cast<const SwNoTxtNode*>(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<const SwTabFrm*>(pFrm)->IsFollow() && |
| !static_cast<const SwTabFrm*>(pFrm)->HasFollow() ) ) |
| mpPDFExtOutDevData->SetStructureBoundingBox( pFrm->Frm().SVRect() ); |
| } |
| |
| if ( bRowSpan ) |
| { |
| const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(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 ); |
| |
| ASSERT( 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() |
| { |
| ASSERT( mpNumInfo, "List without mpNumInfo?" ) |
| if ( !mpNumInfo ) |
| return; |
| |
| const SwFrm& rFrm = mpNumInfo->mrFrm; |
| ASSERT( rFrm.IsTxtFrm(), "numbered only for text frames" ) |
| const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(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 ); |
| |
| #ifdef DBG_UTIL |
| 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<const SwSectionFrm*>(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<const SwTxtFrm*>(pFrm)->GetTxtNode(); |
| |
| const SwFmt* pTxtFmt = pTxtNd->GetFmtColl(); |
| const SwFmt* pParentTxtFmt = pTxtFmt->DerivedFrom(); |
| |
| 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 |
| // <stylename> with role = P |
| nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Paragraph); |
| aPDFType = sStyleName; |
| |
| // |
| // Quotations: BlockQuote |
| // |
| if ( sStyleName == aQuotations ) |
| { |
| nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::BlockQuote); |
| aPDFType = aBlockQuoteString; |
| } |
| |
| // |
| // Caption: Caption |
| // |
| else if ( sStyleName == aCaption) |
| { |
| nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Caption); |
| aPDFType = aCaptionString; |
| } |
| |
| // |
| // Caption: Caption |
| // |
| else if ( sParentStyleName == aCaption) |
| { |
| nPDFType = static_cast<sal_uInt16>(vcl::PDFWriter::Caption); |
| aPDFType = sStyleName.Append(aCaptionString); |
| } |
| |
| // |
| // Heading: H |
| // |
| else if ( sStyleName == aHeading ) |
| { |
| nPDFType = static_cast<sal_uInt16>(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<sal_uInt16>(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<const SwSectionFrm*>(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<const SwTabFrm*>(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<const SwRowFrm*>(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<const SwRowFrm*>(pRowFrm->GetNext()); |
| } |
| pMasterFrm = static_cast<const SwTabFrm*>(pMasterFrm->GetFollow()); |
| } |
| } |
| } |
| |
| break; |
| |
| /* |
| * TABLE ELEMENTS |
| */ |
| |
| case FRM_ROW : |
| // |
| // RowFrm: TR |
| // |
| if ( !static_cast<const SwRowFrm*>(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<const SwCellFrm*>(pFrm)->FindTabFrm(); |
| if ( pTable->IsInHeadline( *pFrm ) || lcl_IsHeadlineCell( *static_cast<const SwCellFrm*>(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<const SwFlyFrm*>(pFrm); |
| if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() ) |
| { |
| const SwNoTxtFrm* pNoTxtFrm = static_cast<const SwNoTxtFrm*>(pFly->Lower()); |
| SwOLENode* pOLENd = const_cast<SwOLENode*>(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<vcl::PDFWriter::StructElement>(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<SwTxtAttr *> 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<const SwFldPortion*>(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->GetFmtFld().GetField(); |
| 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<vcl::PDFWriter::StructElement>(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(); |
| |
| #ifdef DBG_UTIL |
| 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<const SvxLanguageItem*>(&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<SwFmtFld,SwFieldType> aIter( *pType ); |
| for( SwFmtFld* pFirst = aIter.First(); pFirst; ) |
| { |
| if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() ) |
| { |
| const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode(); |
| ASSERT( 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->GetField(); |
| 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->GetContent(); |
| |
| // 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 ]; |
| ASSERT( 0 != p, "Enhanced pdf export - SwGetINetAttr is missing" ) |
| |
| const SwTxtNode* pTNd = p->rINetAttr.GetpTxtNode(); |
| ASSERT( 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 ); |
| ASSERT( 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 ) |
| { |
| // --> FME 2005-05-09 #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 ); |
| |
| // --> FME 2005-05-09 #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<const SwFmtURL*>(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 ); |
| |
| // --> FME 2005-05-09 #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<SwFmtFld,SwFieldType> aIter( *pType ); |
| for( SwFmtFld* pFirst = aIter.First(); pFirst; ) |
| { |
| if( pFirst->GetTxtFld() && pFirst->IsFldInDoc() ) |
| { |
| const SwTxtNode* pTNd = (SwTxtNode*)pFirst->GetTxtFld()->GetpTxtNode(); |
| ASSERT( 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 ); |
| ASSERT( aTmp.Count() > 0, "Enhanced pdf export - rectangles are missing" ) |
| |
| mrSh.SwCrsrShell::ClearMark(); |
| |
| // Destination Rectangle |
| const SwGetRefField* pField = (SwGetRefField*)pFirst->GetField(); |
| 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 ); |
| |
| // --> FME 2005-05-09 #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 ); |
| |
| // --> FME 2005-05-09 #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<SwTxtNode&>(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<const SwTxtNode&>(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 ); |
| ASSERT( 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<sal_uInt16>(mrSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount()); |
| for ( sal_uInt16 i = 0; i < nOutlineCount; ++i ) |
| { |
| // Check if outline is hidden |
| const SwTxtNode* pTNd = mrSh.GetNodes().GetOutLineNds()[ i ]->GetTxtNode(); |
| ASSERT( 0 != pTNd, "Enhanced pdf export - text node is missing" ) |
| |
| if ( pTNd->IsHidden() || |
| // --> FME 2005-01-10 #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<const SwPageFrm*>(pRootFrm->Lower()); |
| |
| for ( sal_Int32 nPageIndex = 0; |
| nPageIndex <= nPageNumOfRect && pCurrPage; |
| ++nPageIndex ) |
| { |
| if ( ( !pPageRange || pPageRange->IsSelected( nPageIndex + 1 ) ) && |
| ( !mbSkipEmptyPages || !pCurrPage->IsEmptyPage() ) ) |
| ++nOutputPageNum; |
| |
| pCurrPage = static_cast<const SwPageFrm*>(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<SwTxtFrm,SwTxtNode> 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 ); |
| } |
| } |
| } |
| } |
| |