summaryrefslogtreecommitdiff
path: root/sw/source/core/text/EnhancedPDFExportHelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/EnhancedPDFExportHelper.cxx')
-rw-r--r--sw/source/core/text/EnhancedPDFExportHelper.cxx2209
1 files changed, 2209 insertions, 0 deletions
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx
new file mode 100644
index 000000000000..350bc4dea8e9
--- /dev/null
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -0,0 +1,2209 @@
+/*************************************************************************
+ *
+ * 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
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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 );
+ 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->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<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->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 ];
+ 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->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 );
+
+ // --> 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 );
+ }
+ }
+ }
+}
+