summaryrefslogtreecommitdiff
path: root/sw/source/core/text
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text')
-rw-r--r--sw/source/core/text/EnhancedPDFExportHelper.cxx2217
-rw-r--r--sw/source/core/text/SwGrammarMarkUp.cxx181
-rw-r--r--sw/source/core/text/atrhndl.hxx179
-rw-r--r--sw/source/core/text/atrstck.cxx956
-rw-r--r--sw/source/core/text/blink.cxx198
-rw-r--r--sw/source/core/text/frmcrsr.cxx1744
-rw-r--r--sw/source/core/text/frmform.cxx2173
-rw-r--r--sw/source/core/text/frminf.cxx377
-rw-r--r--sw/source/core/text/frmpaint.cxx749
-rw-r--r--sw/source/core/text/guess.cxx554
-rw-r--r--sw/source/core/text/guess.hxx73
-rw-r--r--sw/source/core/text/inftxt.cxx1977
-rw-r--r--sw/source/core/text/inftxt.hxx905
-rw-r--r--sw/source/core/text/itradj.cxx919
-rw-r--r--sw/source/core/text/itratr.cxx1078
-rw-r--r--sw/source/core/text/itratr.hxx131
-rw-r--r--sw/source/core/text/itrcrsr.cxx1856
-rw-r--r--sw/source/core/text/itrform2.cxx2127
-rw-r--r--sw/source/core/text/itrform2.hxx214
-rw-r--r--sw/source/core/text/itrpaint.cxx718
-rw-r--r--sw/source/core/text/itrpaint.hxx69
-rw-r--r--sw/source/core/text/itrtxt.cxx523
-rw-r--r--sw/source/core/text/itrtxt.hxx340
-rw-r--r--sw/source/core/text/makefile.mk119
-rw-r--r--sw/source/core/text/noteurl.cxx87
-rw-r--r--sw/source/core/text/pordrop.hxx119
-rw-r--r--sw/source/core/text/porexp.cxx312
-rw-r--r--sw/source/core/text/porexp.hxx108
-rw-r--r--sw/source/core/text/porfld.cxx1389
-rw-r--r--sw/source/core/text/porfld.hxx274
-rw-r--r--sw/source/core/text/porfly.cxx454
-rw-r--r--sw/source/core/text/porfly.hxx108
-rw-r--r--sw/source/core/text/porftn.hxx130
-rw-r--r--sw/source/core/text/porglue.cxx318
-rw-r--r--sw/source/core/text/porglue.hxx134
-rw-r--r--sw/source/core/text/porhyph.hxx119
-rw-r--r--sw/source/core/text/porlay.cxx2465
-rw-r--r--sw/source/core/text/porlay.hxx427
-rw-r--r--sw/source/core/text/porlin.cxx426
-rw-r--r--sw/source/core/text/porlin.hxx251
-rw-r--r--sw/source/core/text/pormulti.cxx2415
-rw-r--r--sw/source/core/text/pormulti.hxx268
-rw-r--r--sw/source/core/text/porref.cxx115
-rw-r--r--sw/source/core/text/porref.hxx73
-rw-r--r--sw/source/core/text/porrst.cxx579
-rw-r--r--sw/source/core/text/porrst.hxx187
-rw-r--r--sw/source/core/text/portab.hxx157
-rw-r--r--sw/source/core/text/portox.cxx115
-rw-r--r--sw/source/core/text/portox.hxx75
-rw-r--r--sw/source/core/text/portxt.cxx881
-rw-r--r--sw/source/core/text/portxt.hxx117
-rw-r--r--sw/source/core/text/possiz.hxx84
-rw-r--r--sw/source/core/text/redlnitr.cxx505
-rw-r--r--sw/source/core/text/redlnitr.hxx123
-rw-r--r--sw/source/core/text/txtcache.cxx241
-rw-r--r--sw/source/core/text/txtcache.hxx76
-rw-r--r--sw/source/core/text/txtcfg.hxx54
-rw-r--r--sw/source/core/text/txtdrop.cxx1105
-rw-r--r--sw/source/core/text/txtfld.cxx549
-rw-r--r--sw/source/core/text/txtfly.cxx2430
-rw-r--r--sw/source/core/text/txtfly.hxx259
-rw-r--r--sw/source/core/text/txtfrm.cxx2753
-rw-r--r--sw/source/core/text/txtftn.cxx1699
-rw-r--r--sw/source/core/text/txthyph.cxx695
-rw-r--r--sw/source/core/text/txtinit.cxx101
-rw-r--r--sw/source/core/text/txtio.cxx949
-rw-r--r--sw/source/core/text/txtpaint.cxx137
-rw-r--r--sw/source/core/text/txtpaint.hxx191
-rw-r--r--sw/source/core/text/txttab.cxx663
-rw-r--r--sw/source/core/text/widorp.cxx566
-rw-r--r--sw/source/core/text/widorp.hxx95
-rw-r--r--sw/source/core/text/wrong.cxx644
72 files changed, 46399 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..09c13b8fb250
--- /dev/null
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -0,0 +1,2217 @@
+/*************************************************************************
+ *
+ * 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 <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< USHORT > 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
+ */
+
+ USHORT nElement;
+ std::vector< USHORT >::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<USHORT>(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;
+
+ USHORT 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<USHORT>(vcl::PDFWriter::Paragraph);
+ aPDFType = sStyleName;
+
+ //
+ // Quotations: BlockQuote
+ //
+ if ( sStyleName == aQuotations )
+ {
+ nPDFType = static_cast<USHORT>(vcl::PDFWriter::BlockQuote);
+ aPDFType = aBlockQuoteString;
+ }
+
+ //
+ // Caption: Caption
+ //
+ else if ( sStyleName == aCaption)
+ {
+ nPDFType = static_cast<USHORT>(vcl::PDFWriter::Caption);
+ aPDFType = aCaptionString;
+ }
+
+ //
+ // Caption: Caption
+ //
+ else if ( sParentStyleName == aCaption)
+ {
+ nPDFType = static_cast<USHORT>(vcl::PDFWriter::Caption);
+ aPDFType = sStyleName.Append(aCaptionString);
+ }
+
+ //
+ // Heading: H
+ //
+ else if ( sStyleName == aHeading )
+ {
+ nPDFType = static_cast<USHORT>(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<USHORT>(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;
+
+ USHORT 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 USHORT 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 BYTE nScript = (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
+ USHORT 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 BOOL bOldLockView = mrSh.IsViewLocked();
+ mrSh.LockView( TRUE );
+
+ if ( !mbEditEngineOnly )
+ {
+ //
+ // POSTITS
+ //
+ if ( pPDFExtOutDevData->GetIsExportNotes() )
+ {
+ SwFieldType* pType = mrSh.GetFldType( RES_POSTITFLD, aEmptyStr );
+ SwClientIter aIter( *pType );
+ const SwClient * pFirst = aIter.GoStart();
+ while( pFirst )
+ {
+ if( ((SwFmtFld*)pFirst)->GetTxtFld() &&
+ ((SwFmtFld*)pFirst)->IsFldInDoc())
+ {
+ const SwTxtNode* pTNd =
+ (SwTxtNode*)((SwFmtFld*)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( *(SwFmtFld*)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*)((SwFmtFld*)pFirst)->GetFld();
+ SvNumberFormatter* pNumFormatter = pDoc->GetNumberFormatter();
+ const Date aDateDiff( pField->GetDate() -
+ *pNumFormatter->GetNullDate() );
+ const 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++;
+ 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 USHORT nNumOfRects = aTmp.Count();
+ for ( USHORT 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, 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 );
+ SwClientIter aIter( *pType );
+ const SwClient * pFirst = aIter.GoStart();
+ while( pFirst )
+ {
+ if( ((SwFmtFld*)pFirst)->GetTxtFld() &&
+ ((SwFmtFld*)pFirst)->IsFldInDoc())
+ {
+ const SwTxtNode* pTNd =
+ (SwTxtNode*)((SwFmtFld*)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( *(SwFmtFld*)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*)((SwFmtFld*)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 USHORT nNumOfRects = aTmp.Count();
+ for ( USHORT 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++;
+ mrSh.SwCrsrShell::ClearMark();
+ }
+
+ //
+ // FOOTNOTES
+ //
+ const USHORT nFtnCount = pDoc->GetFtnIdxs().Count();
+ for ( USHORT 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 )
+ {
+ // Destination Export
+ const sal_Int32 nDestId =
+ pPDFExtOutDevData->CreateDest( rDestRect.SVRect(), nDestPageNum );
+
+ // Connect Link and Destination:
+ pPDFExtOutDevData->SetLinkDest( aIBeg->nLinkId, nDestId );
+ }
+ }
+ else
+ pPDFExtOutDevData->SetLinkURL( aIBeg->nLinkId, aBookmarkName );
+
+ aIBeg++;
+ }
+ rBookmarks.clear();
+ }
+
+ // Restore view, cursor, and outdev:
+ mrSh.LockView( bOldLockView );
+ mrSh.SwCrsrShell::Pop( 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();
+
+ SwClientIter aClientIter( const_cast<SwTxtNode&>(rTNd) );
+ SwClient* pLast = aClientIter.GoStart();
+
+ while( pLast )
+ {
+ if ( pLast->ISA( SwTxtFrm ) )
+ {
+ // Add offset to current page:
+ SwTxtFrm* pTmpFrm = static_cast<SwTxtFrm*>(pLast);
+ 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 );
+ }
+ }
+ }
+
+ pLast = ++aClientIter;
+ }
+}
+
diff --git a/sw/source/core/text/SwGrammarMarkUp.cxx b/sw/source/core/text/SwGrammarMarkUp.cxx
new file mode 100644
index 000000000000..535e619e2708
--- /dev/null
+++ b/sw/source/core/text/SwGrammarMarkUp.cxx
@@ -0,0 +1,181 @@
+/*************************************************************************
+ *
+ * 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 "SwGrammarMarkUp.hxx"
+
+SwGrammarMarkUp::~SwGrammarMarkUp()
+{
+}
+
+SwWrongList* SwGrammarMarkUp::Clone()
+{
+ SwWrongList* pClone = new SwGrammarMarkUp();
+ pClone->CopyFrom( *this );
+ return pClone;
+}
+
+void SwGrammarMarkUp::CopyFrom( const SwWrongList& rCopy )
+{
+ maSentence = ((const SwGrammarMarkUp&)rCopy).maSentence;
+ SwWrongList::CopyFrom( rCopy );
+}
+
+
+void SwGrammarMarkUp::MoveGrammar( xub_StrLen nPos, long nDiff )
+{
+ Move( nPos, nDiff );
+ if( !maSentence.size() )
+ return;
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ while( pIter != maSentence.end() && *pIter < nPos )
+ ++pIter;
+ xub_StrLen nEnd = nDiff < 0 ? xub_StrLen(nPos - nDiff) : nPos;
+ while( pIter != maSentence.end() )
+ {
+ if( *pIter >= nEnd )
+ *pIter = xub_StrLen( *pIter + nDiff );
+ else
+ *pIter = nPos;
+ ++pIter;
+ }
+}
+
+SwGrammarMarkUp* SwGrammarMarkUp::SplitGrammarList( xub_StrLen nSplitPos )
+{
+ SwGrammarMarkUp* pNew = (SwGrammarMarkUp*)SplitList( nSplitPos );
+ if( !maSentence.size() )
+ return pNew;
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ while( pIter != maSentence.end() && *pIter < nSplitPos )
+ ++pIter;
+ if( pIter != maSentence.begin() )
+ {
+ if( !pNew ) {
+ pNew = new SwGrammarMarkUp();
+ pNew->SetInvalid( 0, STRING_LEN );
+ }
+ pNew->maSentence.insert( pNew->maSentence.begin(), maSentence.begin(), pIter );
+ maSentence.erase( maSentence.begin(), pIter );
+ }
+ return pNew;
+}
+
+void SwGrammarMarkUp::JoinGrammarList( SwGrammarMarkUp* pNext, xub_StrLen nInsertPos )
+{
+ JoinList( pNext, nInsertPos );
+ if (pNext)
+ {
+ if( !pNext->maSentence.size() )
+ return;
+ std::vector< xub_StrLen >::iterator pIter = pNext->maSentence.begin();
+ while( pIter != pNext->maSentence.end() )
+ {
+ *pIter = *pIter + nInsertPos;
+ ++pIter;
+ }
+ maSentence.insert( maSentence.end(), pNext->maSentence.begin(), pNext->maSentence.end() );
+ }
+}
+
+void SwGrammarMarkUp::ClearGrammarList( xub_StrLen nSentenceEnd )
+{
+ if( STRING_LEN == nSentenceEnd ) {
+ ClearList();
+ maSentence.clear();
+ Validate();
+ } else if( GetBeginInv() <= nSentenceEnd ) {
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ xub_StrLen nStart = 0;
+ while( pIter != maSentence.end() && *pIter < GetBeginInv() )
+ {
+ nStart = *pIter;
+ ++pIter;
+ }
+ std::vector< xub_StrLen >::iterator pLast = pIter;
+ while( pLast != maSentence.end() && *pLast <= nSentenceEnd )
+ ++pLast;
+ maSentence.erase( pIter, pLast );
+ RemoveEntry( nStart, nSentenceEnd );
+ SetInvalid( nSentenceEnd + 1, STRING_LEN );
+ }
+}
+
+void SwGrammarMarkUp::setSentence( xub_StrLen nStart )
+{
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ while( pIter != maSentence.end() && *pIter < nStart )
+ ++pIter;
+ if( pIter == maSentence.end() || *pIter > nStart )
+ maSentence.insert( pIter, nStart );
+}
+
+void SwGrammarMarkUp::removeSentence(xub_StrLen nStart, xub_StrLen nLength )
+{
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ while( pIter != maSentence.end() && *pIter < nStart )
+ ++pIter;
+ if( nLength == STRING_LEN )
+ nStart = STRING_LEN;
+ else
+ nStart += nLength;
+ std::vector< xub_StrLen >::iterator pLast = pIter;
+ while( pLast != maSentence.end() && *pLast < nStart )
+ ++pLast;
+ maSentence.erase( pIter, pLast );
+}
+
+xub_StrLen SwGrammarMarkUp::getSentenceStart( xub_StrLen nPos )
+{
+ if( !maSentence.size() )
+ return 0;
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ while( pIter != maSentence.end() && *pIter < nPos )
+ ++pIter;
+ if( pIter != maSentence.begin() )
+ --pIter;
+ xub_StrLen nRet = 0;
+ if( pIter != maSentence.end() && *pIter < nPos )
+ nRet = *pIter;
+ return nRet;
+}
+
+xub_StrLen SwGrammarMarkUp::getSentenceEnd( xub_StrLen nPos )
+{
+ if( !maSentence.size() )
+ return STRING_LEN;
+ std::vector< xub_StrLen >::iterator pIter = maSentence.begin();
+ while( pIter != maSentence.end() && *pIter <= nPos )
+ ++pIter;
+ xub_StrLen nRet = STRING_LEN;
+ if( pIter != maSentence.end() )
+ nRet = *pIter;
+ return nRet;
+}
+
diff --git a/sw/source/core/text/atrhndl.hxx b/sw/source/core/text/atrhndl.hxx
new file mode 100644
index 000000000000..62df7e0499db
--- /dev/null
+++ b/sw/source/core/text/atrhndl.hxx
@@ -0,0 +1,179 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _ATRHNDL_HXX
+#define _ATRHNDL_HXX
+
+#define INITIAL_NUM_ATTR 3
+#define NUM_ATTRIBUTE_STACKS 40
+
+#include <txatbase.hxx>
+#include <swfntcch.hxx>
+
+class SwAttrSet;
+class IDocumentSettingAccess;
+class ViewShell;
+class SfxPoolItem;
+extern const BYTE StackPos[];
+
+/*************************************************************************
+ * class SwAttrHandler
+ *
+ * Used by Attribute Iterators to organize attributes on stacks to
+ * find the valid attribute in each category
+ *************************************************************************/
+
+class SwAttrHandler
+{
+private:
+
+ /*************************************************************************
+ * class SwAttrStack
+ *
+ * Container for SwTxtAttr Objects
+ *************************************************************************/
+
+ class SwAttrStack
+ {
+ private:
+ SwTxtAttr* pInitialArray[ INITIAL_NUM_ATTR ];
+ SwTxtAttr** pArray;
+ USHORT nCount; // number of elements on stack
+ USHORT nSize; // number of positions in Array
+
+ public:
+ // Ctor, Dtor
+ inline SwAttrStack();
+ inline ~SwAttrStack() {
+ if ( nSize > INITIAL_NUM_ATTR ) delete [] pArray; }
+
+ // reset stack
+ inline void Reset() { nCount = 0; };
+
+ // insert on top
+ inline void Push( const SwTxtAttr& rAttr ) { Insert( rAttr, nCount ); };
+ // insert at specified position, take care for not inserting behind
+ // the value returned by Count()
+ void Insert( const SwTxtAttr& rAttr, const USHORT nPos );
+
+ // remove specified attribute
+ void Remove( const SwTxtAttr& rAttr );
+
+ // get attribute from top if exists, otherwise 0
+ const SwTxtAttr* Top() const;
+
+ // number of elements on stack
+ inline USHORT Count() const { return nCount; };
+
+ // returns position of rAttr on Stack if found, otherwise USHRT_MAX
+ // can be used for Remove of an attribute
+ USHORT Pos( const SwTxtAttr& rAttr ) const;
+ };
+
+ SwAttrStack aAttrStack[ NUM_ATTRIBUTE_STACKS ]; // stack collection
+ const SfxPoolItem* pDefaultArray[ NUM_DEFAULT_VALUES ];
+ const IDocumentSettingAccess* mpIDocumentSettingAccess;
+ const ViewShell* mpShell;
+
+ // This is the base font for the paragraph. It is stored in order to have
+ // a template, if we have to restart the attribute evaluation
+ SwFont* pFnt;
+
+ sal_Bool bVertLayout;
+
+ // change font according to pool item
+ void FontChg(const SfxPoolItem& rItem, SwFont& rFnt, sal_Bool bPush );
+
+ // push attribute to specified stack, returns true, if attribute has
+ // been pushed on top of stack (important for stacks containing different
+ // attributes with different priority and redlining)
+ sal_Bool Push( const SwTxtAttr& rAttr, const SfxPoolItem& rItem );
+
+ // apply top attribute on stack to font
+ void ActivateTop( SwFont& rFnt, USHORT nStackPos );
+
+public:
+ // Ctor
+ SwAttrHandler();
+ ~SwAttrHandler();
+
+ // set default attributes to values in rAttrSet or from cache
+ void Init( const SwAttrSet& rAttrSet,
+ const IDocumentSettingAccess& rIDocumentSettingAccess,
+ const ViewShell* pShell );
+ void Init( const SfxPoolItem** pPoolItem, const SwAttrSet* pAttrSet,
+ const IDocumentSettingAccess& rIDocumentSettingAccess,
+ const ViewShell* pShell, SwFont& rFnt,
+ sal_Bool bVertLayout );
+
+ // remove everything from internal stacks, keep default data
+ void Reset( );
+
+ // insert specified attribute and change font
+ void PushAndChg( const SwTxtAttr& rAttr, SwFont& rFnt );
+
+ // remove specified attribute and reset font
+ void PopAndChg( const SwTxtAttr& rAttr, SwFont& rFnt );
+ void Pop( const SwTxtAttr& rAttr );
+
+ // apply script dependent attributes
+// void ChangeScript( SwFont& rFnt, const BYTE nScr );
+
+ // returns the default value for stack nStack
+ inline const SfxPoolItem& GetDefault( const USHORT nAttribID ) const;
+ // do not call these if you only used the small init function
+ inline void ResetFont( SwFont& rFnt ) const;
+ inline const SwFont* GetFont() const;
+
+ void GetDefaultAscentAndHeight(ViewShell* pShell,
+ OutputDevice& rOut,
+ USHORT& nAscent,
+ USHORT& nHeight) const;
+};
+
+inline const SfxPoolItem& SwAttrHandler::GetDefault( const USHORT nAttribID ) const
+{
+ ASSERT( nAttribID < RES_TXTATR_END,
+ "this attrib does not ex."
+ );
+ ASSERT( pDefaultArray[ StackPos[ nAttribID ] ], "array not initialized" );
+ return *pDefaultArray[ StackPos[ nAttribID ] ];
+}
+
+inline void SwAttrHandler::ResetFont( SwFont& rFnt ) const
+{
+ ASSERT( pFnt, "ResetFont without a font" );
+ if ( pFnt )
+ rFnt = *pFnt;
+};
+
+inline const SwFont* SwAttrHandler::GetFont() const
+{
+ return pFnt;
+};
+
+#endif
diff --git a/sw/source/core/text/atrstck.cxx b/sw/source/core/text/atrstck.cxx
new file mode 100644
index 000000000000..e4518a26eb0d
--- /dev/null
+++ b/sw/source/core/text/atrstck.cxx
@@ -0,0 +1,956 @@
+/*************************************************************************
+ *
+ * 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 <errhdl.hxx> // ASSERT
+#include <atrhndl.hxx>
+#include <svl/itemiter.hxx>
+#include <vcl/outdev.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/cntritem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/akrnitem.hxx>
+#include <editeng/blnkitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <editeng/emphitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/twolinesitem.hxx>
+#include <editeng/charhiddenitem.hxx>
+#include <viewopt.hxx>
+#include <charfmt.hxx>
+#include <fchrfmt.hxx>
+#include <fmtautofmt.hxx>
+#include <editeng/brshitem.hxx>
+#include <fmtinfmt.hxx>
+#include <txtinet.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <viewsh.hxx> // ViewShell
+#include <viewopt.hxx> // SwViewOptions
+
+#define STACK_INCREMENT 4
+
+/*************************************************************************
+ * Attribute to Stack Mapping
+ *
+ * Attributes applied to a text are pushed on different stacks. For each
+ * stack, the top most attribute on the stack is valid. Because some
+ * kinds of attributes have to be pushed to the same stacks we map their
+ * ids to stack ids
+ * Attention: The first NUM_DEFAULT_VALUES ( defined in swfntcch.hxx == 35 )
+ * are stored in the defaultitem-cache, if you add one, you have to increase
+ * NUM_DEFAULT_VALUES.
+ * Also adjust NUM_ATTRIBUTE_STACKS in atrhndl.hxx.
+ *************************************************************************/
+
+const BYTE StackPos[ static_cast<USHORT>(RES_TXTATR_WITHEND_END) -
+ static_cast<USHORT>(RES_CHRATR_BEGIN) + 1 ] =
+{
+ 0, // // 0
+ 1, // RES_CHRATR_CASEMAP = RES_CHRATR_BEGIN // 1
+ 0, // RES_CHRATR_CHARSETCOLOR, // 2
+ 2, // RES_CHRATR_COLOR, // 3
+ 3, // RES_CHRATR_CONTOUR, // 4
+ 4, // RES_CHRATR_CROSSEDOUT, // 5
+ 5, // RES_CHRATR_ESCAPEMENT, // 6
+ 6, // RES_CHRATR_FONT, // 7
+ 7, // RES_CHRATR_FONTSIZE, // 8
+ 8, // RES_CHRATR_KERNING, // 9
+ 9, // RES_CHRATR_LANGUAGE, // 10
+ 10, // RES_CHRATR_POSTURE, // 11
+ 0, // RES_CHRATR_PROPORTIONALFONTSIZE, // 12
+ 11, // RES_CHRATR_SHADOWED, // 13
+ 12, // RES_CHRATR_UNDERLINE, // 14
+ 13, // RES_CHRATR_WEIGHT, // 15
+ 14, // RES_CHRATR_WORDLINEMODE, // 16
+ 15, // RES_CHRATR_AUTOKERN, // 17
+ 16, // RES_CHRATR_BLINK, // 18
+ 17, // RES_CHRATR_NOHYPHEN, // 19
+ 0, // RES_CHRATR_NOLINEBREAK, // 20
+ 18, // RES_CHRATR_BACKGROUND, // 21
+ 19, // RES_CHRATR_CJK_FONT, // 22
+ 20, // RES_CHRATR_CJK_FONTSIZE, // 23
+ 21, // RES_CHRATR_CJK_LANGUAGE, // 24
+ 22, // RES_CHRATR_CJK_POSTURE, // 25
+ 23, // RES_CHRATR_CJK_WEIGHT, // 26
+ 24, // RES_CHRATR_CTL_FONT, // 27
+ 25, // RES_CHRATR_CTL_FONTSIZE, // 28
+ 26, // RES_CHRATR_CTL_LANGUAGE, // 29
+ 27, // RES_CHRATR_CTL_POSTURE, // 30
+ 28, // RES_CHRATR_CTL_WEIGHT, // 31
+ 29, // RES_CHRATR_ROTATE, // 32
+ 30, // RES_CHRATR_EMPHASIS_MARK, // 33
+ 31, // RES_CHRATR_TWO_LINES, // 34
+ 32, // RES_CHRATR_SCALEW, // 35
+ 33, // RES_CHRATR_RELIEF, // 36
+ 34, // RES_CHRATR_HIDDEN, // 37
+ 35, // RES_CHRATR_OVERLINE, // 38
+ 0, // RES_CHRATR_DUMMY1, // 39
+ 0, // RES_CHRATR_DUMMY2, // 40
+ 36, // RES_TXTATR_REFMARK, // 41
+ 37, // RES_TXTATR_TOXMARK, // 42
+ 38, // RES_TXTATR_META, // 43
+ 38, // RES_TXTATR_METAFIELD, // 44
+ 0, // RES_TXTATR_AUTOFMT, // 45
+ 0, // RES_TXTATR_INETFMT // 46
+ 0, // RES_TXTATR_CHARFMT, // 47
+ 39, // RES_TXTATR_CJK_RUBY, // 48
+ 0, // RES_TXTATR_UNKNOWN_CONTAINER, // 49
+ 0, // RES_TXTATR_DUMMY5 // 50
+};
+
+/*************************************************************************
+ * CharFmt::GetItem
+ * returns the item set associated with an character/inet/auto style
+ *************************************************************************/
+
+namespace CharFmt
+{
+
+const SfxItemSet* GetItemSet( const SfxPoolItem& rAttr )
+{
+ const SfxItemSet* pSet = 0;
+
+ if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
+ {
+ pSet = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle().get();
+ }
+ else
+ {
+ // aus der Vorlage die Attribute holen:
+ SwCharFmt* pFmt = RES_TXTATR_INETFMT == rAttr.Which() ?
+ ((SwFmtINetFmt&)rAttr).GetTxtINetFmt()->GetCharFmt() :
+ ((SwFmtCharFmt&)rAttr).GetCharFmt();
+ if( pFmt )
+ {
+ pSet = &pFmt->GetAttrSet();
+ }
+ }
+
+ return pSet;
+}
+
+/*************************************************************************
+ * CharFmt::GetItem
+ * extracts pool item of type nWhich from rAttr
+ *************************************************************************/
+
+const SfxPoolItem* GetItem( const SwTxtAttr& rAttr, USHORT nWhich )
+{
+ if ( RES_TXTATR_INETFMT == rAttr.Which() ||
+ RES_TXTATR_CHARFMT == rAttr.Which() ||
+ RES_TXTATR_AUTOFMT == rAttr.Which() )
+ {
+ const SfxItemSet* pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
+ if ( !pSet ) return 0;
+
+ bool bInParent = RES_TXTATR_AUTOFMT != rAttr.Which();
+ const SfxPoolItem* pItem;
+ BOOL bRet = SFX_ITEM_SET == pSet->GetItemState( nWhich, bInParent, &pItem );
+
+ return bRet ? pItem : 0;
+ }
+
+ return ( nWhich == rAttr.Which() ) ? &rAttr.GetAttr() : 0;
+}
+
+/*************************************************************************
+ * CharFmt::IsItemIncluded
+ * checks if item is included in character/inet/auto style
+ *************************************************************************/
+
+BOOL IsItemIncluded( const USHORT nWhich, const SwTxtAttr *pAttr )
+{
+ BOOL bRet = FALSE;
+
+ const SfxItemSet* pItemSet = CharFmt::GetItemSet( pAttr->GetAttr() );
+ if ( pItemSet )
+ bRet = SFX_ITEM_SET == pItemSet->GetItemState( nWhich, TRUE );
+
+ return bRet;
+}
+
+}
+
+/*************************************************************************
+ * lcl_ChgHyperLinkColor
+ * The color of hyperlinks is taken from the associated character attribute,
+ * depending on its 'visited' state. There are actually two cases, which
+ * should override the colors from the character attribute:
+ * 1. We never take the 'visited' color during printing/pdf export/preview
+ * 2. The user has choosen to override these colors in the view options
+ *************************************************************************/
+
+bool lcl_ChgHyperLinkColor( const SwTxtAttr& rAttr,
+ const SfxPoolItem& rItem,
+ const ViewShell* pShell,
+ Color* pColor )
+{
+ if ( !pShell ||
+ RES_TXTATR_INETFMT != rAttr.Which() ||
+ RES_CHRATR_COLOR != rItem.Which() )
+ return false;
+
+ // --> FME 2004-09-13 #i15455#
+ // 1. case:
+ // We do not want to show visited links:
+ // (printing, pdf export, page preview)
+ //
+ if ( pShell->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
+ pShell->GetViewOptions()->IsPDFExport() ||
+ pShell->GetViewOptions()->IsPagePreview() )
+ {
+ if ( ((SwTxtINetFmt&)rAttr).IsVisited() )
+ {
+ if ( pColor )
+ {
+ // take color from character format 'unvisited link'
+ SwTxtINetFmt& rInetAttr( const_cast<SwTxtINetFmt&>(
+ static_cast<const SwTxtINetFmt&>(rAttr)) );
+ rInetAttr.SetVisited( false );
+ const SwCharFmt* pTmpFmt = ((SwTxtINetFmt&)rAttr).GetCharFmt();
+ const SfxPoolItem* pItem;
+ pTmpFmt->GetItemState( RES_CHRATR_COLOR, TRUE, &pItem );
+ *pColor = ((SvxColorItem*)pItem)->GetValue();
+ rInetAttr.SetVisited( true );
+ }
+ return true;
+ }
+
+ return false;
+ }
+ // <--
+
+ //
+ // 2. case:
+ // We do not want to apply the color set in the hyperlink
+ // attribute, instead we take the colors from the view options:
+ //
+ if ( pShell->GetWin() &&
+ (
+ (((SwTxtINetFmt&)rAttr).IsVisited() && SwViewOption::IsVisitedLinks()) ||
+ (!((SwTxtINetFmt&)rAttr).IsVisited() && SwViewOption::IsLinks())
+ )
+ )
+ {
+ if ( pColor )
+ {
+ if ( ((SwTxtINetFmt&)rAttr).IsVisited() )
+ {
+ // take color from view option 'visited link color'
+ *pColor = SwViewOption::GetVisitedLinksColor();
+ }
+ else
+ {
+ // take color from view option 'unvisited link color'
+ *pColor = SwViewOption::GetLinksColor();
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/*************************************************************************
+ * SwAttrHandler::SwAttrStack::SwAttrStack()
+ *************************************************************************/
+
+inline SwAttrHandler::SwAttrStack::SwAttrStack()
+ : nCount( 0 ), nSize( INITIAL_NUM_ATTR )
+{
+ pArray = pInitialArray;
+}
+
+/*************************************************************************
+ * SwAttrHandler::SwAttrStack::Insert()
+ *************************************************************************/
+
+void SwAttrHandler::SwAttrStack::Insert( const SwTxtAttr& rAttr, const USHORT nPos )
+{
+ // do we still have enough space?
+ if ( nCount >= nSize )
+ {
+ // we are still in our initial array
+ if ( INITIAL_NUM_ATTR == nSize )
+ {
+ nSize += STACK_INCREMENT;
+ pArray = new SwTxtAttr*[ nSize ];
+ // copy from pInitArray to new Array
+ memcpy( pArray, pInitialArray,
+ INITIAL_NUM_ATTR * sizeof(SwTxtAttr*)
+ );
+ }
+ // we are in new memory
+ else
+ {
+ nSize += STACK_INCREMENT;
+ SwTxtAttr** pTmpArray = new SwTxtAttr*[ nSize ];
+ // copy from pArray to new Array
+ memcpy( pTmpArray, pArray, nCount * sizeof(SwTxtAttr*) );
+ // free old array
+ delete [] pArray;
+ pArray = pTmpArray;
+ }
+ }
+
+ ASSERT( nPos <= nCount, "wrong position for insert operation");
+
+ if ( nPos < nCount )
+ memmove( pArray + nPos + 1, pArray + nPos,
+ ( nCount - nPos ) * sizeof(SwTxtAttr*)
+ );
+ pArray[ nPos ] = (SwTxtAttr*)&rAttr;
+
+ nCount++;
+}
+
+/*************************************************************************
+ * SwAttrHandler::SwAttrStack::Remove()
+ *************************************************************************/
+
+void SwAttrHandler::SwAttrStack::Remove( const SwTxtAttr& rAttr )
+{
+ USHORT nPos = Pos( rAttr );
+ if ( nPos < nCount )
+ {
+ memmove( pArray + nPos, pArray + nPos + 1,
+ ( nCount - 1 - nPos ) * sizeof(SwTxtAttr*)
+ );
+ nCount--;
+ }
+}
+
+/*************************************************************************
+ * SwAttrHandler::SwAttrStack::Top()
+ *************************************************************************/
+
+const SwTxtAttr* SwAttrHandler::SwAttrStack::Top() const
+{
+ return nCount ? pArray[ nCount - 1 ] : 0;
+}
+
+/*************************************************************************
+ * SwAttrHandler::SwAttrStack::Pos()
+ *************************************************************************/
+
+USHORT SwAttrHandler::SwAttrStack::Pos( const SwTxtAttr& rAttr ) const
+{
+ if ( ! nCount )
+ // empty stack
+ return USHRT_MAX;
+
+ for ( USHORT nIdx = nCount; nIdx > 0; )
+ {
+ if ( &rAttr == pArray[ --nIdx ] )
+ return nIdx;
+ }
+
+ // element not found
+ return USHRT_MAX;
+}
+
+/*************************************************************************
+ * SwAttrHandler::SwAttrHandler()
+ *************************************************************************/
+
+SwAttrHandler::SwAttrHandler() : mpShell( 0 ), pFnt( 0 ), bVertLayout( sal_False )
+
+{
+ memset( pDefaultArray, 0, NUM_DEFAULT_VALUES * sizeof(SfxPoolItem*) );
+}
+
+SwAttrHandler::~SwAttrHandler()
+{
+ delete pFnt;
+}
+
+/*************************************************************************
+ * SwAttrHandler::Init()
+ *************************************************************************/
+
+void SwAttrHandler::Init( const SwAttrSet& rAttrSet,
+ const IDocumentSettingAccess& rIDocumentSettingAcces,
+ const ViewShell* pSh )
+{
+ mpIDocumentSettingAccess = &rIDocumentSettingAcces;
+ mpShell = pSh;
+
+ for ( USHORT i = RES_CHRATR_BEGIN; i < RES_CHRATR_END; i++ )
+ pDefaultArray[ StackPos[ i ] ] = &rAttrSet.Get( i, TRUE );
+}
+
+void SwAttrHandler::Init( const SfxPoolItem** pPoolItem, const SwAttrSet* pAS,
+ const IDocumentSettingAccess& rIDocumentSettingAcces,
+ const ViewShell* pSh,
+ SwFont& rFnt, sal_Bool bVL )
+{
+ // initialize default array
+ memcpy( pDefaultArray, pPoolItem,
+ NUM_DEFAULT_VALUES * sizeof(SfxPoolItem*) );
+
+ mpIDocumentSettingAccess = &rIDocumentSettingAcces;
+ mpShell = pSh;
+
+ // do we have to apply additional paragraph attributes?
+ bVertLayout = bVL;
+
+ if ( pAS && pAS->Count() )
+ {
+ SfxItemIter aIter( *pAS );
+ USHORT nWhich;
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ while( TRUE )
+ {
+ nWhich = pItem->Which();
+ if (isCHRATR(nWhich))
+ {
+ pDefaultArray[ StackPos[ nWhich ] ] = pItem;
+ FontChg( *pItem, rFnt, sal_True );
+ }
+
+ if( aIter.IsAtEnd() )
+ break;
+
+ pItem = aIter.NextItem();
+ }
+ }
+
+ // It is possible, that Init is called more than once, e.g., in a
+ // SwTxtFrm::FormatOnceMore situation.
+ delete pFnt;
+ pFnt = new SwFont( rFnt );
+}
+
+void SwAttrHandler::Reset( )
+{
+ for ( USHORT i = 0; i < NUM_ATTRIBUTE_STACKS; i++ )
+ aAttrStack[ i ].Reset();
+}
+
+/*************************************************************************
+ * SwAttrHandler::PushAndChg()
+ *************************************************************************/
+
+void SwAttrHandler::PushAndChg( const SwTxtAttr& rAttr, SwFont& rFnt )
+{
+ // these special attributes in fact represent a collection of attributes
+ // they have to be pushed to each stack they belong to
+ if ( RES_TXTATR_INETFMT == rAttr.Which() ||
+ RES_TXTATR_CHARFMT == rAttr.Which() ||
+ RES_TXTATR_AUTOFMT == rAttr.Which() )
+ {
+ const SfxItemSet* pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
+ if ( !pSet ) return;
+
+ for ( USHORT i = RES_CHRATR_BEGIN; i < RES_CHRATR_END; i++)
+ {
+ const SfxPoolItem* pItem;
+ BOOL bRet = SFX_ITEM_SET == pSet->GetItemState( i, rAttr.Which() != RES_TXTATR_AUTOFMT, &pItem );
+
+ if ( bRet )
+ {
+ // we push rAttr onto the appropriate stack
+ if ( Push( rAttr, *pItem ) )
+ {
+ // we let pItem change rFnt
+ Color aColor;
+ if ( lcl_ChgHyperLinkColor( rAttr, *pItem, mpShell, &aColor ) )
+ {
+ SvxColorItem aItemNext( aColor, RES_CHRATR_COLOR );
+ FontChg( aItemNext, rFnt, sal_True );
+ }
+ else
+ FontChg( *pItem, rFnt, sal_True );
+ }
+ }
+ }
+ }
+ // this is the usual case, we have a basic attribute, push it onto the
+ // stack and change the font
+ else
+ {
+ if ( Push( rAttr, rAttr.GetAttr() ) )
+ // we let pItem change rFnt
+ FontChg( rAttr.GetAttr(), rFnt, sal_True );
+ }
+}
+
+/*************************************************************************
+ * SwAttrHandler::Push()
+ *************************************************************************/
+
+sal_Bool SwAttrHandler::Push( const SwTxtAttr& rAttr, const SfxPoolItem& rItem )
+{
+ ASSERT( rItem.Which() < RES_TXTATR_WITHEND_END,
+ "I do not want this attribute, nWhich >= RES_TXTATR_WITHEND_END" );
+
+ // robust
+ if ( RES_TXTATR_WITHEND_END <= rItem.Which() )
+ return sal_False;
+
+ USHORT nStack = StackPos[ rItem.Which() ];
+
+ // attributes originating from redlining have highest priority
+ // second priority are hyperlink attributes, which have a color replacement
+ const SwTxtAttr* pTopAttr = aAttrStack[ nStack ].Top();
+ if ( !pTopAttr || rAttr.IsPriorityAttr() ||
+ ( !pTopAttr->IsPriorityAttr() &&
+ !lcl_ChgHyperLinkColor( *pTopAttr, rItem, mpShell, 0 ) ) )
+ {
+ aAttrStack[ nStack ].Push( rAttr );
+ return sal_True;
+ }
+
+ USHORT nPos = aAttrStack[ nStack ].Count();
+ ASSERT( nPos, "empty stack?" );
+ aAttrStack[ nStack ].Insert( rAttr, nPos - 1 );
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwAttrHandler::PopAndChg()
+ *************************************************************************/
+
+void SwAttrHandler::PopAndChg( const SwTxtAttr& rAttr, SwFont& rFnt )
+{
+ if ( RES_TXTATR_WITHEND_END <= rAttr.Which() )
+ return; // robust
+
+ // these special attributes in fact represent a collection of attributes
+ // they have to be removed from each stack they belong to
+ if ( RES_TXTATR_INETFMT == rAttr.Which() ||
+ RES_TXTATR_CHARFMT == rAttr.Which() ||
+ RES_TXTATR_AUTOFMT == rAttr.Which() )
+ {
+ const SfxItemSet* pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
+ if ( !pSet ) return;
+
+ for ( USHORT i = RES_CHRATR_BEGIN; i < RES_CHRATR_END; i++)
+ {
+ const SfxPoolItem* pItem;
+ BOOL bRet = SFX_ITEM_SET == pSet->GetItemState( i, RES_TXTATR_AUTOFMT != rAttr.Which(), &pItem );
+ if ( bRet )
+ {
+ // we remove rAttr from the appropriate stack
+ USHORT nStackPos = StackPos[ i ];
+ aAttrStack[ nStackPos ].Remove( rAttr );
+ // reset font according to attribute on top of stack
+ // or default value
+ ActivateTop( rFnt, i );
+ }
+ }
+ }
+ // this is the usual case, we have a basic attribute, remove it from the
+ // stack and reset the font
+ else
+ {
+ aAttrStack[ StackPos[ rAttr.Which() ] ].Remove( rAttr );
+ // reset font according to attribute on top of stack
+ // or default value
+ ActivateTop( rFnt, rAttr.Which() );
+ }
+}
+
+/*************************************************************************
+ * SwAttrHandler::Pop()
+ *
+ * only used during redlining
+ *************************************************************************/
+
+void SwAttrHandler::Pop( const SwTxtAttr& rAttr )
+{
+ ASSERT( rAttr.Which() < RES_TXTATR_WITHEND_END,
+ "I do not have this attribute, nWhich >= RES_TXTATR_WITHEND_END" );
+
+ if ( rAttr.Which() < RES_TXTATR_WITHEND_END )
+ {
+ aAttrStack[ StackPos[ rAttr.Which() ] ].Remove( rAttr );
+ }
+}
+
+/*************************************************************************
+ * SwAttrHandler::ActivateTop()
+ *************************************************************************/
+void SwAttrHandler::ActivateTop( SwFont& rFnt, const USHORT nAttr )
+{
+ ASSERT( nAttr < RES_TXTATR_WITHEND_END,
+ "I cannot activate this attribute, nWhich >= RES_TXTATR_WITHEND_END" );
+
+ const USHORT nStackPos = StackPos[ nAttr ];
+ const SwTxtAttr* pTopAt = aAttrStack[ nStackPos ].Top();
+ if ( pTopAt )
+ {
+ // check if top attribute is collection of attributes
+ if ( RES_TXTATR_INETFMT == pTopAt->Which() ||
+ RES_TXTATR_CHARFMT == pTopAt->Which() ||
+ RES_TXTATR_AUTOFMT == pTopAt->Which() )
+ {
+ const SfxItemSet* pSet = CharFmt::GetItemSet( pTopAt->GetAttr() );
+ const SfxPoolItem* pItemNext;
+ pSet->GetItemState( nAttr, RES_TXTATR_AUTOFMT != pTopAt->Which(), &pItemNext );
+
+ Color aColor;
+ if ( lcl_ChgHyperLinkColor( *pTopAt, *pItemNext, mpShell, &aColor ) )
+ {
+ SvxColorItem aItemNext( aColor, RES_CHRATR_COLOR );
+ FontChg( aItemNext, rFnt, sal_False );
+ }
+ else
+ FontChg( *pItemNext, rFnt, sal_False );
+ }
+ else
+ FontChg( pTopAt->GetAttr(), rFnt, sal_False );
+ }
+
+ // default value has to be set, we only have default values for char attribs
+ else if ( nStackPos < NUM_DEFAULT_VALUES )
+ FontChg( *pDefaultArray[ nStackPos ], rFnt, sal_False );
+ else if ( RES_TXTATR_REFMARK == nAttr )
+ rFnt.GetRef()--;
+ else if ( RES_TXTATR_TOXMARK == nAttr )
+ rFnt.GetTox()--;
+ else if ( (RES_TXTATR_META == nAttr) || (RES_TXTATR_METAFIELD == nAttr) )
+ {
+ rFnt.GetMeta()--;
+ }
+ else if ( RES_TXTATR_CJK_RUBY == nAttr )
+ {
+ // ruby stack has no more attributes
+ // check, if an rotation attribute has to be applied
+ USHORT nTwoLineStack = StackPos[ RES_CHRATR_TWO_LINES ];
+ sal_Bool bTwoLineAct = sal_False;
+ const SfxPoolItem* pTwoLineItem = 0;
+ const SwTxtAttr* pTwoLineAttr = aAttrStack[ nTwoLineStack ].Top();
+
+ if ( pTwoLineAttr )
+ {
+ pTwoLineItem = CharFmt::GetItem( *pTwoLineAttr, RES_CHRATR_TWO_LINES );
+ bTwoLineAct = ((SvxTwoLinesItem*)pTwoLineItem)->GetValue();
+ }
+ else
+ bTwoLineAct =
+ ((SvxTwoLinesItem*)pDefaultArray[ nTwoLineStack ])->GetValue();
+
+ if ( bTwoLineAct )
+ return;
+
+ // eventually, an rotate attribute has to be activated
+ USHORT nRotateStack = StackPos[ RES_CHRATR_ROTATE ];
+ const SfxPoolItem* pRotateItem = 0;
+ const SwTxtAttr* pRotateAttr = aAttrStack[ nRotateStack ].Top();
+
+ if ( pRotateAttr )
+ {
+ pRotateItem = CharFmt::GetItem( *pRotateAttr, RES_CHRATR_ROTATE );
+ rFnt.SetVertical( ((SvxCharRotateItem*)pRotateItem)->GetValue(),
+ bVertLayout );
+ }
+ else
+ rFnt.SetVertical(
+ ((SvxCharRotateItem*)pDefaultArray[ nRotateStack ])->GetValue(),
+ bVertLayout
+ );
+ }
+}
+
+/*************************************************************************
+ * Font Changing Function
+ *
+ * When popping an attribute from the stack, the top mose remaining
+ * attribute in the stack becomes valid. The following function change
+ * a font depending on the stack id.
+ *************************************************************************/
+
+void SwAttrHandler::FontChg(const SfxPoolItem& rItem, SwFont& rFnt, sal_Bool bPush )
+{
+ switch ( rItem.Which() )
+ {
+ case RES_CHRATR_CASEMAP :
+ rFnt.SetCaseMap( ((SvxCaseMapItem&)rItem).GetCaseMap() );
+ break;
+ case RES_CHRATR_COLOR :
+ rFnt.SetColor( ((SvxColorItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_CONTOUR :
+ rFnt.SetOutline( ((SvxContourItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_CROSSEDOUT :
+ rFnt.SetStrikeout( ((SvxCrossedOutItem&)rItem).GetStrikeout() );
+ break;
+ case RES_CHRATR_ESCAPEMENT :
+ rFnt.SetEscapement( ((SvxEscapementItem&)rItem).GetEsc() );
+ rFnt.SetProportion( ((SvxEscapementItem&)rItem).GetProp() );
+ break;
+ case RES_CHRATR_FONT :
+ rFnt.SetName( ((SvxFontItem&)rItem).GetFamilyName(), SW_LATIN );
+ rFnt.SetStyleName( ((SvxFontItem&)rItem).GetStyleName(), SW_LATIN );
+ rFnt.SetFamily( ((SvxFontItem&)rItem).GetFamily(), SW_LATIN );
+ rFnt.SetPitch( ((SvxFontItem&)rItem).GetPitch(), SW_LATIN );
+ rFnt.SetCharSet( ((SvxFontItem&)rItem).GetCharSet(), SW_LATIN );
+ break;
+ case RES_CHRATR_FONTSIZE :
+ rFnt.SetSize(Size(0,((SvxFontHeightItem&)rItem).GetHeight() ), SW_LATIN );
+ break;
+ case RES_CHRATR_KERNING :
+ rFnt.SetFixKerning( ((SvxKerningItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_LANGUAGE :
+ rFnt.SetLanguage( ((SvxLanguageItem&)rItem).GetLanguage(), SW_LATIN );
+ break;
+ case RES_CHRATR_POSTURE :
+ rFnt.SetItalic( ((SvxPostureItem&)rItem).GetPosture(), SW_LATIN );
+ break;
+ case RES_CHRATR_SHADOWED :
+ rFnt.SetShadow( ((SvxShadowedItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_UNDERLINE :
+ {
+ const USHORT nStackPos = StackPos[ RES_CHRATR_HIDDEN ];
+ const SwTxtAttr* pTopAt = aAttrStack[ nStackPos ].Top();
+
+ const SfxPoolItem* pTmpItem = pTopAt ?
+ CharFmt::GetItem( *pTopAt, RES_CHRATR_HIDDEN ) :
+ pDefaultArray[ nStackPos ];
+
+ if( (mpShell && !mpShell->GetWin()) ||
+ (pTmpItem && !static_cast<const SvxCharHiddenItem*>(pTmpItem)->GetValue()) )
+ {
+ rFnt.SetUnderline( ((SvxUnderlineItem&)rItem).GetLineStyle() );
+ rFnt.SetUnderColor( ((SvxUnderlineItem&)rItem).GetColor() );
+ }
+ break;
+ }
+ case RES_CHRATR_OVERLINE :
+ rFnt.SetOverline( ((SvxOverlineItem&)rItem).GetLineStyle() );
+ rFnt.SetOverColor( ((SvxOverlineItem&)rItem).GetColor() );
+ break;
+ case RES_CHRATR_WEIGHT :
+ rFnt.SetWeight( ((SvxWeightItem&)rItem).GetWeight(), SW_LATIN );
+ break;
+ case RES_CHRATR_WORDLINEMODE :
+ rFnt.SetWordLineMode( ((SvxWordLineModeItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_AUTOKERN :
+ if( ((SvxAutoKernItem&)rItem).GetValue() )
+ {
+ rFnt.SetAutoKern( ( !mpIDocumentSettingAccess ||
+ !mpIDocumentSettingAccess->get(IDocumentSettingAccess::KERN_ASIAN_PUNCTUATION) ) ?
+ KERNING_FONTSPECIFIC :
+ KERNING_ASIAN );
+ }
+ else
+ rFnt.SetAutoKern( 0 );
+ break;
+ case RES_CHRATR_BLINK :
+ rFnt.SetBlink( ((SvxBlinkItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_BACKGROUND :
+ rFnt.SetBackColor(new Color( ((SvxBrushItem&)rItem).GetColor() ) );
+ break;
+ case RES_CHRATR_CJK_FONT :
+ rFnt.SetName( ((SvxFontItem&)rItem).GetFamilyName(), SW_CJK );
+ rFnt.SetStyleName( ((SvxFontItem&)rItem).GetStyleName(), SW_CJK );
+ rFnt.SetFamily( ((SvxFontItem&)rItem).GetFamily(), SW_CJK );
+ rFnt.SetPitch( ((SvxFontItem&)rItem).GetPitch(), SW_CJK );
+ rFnt.SetCharSet( ((SvxFontItem&)rItem).GetCharSet(), SW_CJK );
+ break;
+ case RES_CHRATR_CJK_FONTSIZE :
+ rFnt.SetSize(Size( 0, ((SvxFontHeightItem&)rItem).GetHeight()), SW_CJK);
+ break;
+ case RES_CHRATR_CJK_LANGUAGE :
+ rFnt.SetLanguage( ((SvxLanguageItem&)rItem).GetLanguage(), SW_CJK );
+ break;
+ case RES_CHRATR_CJK_POSTURE :
+ rFnt.SetItalic( ((SvxPostureItem&)rItem).GetPosture(), SW_CJK );
+ break;
+ case RES_CHRATR_CJK_WEIGHT :
+ rFnt.SetWeight( ((SvxWeightItem&)rItem).GetWeight(), SW_CJK );
+ break;
+ case RES_CHRATR_CTL_FONT :
+ rFnt.SetName( ((SvxFontItem&)rItem).GetFamilyName(), SW_CTL );
+ rFnt.SetStyleName( ((SvxFontItem&)rItem).GetStyleName(), SW_CTL );
+ rFnt.SetFamily( ((SvxFontItem&)rItem).GetFamily(), SW_CTL );
+ rFnt.SetPitch( ((SvxFontItem&)rItem).GetPitch(), SW_CTL );
+ rFnt.SetCharSet( ((SvxFontItem&)rItem).GetCharSet(), SW_CTL );
+ break;
+ case RES_CHRATR_CTL_FONTSIZE :
+ rFnt.SetSize(Size(0, ((SvxFontHeightItem&)rItem).GetHeight() ), SW_CTL);
+ break;
+ case RES_CHRATR_CTL_LANGUAGE :
+ rFnt.SetLanguage( ((SvxLanguageItem&)rItem).GetLanguage(), SW_CTL );
+ break;
+ case RES_CHRATR_CTL_POSTURE :
+ rFnt.SetItalic( ((SvxPostureItem&)rItem).GetPosture(), SW_CTL );
+ break;
+ case RES_CHRATR_CTL_WEIGHT :
+ rFnt.SetWeight( ((SvxWeightItem&)rItem).GetWeight(), SW_CTL );
+ break;
+ case RES_CHRATR_EMPHASIS_MARK :
+ rFnt.SetEmphasisMark(
+ ((SvxEmphasisMarkItem&)rItem).GetEmphasisMark()
+ );
+ break;
+ case RES_CHRATR_SCALEW :
+ rFnt.SetPropWidth( ((SvxCharScaleWidthItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_RELIEF :
+ rFnt.SetRelief( (FontRelief)((SvxCharReliefItem&)rItem).GetValue() );
+ break;
+ case RES_CHRATR_HIDDEN :
+ if( mpShell && mpShell->GetWin())
+ {
+ if ( ((SvxCharHiddenItem&)rItem).GetValue() )
+ rFnt.SetUnderline( UNDERLINE_DOTTED );
+ else
+ ActivateTop( rFnt, RES_CHRATR_UNDERLINE );
+ }
+ break;
+ case RES_CHRATR_ROTATE :
+ {
+ // rotate attribute is applied, when:
+ // 1. ruby stack is empty and
+ // 2. top of two line stack ( or default attribute )is an
+ // deactivated two line attribute
+ const bool bRuby =
+ 0 != aAttrStack[ StackPos[ RES_TXTATR_CJK_RUBY ] ].Count();
+
+ if ( bRuby )
+ break;
+
+ USHORT nTwoLineStack = StackPos[ RES_CHRATR_TWO_LINES ];
+ sal_Bool bTwoLineAct = sal_False;
+ const SfxPoolItem* pTwoLineItem = 0;
+ const SwTxtAttr* pTwoLineAttr = aAttrStack[ nTwoLineStack ].Top();
+
+ if ( pTwoLineAttr )
+ {
+ pTwoLineItem = CharFmt::GetItem( *pTwoLineAttr, RES_CHRATR_TWO_LINES );
+ bTwoLineAct = ((SvxTwoLinesItem*)pTwoLineItem)->GetValue();
+ }
+ else
+ bTwoLineAct =
+ ((SvxTwoLinesItem*)pDefaultArray[ nTwoLineStack ])->GetValue();
+
+ if ( !bTwoLineAct )
+ rFnt.SetVertical( ((SvxCharRotateItem&)rItem).GetValue(),
+ bVertLayout );
+
+ break;
+ }
+ case RES_CHRATR_TWO_LINES :
+ {
+ sal_Bool bRuby = 0 !=
+ aAttrStack[ StackPos[ RES_TXTATR_CJK_RUBY ] ].Count();
+ sal_Bool bTwoLineAct = sal_False;
+
+ // two line is activated, if
+ // 1. no ruby attribute is set and
+ // 2. attribute is active
+ bTwoLineAct = ((SvxTwoLinesItem&)rItem).GetValue();
+
+ if ( !bRuby && bTwoLineAct )
+ {
+ rFnt.SetVertical( 0, bVertLayout );
+ break;
+ }
+
+ // a deactivating two line attribute is on top of stack,
+ // check if rotate attribute has to be enabled
+ if ( bRuby )
+ break;
+
+ USHORT nRotateStack = StackPos[ RES_CHRATR_ROTATE ];
+ const SfxPoolItem* pRotateItem = 0;
+ const SwTxtAttr* pRotateAttr = aAttrStack[ nRotateStack ].Top();
+
+ if ( pRotateAttr )
+ {
+ pRotateItem = CharFmt::GetItem( *pRotateAttr, RES_CHRATR_ROTATE );
+ rFnt.SetVertical( ((SvxCharRotateItem*)pRotateItem)->GetValue(),
+ bVertLayout );
+ }
+ else
+ rFnt.SetVertical(
+ ((SvxCharRotateItem*)pDefaultArray[ nRotateStack ])->GetValue(),
+ bVertLayout
+ );
+ break;
+ }
+ case RES_TXTATR_CJK_RUBY :
+ rFnt.SetVertical( 0, bVertLayout );
+ break;
+ case RES_TXTATR_REFMARK :
+ if ( bPush )
+ rFnt.GetRef()++;
+ else
+ rFnt.GetRef()--;
+ break;
+ case RES_TXTATR_TOXMARK :
+ if ( bPush )
+ rFnt.GetTox()++;
+ else
+ rFnt.GetTox()--;
+ break;
+ case RES_TXTATR_META:
+ case RES_TXTATR_METAFIELD:
+ if ( bPush )
+ rFnt.GetMeta()++;
+ else
+ rFnt.GetMeta()--;
+ break;
+ }
+}
+
+// Takes the default font and calculated the ascent and height
+void SwAttrHandler::GetDefaultAscentAndHeight( ViewShell* pShell, OutputDevice& rOut,
+ USHORT& nAscent, USHORT& nHeight ) const
+{
+ ASSERT( pFnt, "No font available for GetDefaultAscentAndHeight" )
+
+ if ( pFnt )
+ {
+ SwFont aFont( *pFnt );
+ nHeight = aFont.GetHeight( pShell, rOut );
+ nAscent = aFont.GetAscent( pShell, rOut );
+ }
+}
+
diff --git a/sw/source/core/text/blink.cxx b/sw/source/core/text/blink.cxx
new file mode 100644
index 000000000000..717bf0170179
--- /dev/null
+++ b/sw/source/core/text/blink.cxx
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * 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 <tools/debug.hxx>
+#include "viewsh.hxx"
+#include "rootfrm.hxx" // GetOleShell()
+#include "txtfrm.hxx" // FindRootFrm()
+#include "blink.hxx"
+#include "porlin.hxx"
+#include "porlay.hxx" // SwLineLayout
+
+// Sichtbare Zeit:
+#define BLINK_ON_TIME 2400L
+// Nihct sichtbare Zeit:
+#define BLINK_OFF_TIME 800L
+
+/*************************************************************************
+ * pBlink zeigt auf die Instanz, bei der sich blinkende Portions anmelden
+ * muessen, ggf. muss pBlink erst per new SwBlink angelegt werden.
+ * Diese werden dann rhythmisch zum Repaint angeregt und koennen abfragen,
+ * ob sie zur Zeit sichtbar oder unsichtbar sein sollen ( IsVisible() ).
+ *************************************************************************/
+SwBlink *pBlink = NULL;
+
+
+// Liste von blinkenden Portions
+SV_IMPL_OP_PTRARR_SORT( SwBlinkList, SwBlinkPortionPtr )
+
+SwBlink::SwBlink()
+{
+ bVisible = sal_True;
+ // Den Timer vorbereiten
+ aTimer.SetTimeout( BLINK_ON_TIME );
+ aTimer.SetTimeoutHdl( LINK(this, SwBlink, Blinker) );
+}
+
+SwBlink::~SwBlink( )
+{
+ aTimer.Stop();
+}
+
+/*************************************************************************
+ * SwBlink::Blinker (Timerablauf):
+ * Sichtbar/unsichtbar-Flag toggeln.
+ * Repaint-Rechtecke der Blinkportions ermitteln und an ihren OleShells
+ * invalidieren.
+ *************************************************************************/
+
+IMPL_LINK( SwBlink, Blinker, Timer *, EMPTYARG )
+{
+ bVisible = !bVisible;
+ if( bVisible )
+ aTimer.SetTimeout( BLINK_ON_TIME );
+ else
+ aTimer.SetTimeout( BLINK_OFF_TIME );
+ if( aList.Count() )
+ {
+
+ for( MSHORT nPos = 0; nPos < aList.Count(); )
+ {
+ const SwBlinkPortion* pTmp = aList[ nPos ];
+ if( pTmp->GetRootFrm() &&
+ ((SwRootFrm*)pTmp->GetRootFrm())->GetCurrShell() )
+ {
+ ++nPos;
+
+ Point aPos = pTmp->GetPos();
+ long nWidth, nHeight;
+ switch ( pTmp->GetDirection() )
+ {
+ case 900:
+ aPos.X() -= pTmp->GetPortion()->GetAscent();
+ aPos.Y() -= pTmp->GetPortion()->Width();
+ nWidth = pTmp->GetPortion()->SvLSize().Height();
+ nHeight = pTmp->GetPortion()->SvLSize().Width();
+ break;
+ case 1800:
+ aPos.Y() -= pTmp->GetPortion()->Height() -
+ pTmp->GetPortion()->GetAscent();
+ aPos.X() -= pTmp->GetPortion()->Width();
+ nWidth = pTmp->GetPortion()->SvLSize().Width();
+ nHeight = pTmp->GetPortion()->SvLSize().Height();
+ break;
+ case 2700:
+ aPos.X() -= pTmp->GetPortion()->Height() -
+ pTmp->GetPortion()->GetAscent();
+ nWidth = pTmp->GetPortion()->SvLSize().Height();
+ nHeight = pTmp->GetPortion()->SvLSize().Width();
+ break;
+ default:
+ aPos.Y() -= pTmp->GetPortion()->GetAscent();
+ nWidth = pTmp->GetPortion()->SvLSize().Width();
+ nHeight = pTmp->GetPortion()->SvLSize().Height();
+ }
+
+ Rectangle aRefresh( aPos, Size( nWidth, nHeight ) );
+ aRefresh.Right() += ( aRefresh.Bottom()- aRefresh.Top() ) / 8;
+ ((SwRootFrm*)pTmp->GetRootFrm())
+ ->GetCurrShell()->InvalidateWindows( aRefresh );
+ }
+ else // Portions ohne Shell koennen aus der Liste entfernt werden.
+ aList.Remove( nPos );
+ }
+ }
+ else // Wenn die Liste leer ist, kann der Timer gestoppt werden.
+ aTimer.Stop();
+ return sal_True;
+}
+
+void SwBlink::Insert( const Point& rPoint, const SwLinePortion* pPor,
+ const SwTxtFrm *pTxtFrm, USHORT nDir )
+{
+ SwBlinkPortion *pBlinkPor = new SwBlinkPortion( pPor, nDir );
+
+ MSHORT nPos;
+ if( aList.Seek_Entry( pBlinkPor, &nPos ) )
+ {
+ aList[ nPos ]->SetPos( rPoint );
+ delete pBlinkPor;
+ }
+ else
+ {
+ pBlinkPor->SetPos( rPoint );
+ pBlinkPor->SetRootFrm( pTxtFrm->FindRootFrm() );
+ aList.Insert( pBlinkPor );
+ pTxtFrm->SetBlinkPor();
+ if( pPor->IsLayPortion() || pPor->IsParaPortion() )
+ ((SwLineLayout*)pPor)->SetBlinking( sal_True );
+
+ if( !aTimer.IsActive() )
+ aTimer.Start();
+ }
+}
+
+void SwBlink::Replace( const SwLinePortion* pOld, const SwLinePortion* pNew )
+{
+ // setting direction to 0 because direction does not matter
+ // for this operation
+ SwBlinkPortion aBlink( pOld, 0 );
+ MSHORT nPos;
+ if( aList.Seek_Entry( &aBlink, &nPos ) )
+ {
+ SwBlinkPortion* pTmp = new SwBlinkPortion( aList[ nPos ], pNew );
+ aList.Remove( nPos );
+ aList.Insert( pTmp );
+ }
+}
+
+void SwBlink::Delete( const SwLinePortion* pPor )
+{
+ // setting direction to 0 because direction does not matter
+ // for this operation
+ SwBlinkPortion aBlink( pPor, 0 );
+ MSHORT nPos;
+ if( aList.Seek_Entry( &aBlink, &nPos ) )
+ aList.Remove( nPos );
+}
+
+void SwBlink::FrmDelete( const SwRootFrm* pRoot )
+{
+ for( MSHORT nPos = 0; nPos < aList.Count(); )
+ {
+ if( pRoot == aList[ nPos ]->GetRootFrm() )
+ aList.Remove( nPos );
+ else
+ ++nPos;
+ }
+}
+
+
diff --git a/sw/source/core/text/frmcrsr.cxx b/sw/source/core/text/frmcrsr.cxx
new file mode 100644
index 000000000000..8f9d3fc77337
--- /dev/null
+++ b/sw/source/core/text/frmcrsr.cxx
@@ -0,0 +1,1744 @@
+/*************************************************************************
+ *
+ * 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 "ndtxt.hxx" // GetNode()
+#include "pam.hxx" // SwPosition
+#include "frmtool.hxx"
+#include "viewopt.hxx"
+#include "paratr.hxx"
+#include "pagefrm.hxx"
+#include "colfrm.hxx"
+#include "txttypes.hxx"
+#include <sfx2/printer.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <pormulti.hxx> // SwMultiPortion
+#include <doc.hxx>
+#include <sortedobjs.hxx>
+
+#include <unicode/ubidi.h>
+
+#include "txtcfg.hxx"
+#include "txtfrm.hxx" // SwTxtFrm
+#include "inftxt.hxx" // SwTxtSizeInfo
+#include "itrtxt.hxx" // SwTxtCursor
+#include "crstate.hxx" // SwTxtCursor
+#include "viewsh.hxx" // InvalidateWindows
+#include "swfntcch.hxx" // SwFontAccess
+#include "flyfrm.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include "txtpaint.hxx"
+#endif
+
+#define MIN_OFFSET_STEP 10
+
+using namespace ::com::sun::star;
+
+
+/*
+ * 1170-SurvivalKit: Wie gelangt man hinter das letzte Zeichen der Zeile.
+ * - RightMargin verzichtet auf den Positionsausgleich mit -1
+ * - GetCharRect liefert bei MV_RIGHTMARGIN ein GetEndCharRect
+ * - GetEndCharRect setzt bRightMargin auf sal_True
+ * - SwTxtCursor::bRightMargin wird per CharCrsrToLine auf sal_False gesetzt
+ */
+
+/*************************************************************************
+ * GetAdjFrmAtPos()
+ *************************************************************************/
+
+SwTxtFrm *GetAdjFrmAtPos( SwTxtFrm *pFrm, const SwPosition &rPos,
+ const sal_Bool bRightMargin, const sal_Bool bNoScroll = TRUE )
+{
+ // 8810: vgl. 1170, RightMargin in der letzten Masterzeile...
+ const xub_StrLen nOffset = rPos.nContent.GetIndex();
+ SwTxtFrm *pFrmAtPos = pFrm;
+ if( !bNoScroll || pFrm->GetFollow() )
+ {
+ pFrmAtPos = pFrm->GetFrmAtPos( rPos );
+ if( nOffset < pFrmAtPos->GetOfst() &&
+ !pFrmAtPos->IsFollow() )
+ {
+ xub_StrLen nNew = nOffset;
+ if( nNew < MIN_OFFSET_STEP )
+ nNew = 0;
+ else
+ nNew -= MIN_OFFSET_STEP;
+ lcl_ChangeOffset( pFrmAtPos, nNew );
+ }
+ }
+ while( pFrm != pFrmAtPos )
+ {
+ pFrm = pFrmAtPos;
+ pFrm->GetFormatted();
+ pFrmAtPos = (SwTxtFrm*)pFrm->GetFrmAtPos( rPos );
+ }
+
+ if( nOffset && bRightMargin )
+ {
+ while( pFrmAtPos && pFrmAtPos->GetOfst() == nOffset &&
+ pFrmAtPos->IsFollow() )
+ {
+ pFrmAtPos->GetFormatted();
+ pFrmAtPos = pFrmAtPos->FindMaster();
+ }
+ ASSERT( pFrmAtPos, "+GetCharRect: no frame with my rightmargin" );
+ }
+ return pFrmAtPos ? pFrmAtPos : pFrm;
+}
+
+sal_Bool lcl_ChangeOffset( SwTxtFrm* pFrm, xub_StrLen nNew )
+{
+ // In Bereichen und ausserhalb von Flies wird nicht mehr gescrollt.
+ ASSERT( !pFrm->IsFollow(), "Illegal Scrolling by Follow!" );
+ if( pFrm->GetOfst() != nNew && !pFrm->IsInSct() )
+ {
+ SwFlyFrm *pFly = pFrm->FindFlyFrm();
+ // Vorsicht, wenn z.B. bei einem spaltigen Rahmen die Groesse noch invalide ist,
+ // duerfen wir nicht mal eben herumscrollen
+ if ( ( pFly && pFly->IsValid() &&
+ !pFly->GetNextLink() && !pFly->GetPrevLink() ) ||
+ ( !pFly && pFrm->IsInTab() ) )
+ {
+ ViewShell* pVsh = pFrm->GetShell();
+ if( pVsh )
+ {
+ if( pVsh->GetNext() != pVsh ||
+ ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->Count() ) )
+ {
+ if( !pFrm->GetOfst() )
+ return sal_False;
+ nNew = 0;
+ }
+ pFrm->SetOfst( nNew );
+ pFrm->SetPara( 0 );
+ pFrm->GetFormatted();
+ if( pFrm->Frm().HasArea() )
+ pFrm->GetShell()->InvalidateWindows( pFrm->Frm() );
+ return sal_True;
+ }
+ }
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * GetFrmAtOfst(), GetFrmAtPos()
+ *************************************************************************/
+
+// OD 07.10.2003 #110978#
+SwTxtFrm& SwTxtFrm::GetFrmAtOfst( const xub_StrLen nWhere )
+{
+ SwTxtFrm* pRet = this;
+ while( pRet->HasFollow() && nWhere >= pRet->GetFollow()->GetOfst() )
+ pRet = pRet->GetFollow();
+ return *pRet;
+}
+
+SwTxtFrm *SwTxtFrm::GetFrmAtPos( const SwPosition &rPos )
+{
+ SwTxtFrm *pFoll = (SwTxtFrm*)this;
+ while( pFoll->GetFollow() )
+ {
+ if( rPos.nContent.GetIndex() > pFoll->GetFollow()->GetOfst() )
+ pFoll = pFoll->GetFollow();
+ else
+ {
+ if( rPos.nContent.GetIndex() == pFoll->GetFollow()->GetOfst()
+ && !SwTxtCursor::IsRightMargin() )
+ pFoll = pFoll->GetFollow();
+ else
+ break;
+ }
+ }
+ return pFoll;
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetCharRect()
+ *************************************************************************/
+
+/*
+ * GetCharRect() findet die Characterzelle des Characters, dass
+ * durch aPos beschrieben wird. GetCrsrOfst() findet den
+ * umgekehrten Weg: Von einer Dokumentkoordinate zu einem Pam.
+ * Beide sind virtuell in der Framebasisklasse und werden deshalb
+ * immer angezogen.
+ */
+
+sal_Bool SwTxtFrm::GetCharRect( SwRect& rOrig, const SwPosition &rPos,
+ SwCrsrMoveState *pCMS ) const
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::GetCharRect with swapped frame" );
+
+ if( IsLocked() || IsHiddenNow() )
+ return sal_False;
+
+ //Erstmal den richtigen Frm finden, dabei muss beachtet werden, dass:
+ //- die gecachten Informationen verworfen sein koennen (GetPara() == 0)
+ //- das ein Follow gemeint sein kann
+ //- das die Kette der Follows dynamisch waechst; der in den wir
+ // schliesslich gelangen muss aber Formatiert sein.
+
+ // opt: reading ahead erspart uns ein GetAdjFrmAtPos
+ const sal_Bool bRightMargin = pCMS && ( MV_RIGHTMARGIN == pCMS->eState );
+ const sal_Bool bNoScroll = pCMS && pCMS->bNoScroll;
+ SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, rPos, bRightMargin,
+ bNoScroll );
+ pFrm->GetFormatted();
+ const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
+
+ SWRECTFN ( pFrm )
+ const SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
+ const SwTwips nFrmMaxY = (pFrm->*fnRect->fnGetPrtBottom)();
+
+ // nMaxY is an absolute value
+ SwTwips nMaxY = bVert ?
+ Max( nFrmMaxY, nUpperMaxY ) :
+ Min( nFrmMaxY, nUpperMaxY );
+
+ sal_Bool bRet = sal_False;
+
+ if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
+ {
+ Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
+ short nFirstOffset;
+ pTxtNd->GetFirstLineOfsWithNum( nFirstOffset );
+
+ Point aPnt2;
+ if ( bVert )
+ {
+ if( nFirstOffset > 0 )
+ aPnt1.Y() += nFirstOffset;
+
+ if ( aPnt1.X() < nMaxY )
+ aPnt1.X() = nMaxY;
+ aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
+ aPnt2.Y() = aPnt1.Y();
+ if( aPnt2.X() < nMaxY )
+ aPnt2.X() = nMaxY;
+ }
+ else
+ {
+ if( nFirstOffset > 0 )
+ aPnt1.X() += nFirstOffset;
+
+ if( aPnt1.Y() > nMaxY )
+ aPnt1.Y() = nMaxY;
+ aPnt2.X() = aPnt1.X();
+ aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
+ if( aPnt2.Y() > nMaxY )
+ aPnt2.Y() = nMaxY;
+ }
+
+ rOrig = SwRect( aPnt1, aPnt2 );
+
+ if ( pCMS )
+ {
+ pCMS->aRealHeight.X() = 0;
+ pCMS->aRealHeight.Y() = bVert ? -rOrig.Width() : rOrig.Height();
+ }
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( rOrig );
+
+ bRet = sal_True;
+ }
+ else
+ {
+ if( !pFrm->HasPara() )
+ return sal_False;
+
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+ if ( bVert )
+ nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
+
+ sal_Bool bGoOn = sal_True;
+ xub_StrLen nOffset = rPos.nContent.GetIndex();
+ xub_StrLen nNextOfst;
+
+ do
+ {
+ {
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+ nNextOfst = aLine.GetEnd();
+ // Siehe Kommentar in AdjustFrm
+ // 1170: das letzte Zeichen der Zeile mitnehmen?
+ bRet = bRightMargin ? aLine.GetEndCharRect( &rOrig, nOffset, pCMS, nMaxY )
+ : aLine.GetCharRect( &rOrig, nOffset, pCMS, nMaxY );
+ }
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( rOrig );
+
+ if ( bVert )
+ pFrm->SwitchHorizontalToVertical( rOrig );
+
+ if( pFrm->IsUndersized() && pCMS && !pFrm->GetNext() &&
+ (rOrig.*fnRect->fnGetBottom)() == nUpperMaxY &&
+ pFrm->GetOfst() < nOffset &&
+ !pFrm->IsFollow() && !bNoScroll &&
+ pFrm->GetTxtNode()->GetTxt().Len() != nNextOfst )
+ bGoOn = lcl_ChangeOffset( pFrm, nNextOfst );
+ else
+ bGoOn = sal_False;
+ } while ( bGoOn );
+
+ if ( pCMS )
+ {
+ if ( pFrm->IsRightToLeft() )
+ {
+ if( pCMS->b2Lines && pCMS->p2Lines)
+ {
+ pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aLine );
+ pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aPortion );
+ }
+ }
+
+ if ( bVert )
+ {
+ if ( pCMS->bRealHeight )
+ {
+ pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
+ if ( pCMS->aRealHeight.Y() < 0 )
+ {
+ // writing direction is from top to bottom
+ pCMS->aRealHeight.X() = ( rOrig.Width() -
+ pCMS->aRealHeight.X() +
+ pCMS->aRealHeight.Y() );
+ }
+ }
+ if( pCMS->b2Lines && pCMS->p2Lines)
+ {
+ pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aLine );
+ pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aPortion );
+ }
+ }
+
+ }
+ }
+ if( bRet )
+ {
+ SwPageFrm *pPage = pFrm->FindPageFrm();
+ ASSERT( pPage, "Text esaped from page?" );
+ const SwTwips nOrigTop = (rOrig.*fnRect->fnGetTop)();
+ const SwTwips nPageTop = (pPage->Frm().*fnRect->fnGetTop)();
+ const SwTwips nPageBott = (pPage->Frm().*fnRect->fnGetBottom)();
+
+ // Following situation: if the frame is in an invalid sectionframe,
+ // it's possible that the frame is outside the page. If we restrict
+ // the cursor position to the page area, we enforce the formatting
+ // of the page, of the section frame and the frame himself.
+ if( (*fnRect->fnYDiff)( nPageTop, nOrigTop ) > 0 )
+ (rOrig.*fnRect->fnSetTop)( nPageTop );
+
+ if ( (*fnRect->fnYDiff)( nOrigTop, nPageBott ) > 0 )
+ (rOrig.*fnRect->fnSetTop)( nPageBott );
+ }
+
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetAutoPos()
+ *************************************************************************/
+
+/*
+ * GetAutoPos() findet die Characterzelle des Characters, dass
+ * durch aPos beschrieben wird und wird von autopositionierten Rahmen genutzt.
+ */
+
+sal_Bool SwTxtFrm::GetAutoPos( SwRect& rOrig, const SwPosition &rPos ) const
+{
+ if( IsHiddenNow() )
+ return sal_False;
+
+ xub_StrLen nOffset = rPos.nContent.GetIndex();
+ SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
+
+ pFrm->GetFormatted();
+ const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
+
+ SWRECTFN( pTmpFrm )
+ SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
+
+ // nMaxY is in absolute value
+ SwTwips nMaxY = bVert ?
+ Max( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) :
+ Min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY );
+
+ if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
+ {
+ Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
+ Point aPnt2;
+ if ( bVert )
+ {
+ if ( aPnt1.X() < nMaxY )
+ aPnt1.X() = nMaxY;
+ aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
+ aPnt2.Y() = aPnt1.Y();
+ if( aPnt2.X() < nMaxY )
+ aPnt2.X() = nMaxY;
+ }
+ else
+ {
+ if( aPnt1.Y() > nMaxY )
+ aPnt1.Y() = nMaxY;
+ aPnt2.X() = aPnt1.X();
+ aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
+ if( aPnt2.Y() > nMaxY )
+ aPnt2.Y() = nMaxY;
+ }
+ rOrig = SwRect( aPnt1, aPnt2 );
+ return sal_True;
+ }
+ else
+ {
+ if( !pFrm->HasPara() )
+ return sal_False;
+
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+ if ( bVert )
+ nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
+
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+ SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
+ aTmpState.bRealHeight = TRUE;
+ if( aLine.GetCharRect( &rOrig, nOffset, &aTmpState, nMaxY ) )
+ {
+ if( aTmpState.aRealHeight.X() >= 0 )
+ {
+ rOrig.Pos().Y() += aTmpState.aRealHeight.X();
+ rOrig.Height( aTmpState.aRealHeight.Y() );
+ }
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( rOrig );
+
+ if ( bVert )
+ pFrm->SwitchHorizontalToVertical( rOrig );
+
+ return sal_True;
+ }
+ return sal_False;
+ }
+}
+
+/** determine top of line for given position in the text frame
+
+ OD 11.11.2003 #i22341#
+ OD 2004-03-18 #114789# - corrections:
+ - Top of first paragraph line is the top of the printing area of the text frame
+ - If a proportional line spacing is applied use top of anchor character as
+ top of the line.
+
+ @author OD
+*/
+bool SwTxtFrm::GetTopOfLine( SwTwips& _onTopOfLine,
+ const SwPosition& _rPos ) const
+{
+ bool bRet = true;
+
+ // get position offset
+ xub_StrLen nOffset = _rPos.nContent.GetIndex();
+
+ if ( GetTxt().Len() < nOffset )
+ {
+ bRet = false;
+ }
+ else
+ {
+ SWRECTFN( this )
+ if ( IsEmpty() || !(Prt().*fnRect->fnGetHeight)() )
+ {
+ // OD 2004-03-18 #i11860# - consider upper space amount considered
+ // for previous frame and the page grid.
+ _onTopOfLine = (this->*fnRect->fnGetPrtTop)();
+ }
+ else
+ {
+ // determine formatted text frame that contains the requested position
+ SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
+ pFrm->GetFormatted();
+ SWREFRESHFN( pFrm )
+ // OD 2004-03-18 #114789# - If proportional line spacing is applied
+ // to the text frame, the top of the anchor character is also the
+ // top of the line.
+ // Otherwise the line layout determines the top of the line
+ const SvxLineSpacingItem& rSpace = GetAttrSet()->GetLineSpacing();
+ if ( rSpace.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
+ {
+ SwRect aCharRect;
+ if ( GetAutoPos( aCharRect, _rPos ) )
+ {
+ _onTopOfLine = (aCharRect.*fnRect->fnGetTop)();
+ }
+ else
+ {
+ bRet = false;
+ }
+ }
+ else
+ {
+ // assure that text frame is in a horizontal layout
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+ // determine text line that contains the requested position
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+ aLine.CharCrsrToLine( nOffset );
+ // determine top of line
+ _onTopOfLine = aLine.Y();
+ if ( bVert )
+ {
+ _onTopOfLine = pFrm->SwitchHorizontalToVertical( _onTopOfLine );
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::_GetCrsrOfst()
+ *************************************************************************/
+
+// Minimaler Abstand von nichtleeren Zeilen etwas weniger als 2 cm
+#define FILL_MIN_DIST 1100
+
+struct SwFillData
+{
+ SwRect aFrm;
+ const SwCrsrMoveState *pCMS;
+ SwPosition* pPos;
+ const Point& rPoint;
+ SwTwips nLineWidth;
+ sal_Bool bFirstLine : 1;
+ sal_Bool bInner : 1;
+ sal_Bool bColumn : 1;
+ sal_Bool bEmpty : 1;
+ SwFillData( const SwCrsrMoveState *pC, SwPosition* pP, const SwRect& rR,
+ const Point& rPt ) : aFrm( rR ), pCMS( pC ), pPos( pP ), rPoint( rPt ),
+ nLineWidth( 0 ), bFirstLine( sal_True ), bInner( sal_False ), bColumn( sal_False ),
+ bEmpty( sal_True ){}
+ SwFillMode Mode() const { return pCMS->pFill->eMode; }
+ long X() const { return rPoint.X(); }
+ long Y() const { return rPoint.Y(); }
+ long Left() const { return aFrm.Left(); }
+ long Right() const { return aFrm.Right(); }
+ long Bottom() const { return aFrm.Bottom(); }
+ SwRect& Frm() { return aFrm; }
+ SwFillCrsrPos &Fill() const { return *pCMS->pFill; }
+ void SetTab( MSHORT nNew ) { pCMS->pFill->nTabCnt = nNew; }
+ void SetSpace( MSHORT nNew ) { pCMS->pFill->nSpaceCnt = nNew; }
+ void SetOrient( const sal_Int16 eNew ){ pCMS->pFill->eOrient = eNew; }
+};
+
+sal_Bool SwTxtFrm::_GetCrsrOfst(SwPosition* pPos, const Point& rPoint,
+ const sal_Bool bChgFrm, SwCrsrMoveState* pCMS ) const
+{
+ // 8804: _GetCrsrOfst wird vom GetCrsrOfst und GetKeyCrsrOfst gerufen.
+ // In keinem Fall nur ein return sal_False.
+
+ if( IsLocked() || IsHiddenNow() )
+ return sal_False;
+
+ ((SwTxtFrm*)this)->GetFormatted();
+
+ Point aOldPoint( rPoint );
+
+ if ( IsVertical() )
+ {
+ SwitchVerticalToHorizontal( (Point&)rPoint );
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+ }
+
+ if ( IsRightToLeft() )
+ SwitchRTLtoLTR( (Point&)rPoint );
+
+ SwFillData *pFillData = ( pCMS && pCMS->pFill ) ?
+ new SwFillData( pCMS, pPos, Frm(), rPoint ) : NULL;
+
+ if ( IsEmpty() )
+ {
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
+ pPos->nNode = *pTxtNd;
+ pPos->nContent.Assign( pTxtNd, 0 );
+ if( pCMS && pCMS->bFieldInfo )
+ {
+ SwTwips nDiff = rPoint.X() - Frm().Left() - Prt().Left();
+ if( nDiff > 50 || nDiff < 0 )
+ ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
+ }
+ }
+ else
+ {
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+
+ // Siehe Kommentar in AdjustFrm()
+ SwTwips nMaxY = Frm().Top() + Prt().Top() + Prt().Height();
+ aLine.TwipsToLine( rPoint.Y() );
+ while( aLine.Y() + aLine.GetLineHeight() > nMaxY )
+ {
+ DBG_LOOP;
+ if( !aLine.Prev() )
+ break;
+ }
+
+ if( aLine.GetDropLines() >= aLine.GetLineNr() && 1 != aLine.GetLineNr()
+ && rPoint.X() < aLine.FirstLeft() + aLine.GetDropLeft() )
+ while( aLine.GetLineNr() > 1 )
+ aLine.Prev();
+
+ xub_StrLen nOffset = aLine.GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
+
+ if( pCMS && pCMS->eState == MV_NONE && aLine.GetEnd() == nOffset )
+ ((SwCrsrMoveState*)pCMS)->eState = MV_RIGHTMARGIN;
+
+ // 6776: pPos ist ein reiner IN-Parameter, der nicht ausgewertet werden darf.
+ // Das pIter->GetCrsrOfst returnt aus einer Verschachtelung mit STRING_LEN.
+ // Wenn SwTxtIter::GetCrsrOfst von sich aus weitere GetCrsrOfst
+ // ruft, so aendert sich nNode der Position. In solchen Faellen
+ // darf pPos nicht berechnet werden.
+ if( STRING_LEN != nOffset )
+ {
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
+ pPos->nNode = *pTxtNd;
+ pPos->nContent.Assign( pTxtNd, nOffset );
+ if( pFillData )
+ {
+ if( pTxtNd->GetTxt().Len() > nOffset ||
+ rPoint.Y() < Frm().Top() )
+ pFillData->bInner = sal_True;
+ pFillData->bFirstLine = aLine.GetLineNr() < 2;
+ if( pTxtNd->GetTxt().Len() )
+ {
+ pFillData->bEmpty = sal_False;
+ pFillData->nLineWidth = aLine.GetCurr()->Width();
+ }
+ }
+ }
+ }
+ sal_Bool bChgFillData = sal_False;
+ if( pFillData && FindPageFrm()->Frm().IsInside( aOldPoint ) )
+ {
+ FillCrsrPos( *pFillData );
+ bChgFillData = sal_True;
+ }
+
+ if ( IsVertical() )
+ {
+ if ( bChgFillData )
+ SwitchHorizontalToVertical( pFillData->Fill().aCrsr.Pos() );
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+ }
+
+ if ( IsRightToLeft() && bChgFillData )
+ {
+ SwitchLTRtoRTL( pFillData->Fill().aCrsr.Pos() );
+ const sal_Int16 eOrient = pFillData->pCMS->pFill->eOrient;
+
+ if ( text::HoriOrientation::LEFT == eOrient )
+ pFillData->SetOrient( text::HoriOrientation::RIGHT );
+ else if ( text::HoriOrientation::RIGHT == eOrient )
+ pFillData->SetOrient( text::HoriOrientation::LEFT );
+ }
+
+ (Point&)rPoint = aOldPoint;
+ delete pFillData;
+
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwTxtFrm::GetCrsrOfst()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& rPoint,
+ SwCrsrMoveState* pCMS ) const
+{
+ MSHORT nChgFrm = 2;
+ if( pCMS )
+ {
+ if( MV_UPDOWN == pCMS->eState )
+ nChgFrm = 0;
+ else if( MV_SETONLYTEXT == pCMS->eState ||
+ MV_TBLSEL == pCMS->eState )
+ nChgFrm = 1;
+ }
+ return _GetCrsrOfst( pPos, rPoint, nChgFrm != 0, pCMS );
+}
+
+/*************************************************************************
+ * SwTxtFrm::LeftMargin()
+ *************************************************************************/
+
+/*
+ * Layout-orientierte Cursorbewegungen
+ */
+
+/*
+ * an den Zeilenanfang
+ */
+
+sal_Bool SwTxtFrm::LeftMargin(SwPaM *pPam) const
+{
+ if( ((const SwNode*)pPam->GetNode()) != GetNode() )
+ pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
+
+ SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
+ SwTxtCursor::IsRightMargin() );
+ pFrm->GetFormatted();
+ xub_StrLen nIndx;
+ if ( pFrm->IsEmpty() )
+ nIndx = 0;
+ else
+ {
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+
+ aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
+ nIndx = aLine.GetStart();
+ if( pFrm->GetOfst() && !pFrm->IsFollow() && !aLine.GetPrev() )
+ {
+ lcl_ChangeOffset( pFrm, 0 );
+ nIndx = 0;
+ }
+ }
+ pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nIndx );
+ SwTxtCursor::SetRightMargin( sal_False );
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFrm::RightMargin()
+ *************************************************************************/
+
+/*
+ * An das Zeilenende:Das ist die Position vor dem letzten
+ * Character in der Zeile. Ausnahme: In der letzten Zeile soll
+ * der Cursor auch hinter dem letzten Character stehen koennen,
+ * um Text anhaengen zu koennen.
+ *
+ */
+
+sal_Bool SwTxtFrm::RightMargin(SwPaM *pPam, sal_Bool bAPI) const
+{
+ if( ((const SwNode*)pPam->GetNode()) != GetNode() )
+ pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
+
+ SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
+ SwTxtCursor::IsRightMargin() );
+ pFrm->GetFormatted();
+ xub_StrLen nRightMargin;
+ if ( IsEmpty() )
+ nRightMargin = 0;
+ else
+ {
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+
+ aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
+ nRightMargin = aLine.GetStart() + aLine.GetCurr()->GetLen();
+
+ // Harte Zeilenumbrueche lassen wir hinter uns.
+ if( aLine.GetCurr()->GetLen() &&
+ CH_BREAK == aInf.GetTxt().GetChar( nRightMargin - 1 ) )
+ --nRightMargin;
+ if( !bAPI && (aLine.GetNext() || pFrm->GetFollow()) )
+ {
+ while( nRightMargin > aLine.GetStart() &&
+ ' ' == aInf.GetTxt().GetChar( nRightMargin - 1 ) )
+ --nRightMargin;
+ }
+ }
+ pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nRightMargin );
+ SwTxtCursor::SetRightMargin( !bAPI );
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFrm::_UnitUp()
+ *************************************************************************/
+
+//Die beiden folgenden Methoden versuchen zunaechst den Crsr in die
+//nachste/folgende Zeile zu setzen. Gibt es im Frame keine vorhergehende/
+//folgende Zeile, so wird der Aufruf an die Basisklasse weitergeleitet.
+//Die Horizontale Ausrichtung des Crsr wird hinterher von der CrsrShell
+//vorgenommen.
+
+class SwSetToRightMargin
+{
+ sal_Bool bRight;
+public:
+ inline SwSetToRightMargin() : bRight( sal_False ) { }
+ inline ~SwSetToRightMargin() { SwTxtCursor::SetRightMargin( bRight ); }
+ inline void SetRight( const sal_Bool bNew ) { bRight = bNew; }
+};
+
+sal_Bool SwTxtFrm::_UnitUp( SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+ // 8626: Im Notfall den RightMargin setzen.
+ SwSetToRightMargin aSet;
+
+ if( IsInTab() &&
+ pPam->GetNode( sal_True )->StartOfSectionNode() !=
+ pPam->GetNode( sal_False )->StartOfSectionNode() )
+ {
+ //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
+ //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
+ return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
+ }
+
+ ((SwTxtFrm*)this)->GetFormatted();
+ const xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
+ SwRect aCharBox;
+
+ if( !IsEmpty() && !IsHiddenNow() )
+ {
+ xub_StrLen nFormat = STRING_LEN;
+ do
+ {
+ if( nFormat != STRING_LEN && !IsFollow() )
+ lcl_ChangeOffset( ((SwTxtFrm*)this), nFormat );
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+
+ // 8116: Flys ohne Umlauf und IsDummy(); hier wegoptimiert
+ if( nPos )
+ aLine.CharCrsrToLine( nPos );
+ else
+ aLine.Top();
+
+ const SwLineLayout *pPrevLine = aLine.GetPrevLine();
+ const xub_StrLen nStart = aLine.GetStart();
+ aLine.GetCharRect( &aCharBox, nPos );
+
+ sal_Bool bSecondOfDouble = ( aInf.IsMulti() && ! aInf.IsFirstMulti() );
+ sal_Bool bPrevLine = ( pPrevLine && pPrevLine != aLine.GetCurr() );
+
+ if( !pPrevLine && !bSecondOfDouble && GetOfst() && !IsFollow() )
+ {
+ nFormat = GetOfst();
+ xub_StrLen nDiff = aLine.GetLength();
+ if( !nDiff )
+ nDiff = MIN_OFFSET_STEP;
+ if( nFormat > nDiff )
+ nFormat = nFormat - nDiff;
+ else
+ nFormat = 0;
+ continue;
+ }
+
+ // we select the target line for the cursor, in case we are in a
+ // double line portion, prev line = curr line
+ if( bPrevLine && !bSecondOfDouble )
+ {
+ aLine.PrevLine();
+ while ( aLine.GetStart() == nStart &&
+ 0 != ( pPrevLine = aLine.GetPrevLine() ) &&
+ pPrevLine != aLine.GetCurr() )
+ aLine.PrevLine();
+ }
+
+ if ( bPrevLine || bSecondOfDouble )
+ {
+ aCharBox.SSize().Width() /= 2;
+ aCharBox.Pos().X() = aCharBox.Pos().X() - 150;
+
+ // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
+#ifdef DBG_UTIL
+ const ULONG nOldNode = pPam->GetPoint()->nNode.GetIndex();
+#endif
+ // Der Node soll nicht gewechselt werden
+ xub_StrLen nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
+ aCharBox.Pos(), sal_False );
+ ASSERT( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
+ "SwTxtFrm::UnitUp: illegal node change" )
+
+ // 7684: Wir stellen sicher, dass wir uns nach oben bewegen.
+ if( nTmpOfst >= nStart && nStart && !bSecondOfDouble )
+ {
+ nTmpOfst = nStart;
+ aSet.SetRight( sal_True );
+ }
+ pPam->GetPoint()->nContent =
+ SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
+ return sal_True;
+ }
+
+ if ( IsFollow() )
+ {
+ aLine.GetCharRect( &aCharBox, nPos );
+ aCharBox.SSize().Width() /= 2;
+ }
+ break;
+ } while ( sal_True );
+ }
+ /* Wenn this ein Follow ist und ein Prev miszlang, so
+ * muessen wir in die letzte Zeile des Master ... und der sind wir.
+ * Oder wir sind ein Follow mit Follow, dann muessen wir uns den
+ * Master extra besorgen...
+ */
+ if ( IsFollow() )
+ {
+ const SwTxtFrm *pTmpPrev = FindMaster();
+ xub_StrLen nOffs = GetOfst();
+ if( pTmpPrev )
+ {
+ ViewShell *pSh = GetShell();
+ sal_Bool bProtectedAllowed = pSh && pSh->GetViewOptions()->IsCursorInProtectedArea();
+ const SwTxtFrm *pPrevPrev = pTmpPrev;
+ // Hier werden geschuetzte Frames und Frame ohne Inhalt ausgelassen
+ while( pPrevPrev && ( pPrevPrev->GetOfst() == nOffs ||
+ ( !bProtectedAllowed && pPrevPrev->IsProtected() ) ) )
+ {
+ pTmpPrev = pPrevPrev;
+ nOffs = pTmpPrev->GetOfst();
+ if ( pPrevPrev->IsFollow() )
+ pPrevPrev = pTmpPrev->FindMaster();
+ else
+ pPrevPrev = NULL;
+ }
+ if ( !pPrevPrev )
+ return pTmpPrev->SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
+ aCharBox.Pos().Y() = pPrevPrev->Frm().Bottom() - 1;
+ return pPrevPrev->GetKeyCrsrOfst( pPam->GetPoint(), aCharBox.Pos() );
+ }
+ }
+ return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
+}
+
+//
+// Used for Bidi. nPos is the logical position in the string, bLeft indicates
+// if left arrow or right arrow was pressed. The return values are:
+// nPos: the new visual position
+// bLeft: whether the break iterator has to add or subtract from the
+// current position
+void lcl_VisualMoveRecursion( const SwLineLayout& rCurrLine, xub_StrLen nIdx,
+ xub_StrLen& nPos, sal_Bool& bRight,
+ BYTE& nCrsrLevel, BYTE nDefaultDir )
+{
+ const SwLinePortion* pPor = rCurrLine.GetFirstPortion();
+ const SwLinePortion* pLast = 0;
+
+ // what's the current portion
+ while ( pPor && nIdx + pPor->GetLen() <= nPos )
+ {
+ nIdx = nIdx + pPor->GetLen();
+ pLast = pPor;
+ pPor = pPor->GetPortion();
+ }
+
+ if ( bRight )
+ {
+ sal_Bool bRecurse = pPor && pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->IsBidi();
+
+ // 1. special case: at beginning of bidi portion
+ if ( bRecurse && nIdx == nPos )
+ {
+ nPos = nPos + pPor->GetLen();
+
+ // leave bidi portion
+ if ( nCrsrLevel != nDefaultDir )
+ {
+ bRecurse = sal_False;
+ }
+ else
+ // special case:
+ // buffer: abcXYZ123 in LTR paragraph
+ // view: abc123ZYX
+ // cursor is between c and X in the buffer and cursor level = 0
+ nCrsrLevel++;
+ }
+
+ // 2. special case: at beginning of portion after bidi portion
+ else if ( pLast && pLast->IsMultiPortion() &&
+ ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
+ {
+ // enter bidi portion
+ if ( nCrsrLevel != nDefaultDir )
+ {
+ bRecurse = sal_True;
+ nIdx = nIdx - pLast->GetLen();
+ pPor = pLast;
+ }
+ }
+
+ // Recursion
+ if ( bRecurse )
+ {
+ const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
+ xub_StrLen nTmpPos = nPos - nIdx;
+ sal_Bool bTmpForward = ! bRight;
+ BYTE nTmpCrsrLevel = nCrsrLevel;
+ lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
+ nTmpCrsrLevel, nDefaultDir + 1 );
+
+ nPos = nTmpPos + nIdx;
+ bRight = bTmpForward;
+ nCrsrLevel = nTmpCrsrLevel;
+ }
+
+ // go forward
+ else
+ {
+ bRight = sal_True;
+ nCrsrLevel = nDefaultDir;
+ }
+
+ }
+ else
+ {
+ sal_Bool bRecurse = pPor && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi();
+
+ // 1. special case: at beginning of bidi portion
+ if ( bRecurse && nIdx == nPos )
+ {
+ // leave bidi portion
+ if ( nCrsrLevel == nDefaultDir )
+ {
+ bRecurse = sal_False;
+ }
+ }
+
+ // 2. special case: at beginning of portion after bidi portion
+ else if ( pLast && pLast->IsMultiPortion() &&
+ ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
+ {
+ nPos = nPos - pLast->GetLen();
+
+ // enter bidi portion
+ if ( nCrsrLevel % 2 == nDefaultDir % 2 )
+ {
+ bRecurse = sal_True;
+ nIdx = nIdx - pLast->GetLen();
+ pPor = pLast;
+
+ // special case:
+ // buffer: abcXYZ123 in LTR paragraph
+ // view: abc123ZYX
+ // cursor is behind 3 in the buffer and cursor level = 2
+ if ( nDefaultDir + 2 == nCrsrLevel )
+ nPos = nPos + pLast->GetLen();
+ }
+ }
+
+ // go forward
+ if ( bRecurse )
+ {
+ const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
+ xub_StrLen nTmpPos = nPos - nIdx;
+ sal_Bool bTmpForward = ! bRight;
+ BYTE nTmpCrsrLevel = nCrsrLevel;
+ lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
+ nTmpCrsrLevel, nDefaultDir + 1 );
+
+ // special case:
+ // buffer: abcXYZ123 in LTR paragraph
+ // view: abc123ZYX
+ // cursor is between Z and 1 in the buffer and cursor level = 2
+ if ( nTmpPos == pPor->GetLen() && nTmpCrsrLevel == nDefaultDir + 1 )
+ {
+ nTmpPos = nTmpPos - pPor->GetLen();
+ nTmpCrsrLevel = nDefaultDir;
+ bTmpForward = ! bTmpForward;
+ }
+
+ nPos = nTmpPos + nIdx;
+ bRight = bTmpForward;
+ nCrsrLevel = nTmpCrsrLevel;
+ }
+
+ // go backward
+ else
+ {
+ bRight = sal_False;
+ nCrsrLevel = nDefaultDir;
+ }
+ }
+}
+
+void SwTxtFrm::PrepareVisualMove( xub_StrLen& nPos, BYTE& nCrsrLevel,
+ sal_Bool& bForward, sal_Bool bInsertCrsr )
+{
+ if( IsEmpty() || IsHiddenNow() )
+ return;
+
+ ((SwTxtFrm*)this)->GetFormatted();
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+
+ if( nPos )
+ aLine.CharCrsrToLine( nPos );
+ else
+ aLine.Top();
+
+ const SwLineLayout* pLine = aLine.GetCurr();
+ const xub_StrLen nStt = aLine.GetStart();
+ const xub_StrLen nLen = pLine->GetLen();
+
+ // We have to distinguish between an insert and overwrite cursor:
+ // The insert cursor position depends on the cursor level:
+ // buffer: abcXYZdef in LTR paragraph
+ // display: abcZYXdef
+ // If cursor is between c and X in the buffer and cursor level is 0,
+ // the cursor blinks between c and Z and -> sets the cursor between Z and Y.
+ // If the cursor level is 1, the cursor blinks between X and d and
+ // -> sets the cursor between d and e.
+ // The overwrite cursor simply travels to the next visual character.
+ if ( bInsertCrsr )
+ {
+ lcl_VisualMoveRecursion( *pLine, nStt, nPos, bForward,
+ nCrsrLevel, IsRightToLeft() ? 1 : 0 );
+ return;
+ }
+
+ const BYTE nDefaultDir = static_cast<BYTE>(IsRightToLeft() ? UBIDI_RTL : UBIDI_LTR);
+ const sal_Bool bVisualRight = ( nDefaultDir == UBIDI_LTR && bForward ) ||
+ ( nDefaultDir == UBIDI_RTL && ! bForward );
+
+ //
+ // Bidi functions from icu 2.0
+ //
+ const sal_Unicode* pLineString = GetTxtNode()->GetTxt().GetBuffer();
+ pLine += nStt;
+
+ UErrorCode nError = U_ZERO_ERROR;
+ UBiDi* pBidi = ubidi_openSized( nLen, 0, &nError );
+ ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), nLen, nDefaultDir, NULL, &nError ); // UChar != sal_Unicode in MinGW
+
+ xub_StrLen nTmpPos;
+ sal_Bool bOutOfBounds = sal_False;
+
+ if ( nPos < nStt + nLen )
+ {
+ nTmpPos = (xub_StrLen)ubidi_getVisualIndex( pBidi, nPos, &nError );
+
+ // visual indices are always LTR aligned
+ if ( bVisualRight )
+ {
+ if ( nTmpPos + 1 < nStt + nLen )
+ ++nTmpPos;
+ else
+ {
+ nPos = nDefaultDir == UBIDI_RTL ? 0 : nStt + nLen;
+ bOutOfBounds = sal_True;
+ }
+ }
+ else
+ {
+ if ( nTmpPos )
+ --nTmpPos;
+ else
+ {
+ nPos = nDefaultDir == UBIDI_RTL ? nStt + nLen : 0;
+ bOutOfBounds = sal_True;
+ }
+ }
+ }
+ else
+ {
+ nTmpPos = nDefaultDir == UBIDI_LTR ? nPos - 1 : 0;
+ }
+
+ if ( ! bOutOfBounds )
+ {
+ nPos = (xub_StrLen)ubidi_getLogicalIndex( pBidi, nTmpPos, &nError );
+
+ if ( bForward )
+ {
+ if ( nPos )
+ --nPos;
+ else
+ {
+ ++nPos;
+ bForward = ! bForward;
+ }
+ }
+ else
+ ++nPos;
+ }
+
+ ubidi_close( pBidi );
+}
+
+/*************************************************************************
+ * SwTxtFrm::_UnitDown()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::_UnitDown(SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+
+ if ( IsInTab() &&
+ pPam->GetNode( sal_True )->StartOfSectionNode() !=
+ pPam->GetNode( sal_False )->StartOfSectionNode() )
+ {
+ //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
+ //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
+ return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
+ }
+ ((SwTxtFrm*)this)->GetFormatted();
+ const xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
+ SwRect aCharBox;
+ const SwCntntFrm *pTmpFollow = 0;
+
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+
+ if ( !IsEmpty() && !IsHiddenNow() )
+ {
+ xub_StrLen nFormat = STRING_LEN;
+ do
+ {
+ if( nFormat != STRING_LEN && !IsFollow() &&
+ !lcl_ChangeOffset( ((SwTxtFrm*)this), nFormat ) )
+ break;
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+ nFormat = aLine.GetEnd();
+
+ aLine.CharCrsrToLine( nPos );
+
+ const SwLineLayout* pNextLine = aLine.GetNextLine();
+ const xub_StrLen nStart = aLine.GetStart();
+ aLine.GetCharRect( &aCharBox, nPos );
+
+ sal_Bool bFirstOfDouble = ( aInf.IsMulti() && aInf.IsFirstMulti() );
+
+ if( pNextLine || bFirstOfDouble )
+ {
+ aCharBox.SSize().Width() /= 2;
+#ifdef DBG_UTIL
+ // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
+ const ULONG nOldNode = pPam->GetPoint()->nNode.GetIndex();
+#endif
+ if ( pNextLine && ! bFirstOfDouble )
+ aLine.NextLine();
+
+ xub_StrLen nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
+ aCharBox.Pos(), sal_False );
+ ASSERT( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
+ "SwTxtFrm::UnitDown: illegal node change" )
+
+ // 7684: Wir stellen sicher, dass wir uns nach unten bewegen.
+ if( nTmpOfst <= nStart && ! bFirstOfDouble )
+ nTmpOfst = nStart + 1;
+ pPam->GetPoint()->nContent =
+ SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
+
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+
+ return sal_True;
+ }
+ if( 0 != ( pTmpFollow = GetFollow() ) )
+ { // geschuetzte Follows auslassen
+ const SwCntntFrm* pTmp = pTmpFollow;
+ ViewShell *pSh = GetShell();
+ if( !pSh || !pSh->GetViewOptions()->IsCursorInProtectedArea() )
+ {
+ while( pTmpFollow && pTmpFollow->IsProtected() )
+ {
+ pTmp = pTmpFollow;
+ pTmpFollow = pTmpFollow->GetFollow();
+ }
+ }
+ if( !pTmpFollow ) // nur noch geschuetzte
+ {
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+ return pTmp->SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
+ }
+
+ aLine.GetCharRect( &aCharBox, nPos );
+ aCharBox.SSize().Width() /= 2;
+ }
+ else if( !IsFollow() )
+ {
+ xub_StrLen nTmpLen = aInf.GetTxt().Len();
+ if( aLine.GetEnd() < nTmpLen )
+ {
+ if( nFormat <= GetOfst() )
+ {
+ nFormat = Min( xub_StrLen( GetOfst() + MIN_OFFSET_STEP ),
+ nTmpLen );
+ if( nFormat <= GetOfst() )
+ break;
+ }
+ continue;
+ }
+ }
+ break;
+ } while( sal_True );
+ }
+ else
+ pTmpFollow = GetFollow();
+
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+
+ // Bei Follows schlagen wir eine Abkuerzung
+ if( pTmpFollow )
+ {
+ aCharBox.Pos().Y() = pTmpFollow->Frm().Top() + 1;
+ return ((SwTxtFrm*)pTmpFollow)->GetKeyCrsrOfst( pPam->GetPoint(),
+ aCharBox.Pos() );
+ }
+ return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
+}
+
+/*************************************************************************
+ * virtual SwTxtFrm::UnitUp()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::UnitUp(SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+ /* Im CrsrSh::Up() wird CntntNode::GetFrm() gerufen.
+ * Dies liefert _immer_ den Master zurueck.
+ * Um das Cursortravelling nicht zu belasten, korrigieren wir
+ * hier im SwTxtFrm.
+ * Wir ermittelt UnitUp fuer pFrm, pFrm ist entweder ein Master (=this)
+ * oder ein Follow (!=this)
+ */
+ const SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *(pPam->GetPoint()),
+ SwTxtCursor::IsRightMargin() );
+ const sal_Bool bRet = pFrm->_UnitUp( pPam, nOffset, bSetInReadOnly );
+
+ // 8626: kein SwTxtCursor::SetRightMargin( sal_False );
+ // statt dessen steht ein SwSetToRightMargin im _UnitUp
+ return bRet;
+}
+
+/*************************************************************************
+ * virtual SwTxtFrm::UnitDown()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::UnitDown(SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+ const SwTxtFrm *pFrm = GetAdjFrmAtPos((SwTxtFrm*)this, *(pPam->GetPoint()),
+ SwTxtCursor::IsRightMargin() );
+ const sal_Bool bRet = pFrm->_UnitDown( pPam, nOffset, bSetInReadOnly );
+ SwTxtCursor::SetRightMargin( sal_False );
+ return bRet;
+}
+
+void SwTxtFrm::FillCrsrPos( SwFillData& rFill ) const
+{
+ if( !rFill.bColumn && GetUpper()->IsColBodyFrm() ) // ColumnFrms jetzt mit BodyFrm
+ {
+ const SwColumnFrm* pTmp =
+ (SwColumnFrm*)GetUpper()->GetUpper()->GetUpper()->Lower(); // die 1. Spalte
+ // der erste SwFrm im BodyFrm der ersten Spalte
+ const SwFrm* pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
+ MSHORT nNextCol = 0;
+ // In welcher Spalte landen wir?
+ while( rFill.X() > pTmp->Frm().Right() && pTmp->GetNext() )
+ {
+ pTmp = (SwColumnFrm*)pTmp->GetNext();
+ if( ((SwLayoutFrm*)pTmp->Lower())->Lower() ) // ColumnFrms jetzt mit BodyFrm
+ {
+ pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
+ nNextCol = 0;
+ }
+ else
+ ++nNextCol; // leere Spalten erfordern Spaltenumbrueche
+ }
+ if( pTmp != GetUpper()->GetUpper() ) // Sind wir in einer anderen Spalte gelandet?
+ {
+ if( !pFrm )
+ return;
+ if( nNextCol )
+ {
+ while( pFrm->GetNext() )
+ pFrm = pFrm->GetNext();
+ }
+ else
+ {
+ while( pFrm->GetNext() && pFrm->Frm().Bottom() < rFill.Y() )
+ pFrm = pFrm->GetNext();
+ }
+ // Kein Fuellen, wenn als letzter Frame in der anvisierten
+ // Spalte kein Absatz, sondern z.B. eine Tabelle steht
+ if( pFrm->IsTxtFrm() )
+ {
+ rFill.Fill().nColumnCnt = nNextCol;
+ rFill.bColumn = sal_True;
+ if( rFill.pPos )
+ {
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)pFrm)->GetTxtNode();
+ rFill.pPos->nNode = *pTxtNd;
+ rFill.pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
+ }
+ if( nNextCol )
+ {
+ rFill.aFrm = pTmp->Prt();
+ rFill.aFrm += pTmp->Frm().Pos();
+ }
+ else
+ rFill.aFrm = pFrm->Frm();
+ ((SwTxtFrm*)pFrm)->FillCrsrPos( rFill );
+ }
+ return;
+ }
+ }
+ sal_Bool bFill = sal_True;
+ SwFont *pFnt;
+ SwTxtFmtColl* pColl = GetTxtNode()->GetTxtColl();
+ MSHORT nFirst = GetTxtNode()->GetSwAttrSet().GetULSpace().GetLower();
+ SwTwips nDiff = rFill.Y() - Frm().Bottom();
+ if( nDiff < nFirst )
+ nDiff = -1;
+ else
+ pColl = &pColl->GetNextTxtFmtColl();
+ SwAttrSet aSet( ((SwDoc*)GetTxtNode()->GetDoc())->GetAttrPool(), aTxtFmtCollSetRange );
+ const SwAttrSet* pSet = &pColl->GetAttrSet();
+ ViewShell *pSh = GetShell();
+ if( GetTxtNode()->HasSwAttrSet() )
+ {
+ aSet.Put( *GetTxtNode()->GetpSwAttrSet() );
+ aSet.SetParent( pSet );
+ pSet = &aSet;
+ pFnt = new SwFont( pSet, GetNode()->getIDocumentSettingAccess() );
+ }
+ else
+ {
+ SwFontAccess aFontAccess( pColl, pSh );
+ pFnt = new SwFont( *aFontAccess.Get()->GetFont() );
+ pFnt->ChkMagic( pSh, pFnt->GetActual() );
+ }
+ OutputDevice* pOut = pSh->GetOut();
+ if ( !GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ||
+ ( pSh->GetViewOptions()->IsPrtFormat() ) )
+ pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
+
+ pFnt->SetFntChg( sal_True );
+ pFnt->ChgPhysFnt( pSh, *pOut );
+
+ SwTwips nLineHeight = pFnt->GetHeight( pSh, *pOut );
+
+ if( nLineHeight )
+ {
+ const SvxULSpaceItem &rUL = pSet->GetULSpace();
+ SwTwips nDist = Max( rUL.GetLower(), rUL.GetUpper() );
+ if( rFill.Fill().nColumnCnt )
+ {
+ rFill.aFrm.Height( nLineHeight );
+ nDiff = rFill.Y() - rFill.Bottom();
+ nFirst = 0;
+ }
+ else if( nDist < nFirst )
+ nFirst = nFirst - (USHORT)nDist;
+ else
+ nFirst = 0;
+ nDist = Max( nDist, long( GetLineSpace() ) );
+ nDist += nLineHeight;
+ nDiff -= nFirst;
+
+ if( nDiff > 0 )
+ {
+ nDiff /= nDist;
+ rFill.Fill().nParaCnt = static_cast<USHORT>(nDiff + 1);
+ rFill.nLineWidth = 0;
+ rFill.bInner = sal_False;
+ rFill.bEmpty = sal_True;
+ rFill.SetOrient( text::HoriOrientation::LEFT );
+ }
+ else
+ nDiff = -1;
+ if( rFill.bInner )
+ bFill = sal_False;
+ else
+ {
+ const SvxTabStopItem &rRuler = pSet->GetTabStops();
+ const SvxLRSpaceItem &rLRSpace = pSet->GetLRSpace();
+
+ SwRect &rRect = rFill.Fill().aCrsr;
+ rRect.Top( rFill.Bottom() + (nDiff+1) * nDist - nLineHeight );
+ if( nFirst && nDiff > -1 )
+ rRect.Top( rRect.Top() + nFirst );
+ rRect.Height( nLineHeight );
+ SwTwips nLeft = rFill.Left() + rLRSpace.GetLeft() +
+ GetTxtNode()->GetLeftMarginWithNum( sal_False );
+ SwTwips nRight = rFill.Right() - rLRSpace.GetRight();
+ SwTwips nCenter = ( nLeft + nRight ) / 2;
+ rRect.Left( nLeft );
+ if( FILL_MARGIN == rFill.Mode() )
+ {
+ if( rFill.bEmpty )
+ {
+ rFill.SetOrient( text::HoriOrientation::LEFT );
+ if( rFill.X() < nCenter )
+ {
+ if( rFill.X() > ( nLeft + 2 * nCenter ) / 3 )
+ {
+ rFill.SetOrient( text::HoriOrientation::CENTER );
+ rRect.Left( nCenter );
+ }
+ }
+ else if( rFill.X() > ( nRight + 2 * nCenter ) / 3 )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ }
+ else
+ {
+ rFill.SetOrient( text::HoriOrientation::CENTER );
+ rRect.Left( nCenter );
+ }
+ }
+ else
+ bFill = sal_False;
+ }
+ else
+ {
+ SwTwips nSpace = 0;
+ if( FILL_TAB != rFill.Mode() )
+ {
+static sal_Char __READONLY_DATA sDoubleSpace[] = " ";
+ const XubString aTmp( sDoubleSpace, RTL_TEXTENCODING_MS_1252 );
+
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTmp, 0, 2 );
+ nSpace = pFnt->_GetTxtSize( aDrawInf ).Width()/2;
+ }
+ if( rFill.X() >= nRight )
+ {
+ if( FILL_INDENT != rFill.Mode() && ( rFill.bEmpty ||
+ rFill.X() > rFill.nLineWidth + FILL_MIN_DIST ) )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ }
+ else
+ bFill = sal_False;
+ }
+ else if( FILL_INDENT == rFill.Mode() )
+ {
+ SwTwips nIndent = rFill.X();
+ if( !rFill.bEmpty || nIndent > nRight )
+ bFill = sal_False;
+ else
+ {
+ nIndent -= rFill.Left();
+ if( nIndent >= 0 && nSpace )
+ {
+ nIndent /= nSpace;
+ nIndent *= nSpace;
+ rFill.SetTab( MSHORT( nIndent ) );
+ rRect.Left( nIndent + rFill.Left() );
+ }
+ else
+ bFill = sal_False;
+ }
+ }
+ else if( rFill.X() > nLeft )
+ {
+ SwTwips nTxtLeft = rFill.Left() + rLRSpace.GetTxtLeft() +
+ GetTxtNode()->GetLeftMarginWithNum( sal_True );
+ rFill.nLineWidth += rFill.bFirstLine ? nLeft : nTxtLeft;
+ SwTwips nLeftTab = nLeft;
+ SwTwips nRightTab = nLeft;
+ MSHORT nSpaceCnt = 0;
+ MSHORT nTabCnt = 0;
+ MSHORT nIdx = 0;
+ do
+ {
+ nLeftTab = nRightTab;
+ if( nIdx < rRuler.Count() )
+ {
+ const SvxTabStop &rTabStop = rRuler.operator[](nIdx);
+ nRightTab = nTxtLeft + rTabStop.GetTabPos();
+ if( nLeftTab < nTxtLeft && nRightTab > nTxtLeft )
+ nRightTab = nTxtLeft;
+ else
+ ++nIdx;
+ if( nRightTab > rFill.nLineWidth )
+ ++nTabCnt;
+ }
+ else
+ {
+ const SvxTabStopItem& rTab =
+ (const SvxTabStopItem &)pSet->
+ GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
+ MSHORT nDefTabDist = (MSHORT)rTab.GetStart()->GetTabPos();
+ nRightTab = nLeftTab - nTxtLeft;
+ nRightTab /= nDefTabDist;
+ nRightTab = nRightTab * nDefTabDist + nTxtLeft;
+ while ( nRightTab <= nLeftTab )
+ nRightTab += nDefTabDist;
+ if( nRightTab > rFill.nLineWidth )
+ ++nTabCnt;
+ while ( nRightTab < rFill.X() )
+ {
+ nRightTab += nDefTabDist;
+ if( nRightTab > rFill.nLineWidth )
+ ++nTabCnt;
+ }
+ if( nLeftTab < nRightTab - nDefTabDist )
+ nLeftTab = nRightTab - nDefTabDist;
+ }
+ if( nRightTab > nRight )
+ nRightTab = nRight;
+ }
+ while( rFill.X() > nRightTab );
+ --nTabCnt;
+ if( FILL_TAB != rFill.Mode() )
+ {
+ if( nSpace > 0 )
+ {
+ if( !nTabCnt )
+ nLeftTab = rFill.nLineWidth;
+ while( nLeftTab < rFill.X() )
+ {
+ nLeftTab += nSpace;
+ ++nSpaceCnt;
+ }
+ if( nSpaceCnt )
+ {
+ nLeftTab -= nSpace;
+ --nSpaceCnt;
+ }
+ if( rFill.X() - nLeftTab > nRightTab - rFill.X() )
+ {
+ nSpaceCnt = 0;
+ ++nTabCnt;
+ rRect.Left( nRightTab );
+ }
+ else
+ {
+ if( rFill.X() - nLeftTab > nSpace/2 )
+ {
+ ++nSpaceCnt;
+ rRect.Left( nLeftTab + nSpace );
+ }
+ else
+ rRect.Left( nLeftTab );
+ }
+ }
+ else if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
+ rRect.Left( nLeftTab );
+ else
+ {
+ if( nRightTab >= nRight )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ nTabCnt = 0;
+ nSpaceCnt = 0;
+ }
+ else
+ {
+ rRect.Left( nRightTab );
+ ++nTabCnt;
+ }
+ }
+ }
+ else
+ {
+ if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
+ rRect.Left( nLeftTab );
+ else
+ {
+ if( nRightTab >= nRight )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ nTabCnt = 0;
+ nSpaceCnt = 0;
+ }
+ else
+ {
+ rRect.Left( nRightTab );
+ ++nTabCnt;
+ }
+ }
+ }
+ rFill.SetTab( nTabCnt );
+ rFill.SetSpace( nSpaceCnt );
+ if( bFill )
+ {
+ if( Abs( rFill.X() - nCenter ) <=
+ Abs( rFill.X() - rRect.Left() ) )
+ {
+ rFill.SetOrient( text::HoriOrientation::CENTER );
+ rFill.SetTab( 0 );
+ rFill.SetSpace( 0 );
+ rRect.Left( nCenter );
+ }
+ if( !rFill.bEmpty )
+ rFill.nLineWidth += FILL_MIN_DIST;
+ if( rRect.Left() < rFill.nLineWidth )
+ bFill = sal_False;
+ }
+ }
+ }
+ // Gehen wir ueber die Unterkante der Seite/Spalte etc. hinaus?
+ const SwFrm* pUp = GetUpper();
+ if( pUp->IsInSct() )
+ {
+ if( pUp->IsSctFrm() )
+ pUp = pUp->GetUpper();
+ else if( pUp->IsColBodyFrm() &&
+ pUp->GetUpper()->GetUpper()->IsSctFrm() )
+ pUp = pUp->GetUpper()->GetUpper()->GetUpper();
+ }
+ SWRECTFN( this )
+ SwTwips nLimit = (pUp->*fnRect->fnGetPrtBottom)();
+ SwTwips nRectBottom = rRect.Bottom();
+ if ( bVert )
+ nRectBottom = SwitchHorizontalToVertical( nRectBottom );
+
+ if( (*fnRect->fnYDiff)( nLimit, nRectBottom ) < 0 )
+ bFill = sal_False;
+ else
+ rRect.Width( 1 );
+ }
+ }
+ else
+ bFill = sal_False;
+ ((SwCrsrMoveState*)rFill.pCMS)->bFillRet = bFill;
+ delete pFnt;
+}
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
new file mode 100644
index 000000000000..be9c84cc88af
--- /dev/null
+++ b/sw/source/core/text/frmform.cxx
@@ -0,0 +1,2173 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+#include <editeng/keepitem.hxx>
+#include <editeng/hyznitem.hxx>
+#include <pagefrm.hxx> // ChangeFtnRef
+#include <ndtxt.hxx> // MakeFrm()
+#include <dcontact.hxx> // SwDrawContact
+#include <dflyobj.hxx> // SwVirtFlyDrawObj
+#include <flyfrm.hxx>
+#include <ftnfrm.hxx> // SwFtnFrm
+#include <txtftn.hxx>
+#include <fmtftn.hxx>
+#include <paratr.hxx>
+#include <viewopt.hxx> // SwViewOptions
+#include <viewsh.hxx> // ViewShell
+#include <frmatr.hxx>
+#include <pam.hxx>
+#include <flyfrms.hxx>
+#include <fmtanchr.hxx>
+#include <txtcfg.hxx>
+#include <itrform2.hxx> // SwTxtFormatter
+#include <widorp.hxx> // Widows and Orphans
+#include <txtcache.hxx>
+#include <porrst.hxx> // SwEmptyPortion
+#include <blink.hxx> // pBlink
+#include <porfld.hxx> // SwFldPortion
+#include <sectfrm.hxx> // SwSectionFrm
+#include <pormulti.hxx> // SwMultiPortion
+
+#include <rootfrm.hxx>
+#include <frmfmt.hxx> // SwFrmFmt
+// OD 2004-05-24 #i28701#
+#include <sortedobjs.hxx>
+
+class FormatLevel
+{
+ static MSHORT nLevel;
+public:
+ inline FormatLevel() { ++nLevel; }
+ inline ~FormatLevel() { --nLevel; }
+ inline MSHORT GetLevel() const { return nLevel; }
+ static sal_Bool LastLevel() { return 10 < nLevel; }
+};
+MSHORT FormatLevel::nLevel = 0;
+
+/*************************************************************************
+ * ValidateTxt/Frm()
+ *************************************************************************/
+
+void ValidateTxt( SwFrm *pFrm ) // Freund vom Frame
+{
+ if ( ( ! pFrm->IsVertical() &&
+ pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
+ pFrm->IsVertical() &&
+ pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() )
+ pFrm->bValidSize = sal_True;
+/*
+ pFrm->bValidPrtArea = sal_True;
+ //Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren.
+ //Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate
+ //validiert werden.
+ if ( !pFrm->bValidPos )
+ {
+ //Leider muessen wir dazu die korrekte Position berechnen.
+ Point aOld( pFrm->Frm().Pos() );
+ pFrm->MakePos();
+ if ( aOld != pFrm->Pos() )
+ {
+ pFrm->Frm().Pos( aOld );
+ pFrm->bValidPos = sal_False;
+ }
+ }
+*/
+}
+
+void SwTxtFrm::ValidateFrm()
+{
+ // Umgebung validieren, um Oszillationen zu verhindern.
+ SWAP_IF_SWAPPED( this )
+
+ if ( !IsInFly() && !IsInTab() )
+ { //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich
+ //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von
+ //Flys nicht. Fix fuer 5544
+ SwSectionFrm* pSct = FindSctFrm();
+ if( pSct )
+ {
+ if( !pSct->IsColLocked() )
+ pSct->ColLock();
+ else
+ pSct = NULL;
+ }
+
+ SwFrm *pUp = GetUpper();
+ pUp->Calc();
+ if( pSct )
+ pSct->ColUnlock();
+ }
+ ValidateTxt( this );
+
+ //MA: mindestens das MustFit-Flag muessen wir retten!
+ ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." );
+ SwParaPortion *pPara = GetPara();
+ const sal_Bool bMustFit = pPara->IsPrepMustFit();
+ ResetPreps();
+ pPara->SetPrepMustFit( bMustFit );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * ValidateBodyFrm()
+ *************************************************************************/
+
+// nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert
+// werden, damit die DeadLine richtig sitzt.
+// Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert.
+
+void _ValidateBodyFrm( SwFrm *pFrm )
+{
+ if( pFrm && !pFrm->IsCellFrm() )
+ {
+ if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
+ _ValidateBodyFrm( pFrm->GetUpper() );
+ if( !pFrm->IsSctFrm() )
+ pFrm->Calc();
+ else
+ {
+ sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
+ ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
+ pFrm->Calc();
+ if( !bOld )
+ ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
+ }
+ }
+}
+
+void SwTxtFrm::ValidateBodyFrm()
+{
+ SWAP_IF_SWAPPED( this )
+
+ //siehe Kommtar in ValidateFrm()
+ if ( !IsInFly() && !IsInTab() &&
+ !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
+ _ValidateBodyFrm( GetUpper() );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindBodyFrm()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
+{
+ SWAP_IF_NOT_SWAPPED( this )
+
+ ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
+ if( aLine.GetDropLines() )
+ {
+ rRect.Top( aLine.Y() );
+ rRect.Left( aLine.GetLineStart() );
+ rRect.Height( aLine.GetDropHeight() );
+ rRect.Width( aLine.GetDropLeft() );
+
+ if ( IsRightToLeft() )
+ SwitchLTRtoRTL( rRect );
+
+ if ( IsVertical() )
+ SwitchHorizontalToVertical( rRect );
+ UNDO_SWAP( this )
+ return sal_True;
+ }
+
+ UNDO_SWAP( this )
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindBodyFrm()
+ *************************************************************************/
+
+const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
+{
+ if ( IsInDocBody() )
+ {
+ const SwFrm *pFrm = GetUpper();
+ while( pFrm && !pFrm->IsBodyFrm() )
+ pFrm = pFrm->GetUpper();
+ return (const SwBodyFrm*)pFrm;
+ }
+ return 0;
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcFollow()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
+{
+ SWAP_IF_SWAPPED( this )
+
+ ASSERT( HasFollow(), "CalcFollow: missing Follow." );
+
+ SwTxtFrm* pMyFollow = GetFollow();
+
+ SwParaPortion *pPara = GetPara();
+ sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;
+
+ if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
+ bFollowFld || pMyFollow->IsFieldFollow() ||
+ ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
+ ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
+ {
+#ifdef DBG_UTIL
+ const SwFrm *pOldUp = GetUpper();
+#endif
+
+ SWRECTFN ( this )
+ SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
+ SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();
+
+ const SwPageFrm *pPage = 0;
+ sal_Bool bOldInvaCntnt = sal_True;
+ if ( !IsInFly() && GetNext() )
+ {
+ pPage = FindPageFrm();
+ //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u.
+ bOldInvaCntnt = pPage->IsInvalidCntnt();
+ }
+
+ pMyFollow->_SetOfst( nTxtOfst );
+ pMyFollow->SetFieldFollow( bFollowFld );
+ if( HasFtn() || pMyFollow->HasFtn() )
+ {
+ ValidateFrm();
+ ValidateBodyFrm();
+ if( pPara )
+ {
+ *(pPara->GetReformat()) = SwCharRange();
+ *(pPara->GetDelta()) = 0;
+ }
+ }
+
+ //Der Fussnotenbereich darf sich keinesfalls vergrossern.
+ SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );
+
+ pMyFollow->CalcFtnFlag();
+ if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
+ nOldBottom = bVert ? 0 : LONG_MAX;
+
+ while( sal_True )
+ {
+ if( !FormatLevel::LastLevel() )
+ {
+ // Weenn der Follow in einem spaltigen Bereich oder einem
+ // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert
+ // werden, da das FormatWidthCols() nicht funktioniert, wenn
+ // es aus dem MakeAll des _gelockten_ Follows heraus gerufen
+ // wird.
+ SwSectionFrm* pSct = pMyFollow->FindSctFrm();
+ if( pSct && !pSct->IsAnLower( this ) )
+ {
+ if( pSct->GetFollow() )
+ pSct->SimpleFormat();
+ else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
+ ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
+ break;
+ }
+ // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
+ if ( FollowFormatAllowed() )
+ {
+ // OD 14.03.2003 #i11760# - no nested format of follows, if
+ // text frame is contained in a column frame.
+ // Thus, forbid intrinsic format of follow.
+ {
+ bool bIsFollowInColumn = false;
+ SwFrm* pFollowUpper = pMyFollow->GetUpper();
+ while ( pFollowUpper )
+ {
+ if ( pFollowUpper->IsColumnFrm() )
+ {
+ bIsFollowInColumn = true;
+ break;
+ }
+ if ( pFollowUpper->IsPageFrm() ||
+ pFollowUpper->IsFlyFrm() )
+ {
+ break;
+ }
+ pFollowUpper = pFollowUpper->GetUpper();
+ }
+ if ( bIsFollowInColumn )
+ {
+ pMyFollow->ForbidFollowFormat();
+ }
+ }
+
+ pMyFollow->Calc();
+ // Der Follow merkt anhand seiner Frm().Height(), dass was schief
+ // gelaufen ist.
+ ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
+ if( pMyFollow->GetPrev() )
+ {
+ pMyFollow->Prepare( PREP_CLEAR );
+ pMyFollow->Calc();
+ ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
+ }
+
+ // OD 14.03.2003 #i11760# - reset control flag for follow format.
+ pMyFollow->AllowFollowFormat();
+ }
+
+ //Sicherstellen, dass der Follow gepaintet wird.
+ pMyFollow->SetCompletePaint();
+ }
+
+ pPara = GetPara();
+ //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er
+ //diese und wird erneut formatiert, falls moeglich.
+ if( pPara && pPara->IsPrepWidows() )
+ CalcPreps();
+ else
+ break;
+ }
+
+ if( HasFtn() || pMyFollow->HasFtn() )
+ {
+ ValidateBodyFrm();
+ ValidateFrm();
+ if( pPara )
+ {
+ *(pPara->GetReformat()) = SwCharRange();
+ *(pPara->GetDelta()) = 0;
+ }
+ }
+
+ if ( pPage )
+ {
+ if ( !bOldInvaCntnt )
+ pPage->ValidateCntnt();
+ }
+
+#ifdef DBG_UTIL
+ ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
+#endif
+
+ const long nRemaining =
+ - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
+ if ( nRemaining > 0 && !GetUpper()->IsSctFrm() &&
+ nRemaining != ( bVert ?
+ nMyPos - Frm().Right() :
+ Frm().Top() - nMyPos ) )
+ {
+ UNDO_SWAP( this )
+ return sal_True;
+ }
+ }
+
+ UNDO_SWAP( this )
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtFrm::AdjustFrm()
+ *************************************************************************/
+
+void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
+{
+ if( IsUndersized() )
+ {
+ if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized)
+ return;
+ SetUndersized( nChgHght == 0 || bHasToFit );
+ }
+
+ // AdjustFrm is called with a swapped frame during
+ // formatting but the frame is not swapped during FormatEmpty
+ SWAP_IF_SWAPPED( this )
+ SWRECTFN ( this )
+
+ // Die Size-Variable des Frames wird durch Grow inkrementiert
+ // oder durch Shrink dekrementiert. Wenn die Groesse
+ // unveraendert ist, soll nichts passieren!
+ if( nChgHght >= 0)
+ {
+ SwTwips nChgHeight = nChgHght;
+ if( nChgHght && !bHasToFit )
+ {
+ if( IsInFtn() && !IsInSct() )
+ {
+ SwTwips nReal = Grow( nChgHght, sal_True );
+ if( nReal < nChgHght )
+ {
+ SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
+ nChgHght - nReal );
+ SwFrm* pCont = FindFtnFrm()->GetUpper();
+
+ if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
+ {
+ (Frm().*fnRect->fnAddBottom)( nChgHght );
+ if( bVert )
+ Prt().SSize().Width() += nChgHght;
+ else
+ Prt().SSize().Height() += nChgHght;
+ UNDO_SWAP( this )
+ return;
+ }
+ }
+ }
+
+ Grow( nChgHght );
+
+ if ( IsInFly() )
+ {
+ //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es
+ //sehr wahrscheinlich, dass dieser Fly durch das Grow seine
+ //Position veraendert - also muss auch meine Position korrigiert
+ //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig).
+ //Die Vorgaenger muessen berechnet werden, damit die Position
+ //korrekt berechnet werden kann.
+ if ( GetPrev() )
+ {
+ SwFrm *pPre = GetUpper()->Lower();
+ do
+ { pPre->Calc();
+ pPre = pPre->GetNext();
+ } while ( pPre && pPre != this );
+ }
+ const Point aOldPos( Frm().Pos() );
+ MakePos();
+ if ( aOldPos != Frm().Pos() )
+ {
+ // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
+ // No format is performed for the floating screen objects.
+ InvalidateObjs( true );
+ }
+ }
+ nChgHeight = 0;
+ }
+ // Ein Grow() wird von der Layout-Seite immer akzeptiert,
+ // also auch, wenn die FixSize des umgebenden Layoutframes
+ // dies nicht zulassen sollte. Wir ueberpruefen diesen
+ // Fall und korrigieren die Werte.
+ // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht
+ // weiter geschrumpft werden als es seine Groesse zulaesst.
+ SwTwips nRstHeight;
+ if ( IsVertical() )
+ {
+ ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
+ nRstHeight = Frm().Left() + Frm().Width() -
+ ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
+ }
+ else
+ nRstHeight = GetUpper()->Frm().Top()
+ + GetUpper()->Prt().Top()
+ + GetUpper()->Prt().Height()
+ - Frm().Top();
+
+ //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil
+ //durch eine vertikale Ausrichtung auch oben noch Raum sein kann.
+ // --> OD 2004-11-25 #115759# - assure, that first lower in upper
+ // is the current one or is valid.
+ if ( IsInTab() &&
+ ( GetUpper()->Lower() == this ||
+ GetUpper()->Lower()->IsValid() ) )
+ // <--
+ {
+ long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
+ (GetUpper()->*fnRect->fnGetPrtTop)() );
+ ASSERT( nAdd >= 0, "Ey" );
+ nRstHeight += nAdd;
+ }
+
+/* ------------------------------------
+ * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines
+ * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der
+ * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der
+ * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur
+ * Endlosschleife.
+ * -----------------------------------*/
+ SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
+ SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
+
+ if( nRstHeight < nFrmHeight )
+ {
+ //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu
+ //klein ist und der Upper noch Platz schaffen kann.
+ if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
+ nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
+ // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit
+ // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen
+ // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige
+ // Spaltengroesse ermitteln kann.
+ if ( nRstHeight < nFrmHeight )
+ {
+ if( bHasToFit || !IsMoveable() ||
+ ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
+ {
+ SetUndersized( sal_True );
+ Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
+ }
+ else
+ SetUndersized( sal_False );
+ }
+ }
+ else if( nChgHeight )
+ {
+ if( nRstHeight - nFrmHeight < nChgHeight )
+ nChgHeight = nRstHeight - nFrmHeight;
+ if( nChgHeight )
+ Grow( nChgHeight );
+ }
+ }
+ else
+ Shrink( -nChgHght );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::AdjustFollow()
+ *************************************************************************/
+
+/* AdjustFollow erwartet folgende Situation:
+ * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird
+ * im Follow eingestellt.
+ * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst
+ * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht.
+ */
+
+void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
+ const xub_StrLen nOffset, const xub_StrLen nEnd,
+ const sal_uInt8 nMode )
+{
+ SwFrmSwapper aSwapper( this, sal_False );
+
+ // Wir haben den Rest der Textmasse: alle Follows loeschen
+ // Sonderfall sind DummyPortions()
+ // - special cases are controlled by parameter <nMode>.
+ if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
+ {
+ while( GetFollow() )
+ {
+ if( ((SwTxtFrm*)GetFollow())->IsLocked() )
+ {
+ ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." );
+ return;
+ }
+ JoinFrm();
+ }
+
+ return;
+ }
+
+ // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal
+ // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich
+ // kann sich dadurch auch der Offset verschieben:
+ const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
+ rLine.FormatQuoVadis(nOffset) : nOffset;
+
+ if( !(nMode & 1) )
+ {
+ // Wir klauen unseren Follows Textmasse, dabei kann es passieren,
+ // dass wir einige Follows Joinen muessen.
+ while( GetFollow() && GetFollow()->GetFollow() &&
+ nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
+ {
+ DBG_LOOP;
+ JoinFrm();
+ }
+ }
+
+ // Der Ofst hat sich verschoben.
+ if( GetFollow() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ static sal_Bool bTest = sal_False;
+ if( !bTest || ( nMode & 1 ) )
+#endif
+ if ( nMode )
+ GetFollow()->ManipOfst( 0 );
+
+ if ( CalcFollow( nNewOfst ) ) // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst
+ rLine.SetOnceMore( sal_True );
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::JoinFrm()
+ *************************************************************************/
+
+SwCntntFrm *SwTxtFrm::JoinFrm()
+{
+ ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
+ SwTxtFrm *pFoll = GetFollow();
+
+ SwTxtFrm *pNxt = pFoll->GetFollow();
+
+ // Alle Fussnoten des zu zerstoerenden Follows werden auf uns
+ // umgehaengt.
+ xub_StrLen nStart = pFoll->GetOfst();
+ if ( pFoll->HasFtn() )
+ {
+ const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
+ if( pHints )
+ {
+ SwFtnBossFrm *pFtnBoss = 0;
+ SwFtnBossFrm *pEndBoss = 0;
+ for ( USHORT i = 0; i < pHints->Count(); ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
+ {
+ if( pHt->GetFtn().IsEndNote() )
+ {
+ if( !pEndBoss )
+ pEndBoss = pFoll->FindFtnBossFrm();
+ pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
+ }
+ else
+ {
+ if( !pFtnBoss )
+ pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
+ pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
+ }
+ SetFtn( sal_True );
+ }
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ else if ( pFoll->GetValidPrtAreaFlag() ||
+ pFoll->GetValidSizeFlag() )
+ {
+ pFoll->CalcFtnFlag();
+ ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." );
+ }
+#endif
+
+ pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
+ pFoll->SetFtn( FALSE );
+ // --> OD 2005-12-01 #i27138#
+ // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
+ // Relation CONTENT_FLOWS_FROM for current next paragraph will change
+ // and relation CONTENT_FLOWS_TO for current previous paragraph, which
+ // is <this>, will change.
+ {
+ ViewShell* pViewShell( pFoll->GetShell() );
+ if ( pViewShell && pViewShell->GetLayout() &&
+ pViewShell->GetLayout()->IsAnyShellAccessible() )
+ {
+ pViewShell->InvalidateAccessibleParaFlowRelation(
+ dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
+ this );
+ }
+ }
+ // <--
+ pFoll->Cut();
+ delete pFoll;
+ pFollow = pNxt;
+ return pNxt;
+}
+
+/*************************************************************************
+ * SwTxtFrm::SplitFrm()
+ *************************************************************************/
+
+SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
+{
+ SWAP_IF_SWAPPED( this )
+
+ // Durch das Paste wird ein Modify() an mich verschickt.
+ // Damit meine Daten nicht verschwinden, locke ich mich.
+ SwTxtFrmLocker aLock( this );
+ SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm());
+ pNew->bIsFollow = sal_True;
+
+ pNew->SetFollow( GetFollow() );
+ SetFollow( pNew );
+
+ pNew->Paste( GetUpper(), GetNext() );
+ // --> OD 2005-12-01 #i27138#
+ // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
+ // Relation CONTENT_FLOWS_FROM for current next paragraph will change
+ // and relation CONTENT_FLOWS_TO for current previous paragraph, which
+ // is <this>, will change.
+ {
+ ViewShell* pViewShell( pNew->GetShell() );
+ if ( pViewShell && pViewShell->GetLayout() &&
+ pViewShell->GetLayout()->IsAnyShellAccessible() )
+ {
+ pViewShell->InvalidateAccessibleParaFlowRelation(
+ dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
+ this );
+ }
+ }
+ // <--
+
+ // Wenn durch unsere Aktionen Fussnoten in pNew landen,
+ // so muessen sie umgemeldet werden.
+ if ( HasFtn() )
+ {
+ const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( pHints )
+ {
+ SwFtnBossFrm *pFtnBoss = 0;
+ SwFtnBossFrm *pEndBoss = 0;
+ for ( USHORT i = 0; i < pHints->Count(); ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
+ {
+ if( pHt->GetFtn().IsEndNote() )
+ {
+ if( !pEndBoss )
+ pEndBoss = FindFtnBossFrm();
+ pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
+ }
+ else
+ {
+ if( !pFtnBoss )
+ pFtnBoss = FindFtnBossFrm( sal_True );
+ pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
+ }
+ pNew->SetFtn( sal_True );
+ }
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ else
+ {
+ CalcFtnFlag( nTxtPos-1 );
+ ASSERT( !HasFtn(), "Missing FtnFlag." );
+ }
+#endif
+
+ MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );
+
+ // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt.
+
+ pNew->ManipOfst( nTxtPos );
+
+ UNDO_SWAP( this )
+ return pNew;
+}
+
+
+/*************************************************************************
+ * virtual SwTxtFrm::SetOfst()
+ *************************************************************************/
+
+void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
+{
+#ifdef DBGTXT
+ // Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0)
+ // zulaessig ist: bug 3496
+ ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." );
+#endif
+
+ // Die Invalidierung unseres Follows ist nicht noetig.
+ // Wir sind ein Follow, werden gleich formatiert und
+ // rufen von dort aus das SetOfst() !
+ nOfst = nNewOfst;
+ SwParaPortion *pPara = GetPara();
+ if( pPara )
+ {
+ SwCharRange &rReformat = *(pPara->GetReformat());
+ rReformat.Start() = 0;
+ rReformat.Len() = GetTxt().Len();
+ *(pPara->GetDelta()) = rReformat.Len();
+ }
+ InvalidateSize();
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcPreps
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::CalcPreps()
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
+ SWRECTFN( this );
+
+ SwParaPortion *pPara = GetPara();
+ if ( !pPara )
+ return sal_False;
+ sal_Bool bPrep = pPara->IsPrep();
+ sal_Bool bPrepWidows = pPara->IsPrepWidows();
+ sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
+ sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
+ ResetPreps();
+
+ sal_Bool bRet = sal_False;
+ if( bPrep && !pPara->GetReformat()->Len() )
+ {
+ // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel
+ // zuschlug.
+ // Es kann in unguenstigen Faellen vorkommen, dass auch ein
+ // PrepAdjust vorliegt (3680)!
+ if( bPrepWidows )
+ {
+ if( !GetFollow() )
+ {
+ ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
+ return sal_False;
+ }
+
+ // Wir muessen uns auf zwei Faelle einstellen:
+ // Wir konnten dem Follow noch ein paar Zeilen abgeben,
+ // -> dann muessen wir schrumpfen
+ // oder wir muessen auf die naechste Seite
+ // -> dann lassen wir unseren Frame zu gross werden.
+
+ SwTwips nChgHeight = GetParHeight();
+ if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
+ {
+ if( bPrepMustFit )
+ {
+ GetFollow()->SetJustWidow( sal_True );
+ GetFollow()->Prepare( PREP_CLEAR );
+ }
+ else if ( bVert )
+ {
+ Frm().Width( Frm().Width() + Frm().Left() );
+ Prt().Width( Prt().Width() + Frm().Left() );
+ Frm().Left( 0 );
+ SetWidow( sal_True );
+ }
+ else
+ {
+ SwTwips nTmp = LONG_MAX - (Frm().Top()+10000);
+ SwTwips nDiff = nTmp - Frm().Height();
+ Frm().Height( nTmp );
+ Prt().Height( Prt().Height() + nDiff );
+ SetWidow( sal_True );
+ }
+ }
+ else
+ {
+ ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
+ "+SwTxtFrm::CalcPrep: wanna shrink" );
+
+ nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;
+
+ GetFollow()->SetJustWidow( sal_True );
+ GetFollow()->Prepare( PREP_CLEAR );
+ Shrink( nChgHeight );
+ SwRect &rRepaint = *(pPara->GetRepaint());
+
+ if ( bVert )
+ {
+ SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+ SwitchVerticalToHorizontal( aRepaint );
+ rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
+ }
+ else
+ rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+
+ // 6792: Rrand < LRand und Repaint
+ if( 0 >= rRepaint.Width() )
+ rRepaint.Width(1);
+ }
+ bRet = sal_True;
+ }
+
+ else if ( bPrepAdjust )
+ {
+ if ( HasFtn() )
+ {
+ if( !CalcPrepFtnAdjust() )
+ {
+ if( bPrepMustFit )
+ {
+ SwTxtLineAccess aAccess( this );
+ aAccess.GetPara()->SetPrepMustFit( sal_True );
+ }
+ return sal_False;
+ }
+ }
+
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+
+ WidowsAndOrphans aFrmBreak( this );
+ // Egal was die Attribute meinen, bei MustFit wird
+ // der Absatz im Notfall trotzdem gesplittet...
+ if( bPrepMustFit )
+ {
+ aFrmBreak.SetKeep( sal_False );
+ aFrmBreak.ClrOrphLines();
+ }
+ // Bevor wir FormatAdjust aufrufen muessen wir dafuer
+ // sorgen, dass die Zeilen, die unten raushaengen
+ // auch tatsaechlich abgeschnitten werden.
+ // OD 2004-02-25 #i16128# - method renamed
+ sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
+ bRet = sal_True;
+ while( !bBreak && aLine.Next() )
+ {
+ // OD 2004-02-25 #i16128# - method renamed
+ bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
+ }
+ if( bBreak )
+ {
+ // Es gibt Komplikationen: wenn TruncLines gerufen wird,
+ // veraendern sich ploetzlich die Bedingungen in
+ // IsInside, so dass IsBreakNow andere Ergebnisse
+ // liefern kann. Aus diesem Grund wird rFrmBreak bekannt
+ // gegeben, dass da wo rLine steht, das Ende erreicht
+ // ist. Mal sehen, ob's klappt ...
+ aLine.TruncLines();
+ aFrmBreak.SetRstHeight( aLine );
+ FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
+ }
+ else
+ {
+ if( !GetFollow() )
+ {
+ FormatAdjust( aLine, aFrmBreak,
+ aInf.GetTxt().Len(), aInf.IsStop() );
+ }
+ else if ( !aFrmBreak.IsKeepAlways() )
+ {
+ // Siehe Bug: 2320
+ // Vor dem Master wird eine Zeile geloescht, der Follow
+ // koennte eine Zeile abgeben.
+ const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
+ *(pPara->GetReformat()) += aFollowRg;
+ // Es soll weitergehen!
+ bRet = sal_False;
+ }
+ }
+
+ UNDO_SWAP( this )
+ // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts
+ // brachte, muessen wir amputieren.
+ if( bPrepMustFit )
+ {
+ const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
+ const SwTwips nIs = (Frm().*fnRect->fnGetBottom)();
+
+ if( bVert && nIs < nMust )
+ {
+ Shrink( nMust - nIs );
+ if( Prt().Width() < 0 )
+ Prt().Width( 0 );
+ SetUndersized( sal_True );
+ }
+ else if ( ! bVert && nIs > nMust )
+ {
+ Shrink( nIs - nMust );
+ if( Prt().Height() < 0 )
+ Prt().Height( 0 );
+ SetUndersized( sal_True );
+ }
+ }
+ }
+ }
+ pPara->SetPrepMustFit( bPrepMustFit );
+ return bRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::FormatAdjust()
+ *************************************************************************/
+
+// Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt
+#define CHG_OFFSET( pFrm, nNew )\
+ {\
+ if( pFrm->GetOfst() < nNew )\
+ pFrm->MoveFlyInCnt( this, 0, nNew );\
+ else if( pFrm->GetOfst() > nNew )\
+ MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
+ }
+
+void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
+ WidowsAndOrphans &rFrmBreak,
+ const xub_StrLen nStrLen,
+ const sal_Bool bDummy )
+{
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+
+ xub_StrLen nEnd = rLine.GetStart();
+
+ sal_Bool bHasToFit = pPara->IsPrepMustFit();
+
+ // Das StopFlag wird durch Fussnoten gesetzt,
+ // die auf die naechste Seite wollen.
+ // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)>
+ // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
+ // even if due to widow rule no enough lines exists.
+ sal_uInt8 nNew = ( !GetFollow() &&
+ nEnd < nStrLen &&
+ ( rLine.IsStop() ||
+ ( bHasToFit
+ ? ( rLine.GetLineNr() > 1 &&
+ !rFrmBreak.IsInside( rLine ) )
+ : rFrmBreak.IsBreakNow( rLine ) ) ) )
+ ? 1 : 0;
+ if ( nNew )
+ SplitFrm( nEnd );
+
+ const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());
+
+ const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
+ pBodyFrm->Frm().Width() :
+ pBodyFrm->Frm().Height() ) : 0;
+
+ // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass
+ // sie jetzt gueltig sind.
+ *(pPara->GetReformat()) = SwCharRange();
+ sal_Bool bDelta = *pPara->GetDelta() != 0;
+ *(pPara->GetDelta()) = 0;
+
+ if( rLine.IsStop() )
+ {
+ rLine.TruncLines( sal_True );
+ nNew = 1;
+ }
+
+ // FindBreak schneidet die letzte Zeile ab.
+ if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
+ {
+ // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende
+ // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt.
+ // Ansonsten ist nEnd das Ende der letzten Zeile im Master.
+ xub_StrLen nOld = nEnd;
+ nEnd = rLine.GetEnd();
+ if( GetFollow() )
+ {
+ if( nNew && nOld < nEnd )
+ RemoveFtn( nOld, nEnd - nOld );
+ CHG_OFFSET( GetFollow(), nEnd )
+ if( !bDelta )
+ GetFollow()->ManipOfst( nEnd );
+ }
+ }
+ else
+ { // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden,
+ // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden.
+ // Dies muss auch geschehen, wenn die Textmasse komplett im Master
+ // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere
+ // Zeile (ohne Textmassse) notwendig machen!
+ nEnd = rLine.GetEnd();
+ if( GetFollow() )
+ {
+ // OD 21.03.2003 #108121# - Another case for not joining the follow:
+ // Text frame has no content, but a numbering. Then, do *not* join.
+ // Example of this case: When an empty, but numbered paragraph
+ // at the end of page is completely displaced by a fly frame.
+ // Thus, the text frame introduced a follow by a
+ // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
+ // the numbering and must stay.
+ if ( GetFollow()->GetOfst() != nEnd ||
+ GetFollow()->IsFieldFollow() ||
+ ( nStrLen == 0 && GetTxtNode()->GetNumRule())
+ )
+ {
+ nNew |= 3;
+ }
+ CHG_OFFSET( GetFollow(), nEnd )
+ GetFollow()->ManipOfst( nEnd );
+ }
+ else
+ {
+ // OD 21.03.2003 #108121# - Only split frame, if the frame contains
+ // content or contains no content, but has a numbering.
+ if ( nStrLen > 0 ||
+ ( nStrLen == 0 && GetTxtNode()->GetNumRule())
+ )
+ {
+ SplitFrm( nEnd );
+ nNew |= 3;
+ }
+ }
+ // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn()
+ // dann muessen wir auffuellen, um Oszillationen zu vermeiden!
+ if( bDummy && pBodyFrm &&
+ nBodyHeight < ( IsVertical() ?
+ pBodyFrm->Frm().Width() :
+ pBodyFrm->Frm().Height() ) )
+ rLine.MakeDummyLine();
+ }
+
+ // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein,
+ // in AdjustFollow() stellen wir unseren FolgeFrame ein.
+
+ const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
+ const SwTwips nOldHeight = Prt().SSize().Height();
+ const SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
+
+ // Vertical Formatting:
+ // The (rotated) repaint rectangle's x coordinate referes to the frame.
+ // If the frame grows (or shirks) the repaint rectangle cannot simply
+ // be rotated back after formatting, because we use the upper left point
+ // of the frame for rotation. This point changes when growing/shrinking.
+ if ( IsVertical() && nChg )
+ {
+ SwRect &rRepaint = *(pPara->GetRepaint());
+ rRepaint.Left( rRepaint.Left() - nChg );
+ rRepaint.Width( rRepaint.Width() - nChg );
+ }
+
+ AdjustFrm( nChg, bHasToFit );
+
+/*
+ // FME 16.07.2003 #i16930# - removed this code because it did not
+ // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the
+ // next page, instead the print area was recalculated and
+ // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, FALSE ) invalidated
+ // the other flags => loop
+
+ // OD 04.04.2003 #108446# - handle special case:
+ // If text frame contains no content and just has split, because of a
+ // line stop, it has to move forward. To force this forward move without
+ // unnecessary formatting of its footnotes and its follow, especially in
+ // columned sections, adjust frame height to zero (0) and do not perform
+ // the intrinsic format of the follow.
+ // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward.
+ sal_Bool bForcedNoIntrinsicFollowCalc = sal_False;
+ if ( nEnd == 0 &&
+ rLine.IsStop() && HasFollow() && nNew == 1
+ )
+ {
+ AdjustFrm( -Frm().SSize().Height(), bHasToFit );
+ Prt().Pos().Y() = 0;
+ Prt().Height( Frm().Height() );
+ if ( FollowFormatAllowed() )
+ {
+ bForcedNoIntrinsicFollowCalc = sal_True;
+ ForbidFollowFormat();
+ }
+ }
+ else
+ {
+ AdjustFrm( nChg, bHasToFit );
+ }
+ */
+
+ if( HasFollow() || IsInFtn() )
+ _AdjustFollow( rLine, nEnd, nStrLen, nNew );
+
+ // FME 16.07.2003 #i16930# - removed this code because it did not work
+ // correctly
+ // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above
+ // special case has forbit it.
+/* if ( bForcedNoIntrinsicFollowCalc )
+ {
+ AllowFollowFormat();
+ }
+ */
+
+ pPara->SetPrepMustFit( sal_False );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::FormatLine()
+ *************************************************************************/
+
+// bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde.
+// Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht.
+
+
+sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
+{
+ ASSERT( ! IsVertical() || IsSwapped(),
+ "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+ // Nach rLine.FormatLine() haelt nStart den neuen Wert,
+ // waehrend in pOldStart der alte Offset gepflegt wird.
+ // Ueber diesen Weg soll das nDelta ersetzt werden.
+ // *pOldStart += rLine.GetCurr()->GetLen();
+ const SwLineLayout *pOldCur = rLine.GetCurr();
+ const xub_StrLen nOldLen = pOldCur->GetLen();
+ const KSHORT nOldAscent = pOldCur->GetAscent();
+ const KSHORT nOldHeight = pOldCur->Height();
+ const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin();
+ const sal_Bool bOldHyph = pOldCur->IsEndHyph();
+ SwTwips nOldTop = 0;
+ SwTwips nOldBottom = 0;
+ if( rLine.GetCurr()->IsClipping() )
+ rLine.CalcUnclipped( nOldTop, nOldBottom );
+
+ const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );
+
+ ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
+ "SwTxtFrm::FormatLine: frame leaves orbit." );
+ ASSERT( rLine.GetCurr()->Height(),
+ "SwTxtFrm::FormatLine: line height is zero" );
+
+ // Das aktuelle Zeilenumbruchobjekt.
+ const SwLineLayout *pNew = rLine.GetCurr();
+
+ sal_Bool bUnChg = nOldLen == pNew->GetLen() &&
+ bOldHyph == pNew->IsEndHyph();
+ if ( bUnChg && !bPrev )
+ {
+ // 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922
+ const long nWidthDiff = nOldWidth > pNew->Width()
+ ? nOldWidth - pNew->Width()
+ : pNew->Width() - nOldWidth;
+
+ // we only declare a line as unchanged, if its main values have not
+ // changed and it is not the last line (!paragraph end symbol!)
+ bUnChg = nOldHeight == pNew->Height() &&
+ nOldAscent == pNew->GetAscent() &&
+ nWidthDiff <= SLOPPY_TWIPS &&
+ pOldCur->GetNext();
+ }
+
+ // rRepaint wird berechnet:
+ const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
+ SwRepaint &rRepaint = *(pPara->GetRepaint());
+ if( bUnChg && rRepaint.Top() == rLine.Y()
+ && (bPrev || nNewStart <= pPara->GetReformat()->Start())
+ && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
+ {
+ rRepaint.Top( nBottom );
+ rRepaint.Height( 0 );
+ }
+ else
+ {
+ if( nOldTop )
+ {
+ if( nOldTop < rRepaint.Top() )
+ rRepaint.Top( nOldTop );
+ if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
+ {
+ rRepaint.Bottom( nOldBottom - 1 );
+ rLine.SetUnclipped( sal_True );
+ }
+ }
+ if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
+ {
+ SwTwips nTmpTop, nTmpBottom;
+ rLine.CalcUnclipped( nTmpTop, nTmpBottom );
+ if( nTmpTop < rRepaint.Top() )
+ rRepaint.Top( nTmpTop );
+ if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
+ {
+ rRepaint.Bottom( nTmpBottom - 1 );
+ rLine.SetUnclipped( sal_True );
+ }
+ }
+ else
+ {
+ if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
+ {
+ rRepaint.Bottom( nBottom - 1 );
+ rLine.SetUnclipped( sal_False );
+ }
+ }
+ SwTwips nRght = Max( nOldWidth, pNew->Width() +
+ pNew->GetHangingMargin() );
+ ViewShell *pSh = GetShell();
+ const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
+ if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
+ nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
+ else
+ nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
+ nRght += rLine.GetLeftMargin();
+ if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
+ rRepaint.SetRightOfst( nRght );
+
+ // Finally we enlarge the repaint rectangle if we found an underscore
+ // within our line. 40 Twips should be enough
+ const sal_Bool bHasUnderscore =
+ ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
+ if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
+ rRepaint.Bottom( rRepaint.Bottom() + 40 );
+
+ ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
+ }
+ if( !bUnChg )
+ rLine.SetChanges();
+
+ // Die gute, alte nDelta-Berechnung:
+ *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);
+
+ // Stop!
+ if( rLine.IsStop() )
+ return sal_False;
+
+ // Unbedingt noch eine Zeile
+ if( rLine.IsNewLine() )
+ return sal_True;
+
+ // bis zum Ende des Strings ?
+ if( nNewStart >= GetTxtNode()->GetTxt().Len() )
+ return sal_False;
+
+ if( rLine.GetInfo().IsShift() )
+ return sal_True;
+
+ // Ende des Reformats erreicht ?
+ const xub_StrLen nEnd = pPara->GetReformat()->Start() +
+ pPara->GetReformat()->Len();
+
+ if( nNewStart <= nEnd )
+ return sal_True;
+
+ return 0 != *(pPara->GetDelta());
+}
+
+/*************************************************************************
+ * SwTxtFrm::_Format()
+ *************************************************************************/
+
+void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
+ const sal_Bool bAdjust )
+{
+ ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );
+
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+ rLine.SetUnclipped( sal_False );
+
+ // Das war dem C30 zu kompliziert: aString( GetTxt() );
+ const XubString &rString = GetTxtNode()->GetTxt();
+ const xub_StrLen nStrLen = rString.Len();
+
+ SwCharRange &rReformat = *(pPara->GetReformat());
+ SwRepaint &rRepaint = *(pPara->GetRepaint());
+ SwRepaint *pFreeze = NULL;
+
+ // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt.
+ // Fuer diesen Fall wird rReformat angepasst.
+ if( rReformat.Len() > nStrLen )
+ rReformat.Len() = nStrLen;
+
+ // Optimiert:
+ xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
+ if( nEnd > nStrLen )
+ {
+ rReformat.Len() = nStrLen - rReformat.Start();
+ nEnd = nStrLen;
+ }
+
+ SwTwips nOldBottom;
+ if( GetOfst() && !IsFollow() )
+ {
+ rLine.Bottom();
+ nOldBottom = rLine.Y();
+ rLine.Top();
+ }
+ else
+ nOldBottom = 0;
+ rLine.CharToLine( rReformat.Start() );
+
+ // Worte koennen durch Fortfall oder Einfuegen eines Space
+ // auf die Zeile vor der editierten hinausgezogen werden,
+ // deshalb muss diese ebenfalls formatiert werden.
+ // Optimierung: Wenn rReformat erst hinter dem ersten Wort der
+ // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen.
+ // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung
+ // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen!
+
+ // --> FME 2005-04-18 #i46560#
+ // FME: Yes, consider this case: (word ) has to go to the next line
+ // because ) is a forbidden character at the beginning of a line although
+ // (word would still fit on the previous line. Adding text right in front
+ // of ) would not trigger a reformatting of the previous line. Adding 1
+ // to the result of FindBrk() does not solve the problem in all cases,
+ // nevertheless it should be sufficient.
+ // <--
+ sal_Bool bPrev = rLine.GetPrev() &&
+ ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
+ // --> FME 2005-04-18 #i46560#
+ + 1
+ // <--
+ >= rReformat.Start() ||
+ rLine.GetCurr()->IsRest() );
+ if( bPrev )
+ {
+ while( rLine.Prev() )
+ if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
+ {
+ if( !rLine.GetStart() )
+ rLine.Top(); // damit NumDone nicht durcheinander kommt
+ break;
+ }
+ xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
+ if( nNew )
+ {
+ --nNew;
+ if( CH_BREAK == rString.GetChar( nNew ) )
+ {
+ ++nNew;
+ rLine.Next();
+ bPrev = sal_False;
+ }
+ }
+ rReformat.Len() += rReformat.Start() - nNew;
+ rReformat.Start() = nNew;
+ }
+
+ rRepaint.SetOfst( 0 );
+ rRepaint.SetRightOfst( 0 );
+ rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+ if( pPara->IsMargin() )
+ rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
+ rRepaint.Top( rLine.Y() );
+ // 6792: Rrand < LRand und Repaint
+ if( 0 >= rRepaint.Width() )
+ rRepaint.Width(1);
+ WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );
+
+ // rLine steht jetzt auf der ersten Zeile, die formatiert werden
+ // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird.
+ // Das ganze sieht verdreht aus, aber es muss sichergestellt werden,
+ // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die
+ // nicht mehr passt.
+ sal_Bool bFirst = sal_True;
+ sal_Bool bFormat = sal_True;
+
+ // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren.
+ // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die
+ // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse
+ // verloren, weil der Ofst im Follow falsch eingestellt wird.
+
+ // OD 2004-02-25 #i16128# - method renamed
+ sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
+ && aFrmBreak.IsBreakNowWidAndOrp( rLine );
+ if( bBreak )
+ {
+ sal_Bool bPrevDone = 0 != rLine.Prev();
+ // OD 2004-02-25 #i16128# - method renamed
+ while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
+ bPrevDone = 0 != rLine.Prev();
+ if( bPrevDone )
+ {
+ aFrmBreak.SetKeep( sal_False );
+ rLine.Next();
+ }
+ rLine.TruncLines();
+
+ // auf Nummer sicher:
+ // OD 2004-02-25 #i16128# - method renamed
+ bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
+ ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
+ }
+
+ /* Bedeutung der folgenden Flags:
+ Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn
+ eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist.
+ Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine
+ Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt
+ umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph
+ verboten war.
+ Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine
+ Trennstelle erhalten hat, vorher aber keine hatte,
+ Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet.
+ */
+ sal_Bool bJumpEndHyph = sal_False,
+ bWatchEndHyph = sal_False,
+ bJumpMidHyph = sal_False,
+ bWatchMidHyph = sal_False;
+
+ const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
+ sal_Bool bMaxHyph = ( 0 !=
+ ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
+ if ( bMaxHyph )
+ rLine.InitCntHyph();
+
+ if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
+ {
+ const SwLineLayout* pLine;
+ {
+ SwTxtFrm *pMaster = FindMaster();
+ ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
+ if( !pMaster->HasPara() )
+ pMaster->GetFormatted();
+ SwTxtSizeInfo aInf( pMaster );
+ SwTxtIter aMasterLine( pMaster, &aInf );
+ aMasterLine.Bottom();
+ pLine = aMasterLine.GetCurr();
+ }
+ SwLinePortion* pRest =
+ rLine.MakeRestPortion( pLine, GetOfst() );
+ if( pRest )
+ rInf.SetRest( pRest );
+ else
+ SetFieldFollow( sal_False );
+ }
+
+ /* Zum Abbruchkriterium:
+ * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt,
+ * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow
+ * wieder entfernt.
+ * Eine weitere Komplikation: wenn wir der Master sind, so muessen
+ * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile
+ * vom Follow in den Master rutschen kann.
+ */
+ do
+ {
+ DBG_LOOP;
+ if( bFirst )
+ bFirst = sal_False;
+ else
+ {
+ if ( bMaxHyph )
+ {
+ if ( rLine.GetCurr()->IsEndHyph() )
+ rLine.CntEndHyph()++;
+ else
+ rLine.CntEndHyph() = 0;
+ if ( rLine.GetCurr()->IsMidHyph() )
+ rLine.CntMidHyph()++;
+ else
+ rLine.CntMidHyph() = 0;
+ }
+ if( !rLine.Next() )
+ {
+ if( !bFormat )
+ {
+ SwLinePortion* pRest =
+ rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() );
+ if( pRest )
+ rInf.SetRest( pRest );
+ }
+ rLine.Insert( new SwLineLayout() );
+ rLine.Next();
+ bFormat = sal_True;
+ }
+ }
+ if ( !bFormat && bMaxHyph &&
+ (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
+ {
+ if ( rLine.GetCurr()->IsEndHyph() )
+ {
+ if ( bWatchEndHyph )
+ bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
+ }
+ else
+ {
+ bFormat = bJumpEndHyph;
+ bWatchEndHyph = sal_False;
+ bJumpEndHyph = sal_False;
+ }
+ if ( rLine.GetCurr()->IsMidHyph() )
+ {
+ if ( bWatchMidHyph && !bFormat )
+ bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
+ }
+ else
+ {
+ bFormat = bFormat || bJumpMidHyph;
+ bWatchMidHyph = sal_False;
+ bJumpMidHyph = sal_False;
+ }
+ }
+ if( bFormat )
+ {
+ sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
+ sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
+ bFormat = FormatLine( rLine, bPrev );
+ //9334: Es kann nur ein bPrev geben... (???)
+ bPrev = sal_False;
+ if ( bMaxHyph )
+ {
+ if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
+ {
+ bWatchEndHyph = !bOldEndHyph;
+ bJumpEndHyph = bOldEndHyph;
+ }
+ if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
+ {
+ bWatchMidHyph = !bOldMidHyph;
+ bJumpMidHyph = bOldMidHyph;
+ }
+ }
+ }
+
+ if( !rInf.IsNewLine() )
+ {
+ if( !bFormat )
+ bFormat = 0 != rInf.GetRest();
+ if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
+ break;
+ if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
+ !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
+ {
+ if( GetFollow() )
+ {
+ while( rLine.Next() )
+ ; //Nothing
+ pFreeze = new SwRepaint( rRepaint ); // to minimize painting
+ }
+ else
+ break;
+ }
+ }
+ // OD 2004-02-25 #i16128# - method renamed
+ bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
+ }while( !bBreak );
+
+ if( pFreeze )
+ {
+ rRepaint = *pFreeze;
+ delete pFreeze;
+ }
+
+ if( !rLine.IsStop() )
+ {
+ // Wurde aller Text formatiert und gibt es noch weitere
+ // Zeilenobjekte, dann sind diese jetzt ueberfluessig,
+ // weil der Text kuerzer geworden ist.
+ if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
+ rLine.GetCurr()->GetNext() )
+ {
+ rLine.TruncLines();
+ rLine.SetTruncLines( sal_True );
+ }
+ }
+
+ if( !rInf.IsTest() )
+ {
+ // Bei OnceMore lohnt sich kein FormatAdjust
+ if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
+ {
+ FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
+ }
+ if( rRepaint.HasArea() )
+ SetRepaint();
+ rLine.SetTruncLines( sal_False );
+ if( nOldBottom ) // Bei "gescollten" Absaetzen wird
+ { // noch ueberprueft, ob durch Schrumpfen
+ rLine.Bottom(); // das Scrolling ueberfluessig wurde.
+ SwTwips nNewBottom = rLine.Y();
+ if( nNewBottom < nOldBottom )
+ _SetOfst( 0 );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::Format()
+ *************************************************************************/
+
+void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
+{
+ ASSERT( ! IsVertical() || IsSwapped(),
+ "A frame is not swapped in SwTxtFrm::FormatOnceMore" );
+
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+ if( !pPara )
+ return;
+
+ // ggf gegen pPara
+ KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight();
+ sal_Bool bShrink = sal_False,
+ bGrow = sal_False,
+ bGoOn = rLine.IsOnceMore();
+ sal_uInt8 nGo = 0;
+ while( bGoOn )
+ {
+#ifdef DBGTXT
+ aDbstream << "OnceMore!" << endl;
+#endif
+ ++nGo;
+ rInf.Init();
+ rLine.Top();
+ if( !rLine.GetDropFmt() )
+ rLine.SetOnceMore( sal_False );
+ SwCharRange aRange( 0, rInf.GetTxt().Len() );
+ *(pPara->GetReformat()) = aRange;
+ _Format( rLine, rInf );
+
+ bGoOn = rLine.IsOnceMore();
+ if( bGoOn )
+ {
+ const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
+ if( nOld == nNew )
+ bGoOn = sal_False;
+ else
+ {
+ if( nOld > nNew )
+ bShrink = sal_True;
+ else
+ bGrow = sal_True;
+
+ if( bShrink == bGrow || 5 < nGo )
+ bGoOn = sal_False;
+
+ nOld = nNew;
+ }
+
+ // 6107: Wenn was schief ging, muss noch einmal formatiert werden.
+ if( !bGoOn )
+ {
+ rInf.CtorInitTxtFormatInfo( this );
+ rLine.CtorInitTxtFormatter( this, &rInf );
+ rLine.SetDropLines( 1 );
+ rLine.CalcDropHeight( 1 );
+ SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
+ *(pPara->GetReformat()) = aTmpRange;
+ _Format( rLine, rInf, sal_True );
+ // 8047: Wir painten alles...
+ SetCompletePaint();
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::_Format()
+ *************************************************************************/
+
+
+void SwTxtFrm::_Format( SwParaPortion *pPara )
+{
+ const xub_StrLen nStrLen = GetTxt().Len();
+
+ // AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten
+ // Formatieren und Repainten zu fuehren???
+// if ( !(*pPara->GetDelta()) )
+// *(pPara->GetDelta()) = nStrLen;
+// else
+ if ( !nStrLen )
+ {
+ // Leere Zeilen werden nicht lange gequaelt:
+ // pPara wird blank geputzt
+ // entspricht *pPara = SwParaPortion;
+ sal_Bool bMustFit = pPara->IsPrepMustFit();
+ pPara->Truncate();
+ pPara->FormatReset();
+ if( pBlink && pPara->IsBlinking() )
+ pBlink->Delete( pPara );
+
+ // delete pSpaceAdd und pKanaComp
+ pPara->FinishSpaceAdd();
+ pPara->FinishKanaComp();
+ pPara->ResetFlags();
+ pPara->SetPrepMustFit( bMustFit );
+ }
+
+ ASSERT( ! IsSwapped(), "A frame is swapped before _Format" );
+
+ if ( IsVertical() )
+ SwapWidthAndHeight();
+
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+
+ // OD 2004-01-15 #110582#
+ HideAndShowObjects();
+
+ _Format( aLine, aInf );
+
+ if( aLine.IsOnceMore() )
+ FormatOnceMore( aLine, aInf );
+
+ if ( IsVertical() )
+ SwapWidthAndHeight();
+
+ ASSERT( ! IsSwapped(), "A frame is swapped after _Format" );
+
+ if( 1 < aLine.GetDropLines() )
+ {
+ if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
+ SVX_ADJUST_BLOCK != aLine.GetAdjust() )
+ {
+ aLine.CalcDropAdjust();
+ aLine.SetPaintDrop( sal_True );
+ }
+
+ if( aLine.IsPaintDrop() )
+ {
+ aLine.CalcDropRepaint();
+ aLine.SetPaintDrop( sal_False );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::Format()
+ *************************************************************************/
+
+/*
+ * Format berechnet die Groesse des Textframes und ruft, wenn
+ * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem
+ * evtl. veraenderten Platzbedarf anzupassen.
+ */
+
+void SwTxtFrm::Format( const SwBorderAttrs * )
+{
+ DBG_LOOP;
+#if OSL_DEBUG_LEVEL > 1
+ const XubString aXXX = GetTxtNode()->GetTxt();
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+ const SwPageFrm *pDbgPage = FindPageFrm();
+ const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum();
+ (void)nDbgPageNr;
+ // Um zu gucken, ob es einen Ftn-Bereich gibt.
+ const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont());
+ (void)pDbgFtnCont;
+
+#ifdef DBG_UTIL
+ // nStopAt laesst sich vom CV bearbeiten.
+ static MSHORT nStopAt = 0;
+ if( nStopAt == GetFrmId() )
+ {
+ int i = GetFrmId();
+ (void)i;
+ }
+#endif
+#endif
+
+#ifdef DEBUG_FTN
+ //Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen.
+ if( IsInFtn() )
+ {
+ const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper();
+ const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm();
+ const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum();
+ if( !IsLocked() )
+ {
+ if( nFtnPageNr > nDbgPageNr )
+ {
+ SwTxtFrmLocker aLock(this);
+ ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." );
+ MSHORT i = 0;
+ }
+ }
+ }
+#endif
+
+ SWRECTFN( this )
+
+ // --> OD 2008-01-31 #newlistlevelattrs#
+ CalcAdditionalFirstLineOffset();
+ // <--
+
+ // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen
+ // gelegentlich TxtFrms mit einer Breite <=0.
+ if( (Prt().*fnRect->fnGetWidth)() <= 0 )
+ {
+ // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante
+ // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse
+ // von 12 Pt. ein (240 Twip).
+ SwTxtLineAccess aAccess( this );
+ long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
+ if( aAccess.GetPara()->IsPrepMustFit() )
+ {
+ const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
+ const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
+ if( nDiff > 0 )
+ Shrink( nDiff );
+ }
+ else if( 240 < nFrmHeight )
+ Shrink( nFrmHeight - 240 );
+ else if( 240 > nFrmHeight )
+ Grow( 240 - nFrmHeight );
+ nFrmHeight = (Frm().*fnRect->fnGetHeight)();
+
+ long nTop = (this->*fnRect->fnGetTopMargin)();
+ if( nTop > nFrmHeight )
+ (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
+ else if( (Prt().*fnRect->fnGetHeight)() < 0 )
+ (Prt().*fnRect->fnSetHeight)( 0 );
+ return;
+ }
+
+ const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
+ if ( nStrLen || !FormatEmpty() )
+ {
+
+ SetEmpty( sal_False );
+ // Um nicht durch verschachtelte Formats irritiert zu werden.
+ FormatLevel aLevel;
+ if( 12 == aLevel.GetLevel() )
+ return;
+
+ // Die Formatinformationen duerfen u.U. nicht veraendert werden.
+ if( IsLocked() )
+ return;
+
+ // 8708: Vorsicht, das Format() kann auch durch GetFormatted()
+ // angestossen werden.
+ if( IsHiddenNow() )
+ {
+ long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
+ if( nPrtHeight )
+ {
+ HideHidden();
+ Shrink( nPrtHeight );
+ }
+ else
+ {
+ // OD 2004-01-20 #110582# - assure that objects anchored
+ // at paragraph resp. at/as character inside paragraph
+ // are hidden.
+ HideAndShowObjects();
+ }
+ ChgThisLines();
+ return;
+ }
+
+ // Waehrend wir formatieren, wollen wir nicht gestoert werden.
+ SwTxtFrmLocker aLock(this);
+ SwTxtLineAccess aAccess( this );
+ const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
+ const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );
+
+ if( CalcPreps() )
+ ; // nothing
+ // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn
+ // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format-
+ // informationen vorliegen.
+ else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
+ {
+ if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
+ {
+ aAccess.GetPara()->SetPrepAdjust( sal_True );
+ aAccess.GetPara()->SetPrep( sal_True );
+ CalcPreps();
+ }
+ SetWidow( sal_False );
+ }
+ else if( bSetOfst && IsFollow() )
+ {
+ SwTxtFrm *pMaster = FindMaster();
+ ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
+ if( pMaster )
+ pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
+ SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
+ if( (Frm().*fnRect->fnOverStep)( nMaxY ) )
+ (this->*fnRect->fnSetLimit)( nMaxY );
+ else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 )
+ (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
+ }
+ else
+ {
+ // bSetOfst here means that we have the "red arrow situation"
+ if ( bSetOfst )
+ _SetOfst( 0 );
+
+ const sal_Bool bOrphan = IsWidow();
+ const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
+ SwTwips nFtnHeight = 0;
+ if( pFtnBoss )
+ {
+ const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
+ nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
+ }
+ do
+ {
+ _Format( aAccess.GetPara() );
+ if( pFtnBoss && nFtnHeight )
+ {
+ const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
+ SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
+ // If we lost some footnotes, we may have more space
+ // for our main text, so we have to format again ...
+ if( nNewHeight < nFtnHeight )
+ nFtnHeight = nNewHeight;
+ else
+ break;
+ }
+ else
+ break;
+ } while ( pFtnBoss );
+ if( bOrphan )
+ {
+ ValidateFrm();
+ SetWidow( sal_False );
+ }
+ }
+ if( IsEmptyMaster() )
+ {
+ SwFrm* pPre = GetPrev();
+ if( pPre &&
+ // --> FME 2004-07-22 #i10826# It's the first, it cannot keep!
+ pPre->GetIndPrev() &&
+ // <--
+ pPre->GetAttrSet()->GetKeep().GetValue() )
+ {
+ pPre->InvalidatePos();
+ }
+ }
+ }
+
+ ChgThisLines();
+
+ // the PrepMustFit should not survive a Format operation
+ SwParaPortion *pPara = GetPara();
+ if ( pPara )
+ pPara->SetPrepMustFit( sal_False );
+
+#if OSL_DEBUG_LEVEL > 1
+ // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen,
+ // insbesondere bei Fussnoten, auf die Schliche zu kommen
+ if( IsFollow() || GetFollow() )
+ {
+ SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this;
+ const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm();
+ MSHORT nPgNr = pTmpPage->GetPhyPageNum();
+ MSHORT nLast;
+ MSHORT nDummy = 0; // nur zum Breakpoint setzen
+ while( pTmpFrm->GetFollow() )
+ {
+ pTmpFrm = pTmpFrm->GetFollow();
+ nLast = nPgNr;
+ pTmpPage = pTmpFrm->FindPageFrm();
+ nPgNr = pTmpPage->GetPhyPageNum();
+ if( nLast > nPgNr )
+ ++nDummy; // schon fast eine Assertion wert
+ else if( nLast == nPgNr )
+ ++nDummy; // bei Spalten voellig normal, aber sonst!?
+ else if( nLast < nPgNr - 1 )
+ ++nDummy; // kann schon mal temporaer vorkommen
+ }
+ }
+#endif
+
+ CalcBaseOfstForFly();
+ // OD 2004-03-17 #i11860#
+ _CalcHeightOfLastLine();
+}
+
+/*************************************************************************
+ * SwTxtFrm::FormatQuick()
+ *
+ * bForceQuickFormat is set if GetFormatted() has been called during the
+ * painting process. Actually I cannot imagine a situation which requires
+ * a full formatting of the paragraph during painting, on the other hand
+ * a full formatting can cause the invalidation of other layout frames,
+ * e.g., if there are footnotes in this paragraph, and invalid layout
+ * frames will not calculated during the painting. So I actually want to
+ * avoid a formatting during painting, but since I'm a coward, I'll only
+ * force the quick formatting in the situation of issue i29062.
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::FormatQuick with swapped frame" );
+
+ DBG_LOOP;
+#if OSL_DEBUG_LEVEL > 1
+ const XubString aXXX = GetTxtNode()->GetTxt();
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+#ifdef DBG_UTIL
+ // nStopAt laesst sich vom CV bearbeiten.
+ static MSHORT nStopAt = 0;
+ if( nStopAt == GetFrmId() )
+ {
+ int i = GetFrmId();
+ (void)i;
+ }
+#endif
+#endif
+
+ if( IsEmpty() && FormatEmpty() )
+ return sal_True;
+
+ // Wir sind sehr waehlerisch:
+ if( HasPara() || IsWidow() || IsLocked()
+ || !GetValidSizeFlag() ||
+ ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
+ return sal_False;
+
+ SwTxtLineAccess aAccess( this );
+ SwParaPortion *pPara = aAccess.GetPara();
+ if( !pPara )
+ return sal_False;
+
+ SwFrmSwapper aSwapper( this, sal_True );
+
+ SwTxtFrmLocker aLock(this);
+ SwTxtFormatInfo aInf( this, sal_False, sal_True );
+ if( 0 != aInf.MaxHyph() ) // 27483: MaxHyphen beachten!
+ return sal_False;
+
+ SwTxtFormatter aLine( this, &aInf );
+
+ // DropCaps sind zu kompliziert...
+ if( aLine.GetDropFmt() )
+ return sal_False;
+
+ xub_StrLen nStart = GetOfst();
+ const xub_StrLen nEnd = GetFollow()
+ ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
+ do
+ {
+ //DBG_LOOP; shadows declaration above.
+ //resolved into:
+#if OSL_DEBUG_LEVEL > 1
+#ifdef DBG_UTIL
+ DbgLoop aDbgLoop2( (const void*) this );
+#endif
+#endif
+ nStart = aLine.FormatLine( nStart );
+ if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
+ aLine.Insert( new SwLineLayout() );
+ } while( aLine.Next() );
+
+ // Last exit: die Hoehen muessen uebereinstimmen.
+ Point aTopLeft( Frm().Pos() );
+ aTopLeft += Prt().Pos();
+ const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
+ const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();
+
+ if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
+ {
+ // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic!
+ // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" );
+ const xub_StrLen nStrt = GetOfst();
+ _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
+ return sal_False;
+ }
+
+ if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() )
+ return sal_False; // kann z.B. durch Orphans auftreten (35083,35081)
+
+ // Geschafft, wir sind durch ...
+
+ // Repaint setzen
+ pPara->GetRepaint()->Pos( aTopLeft );
+ pPara->GetRepaint()->SSize( Prt().SSize() );
+
+ // Reformat loeschen
+ *(pPara->GetReformat()) = SwCharRange();
+ *(pPara->GetDelta()) = 0;
+
+ return sal_True;
+}
diff --git a/sw/source/core/text/frminf.cxx b/sw/source/core/text/frminf.cxx
new file mode 100644
index 000000000000..60700849fc80
--- /dev/null
+++ b/sw/source/core/text/frminf.cxx
@@ -0,0 +1,377 @@
+/*************************************************************************
+ *
+ * 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 <pam.hxx> // GetSpaces
+#include <txtcfg.hxx>
+#include <frminf.hxx> // SwTxtFrminfo
+#include <itrtxt.hxx> // SwTxtMargin
+
+/*************************************************************************
+ * SwTxtMargin::GetTxtStart()
+ *************************************************************************/
+
+xub_StrLen SwTxtMargin::GetTxtStart() const
+{
+ const XubString &rTxt = GetInfo().GetTxt();
+ const xub_StrLen nTmpPos = nStart;
+ const xub_StrLen nEnd = nTmpPos + pCurr->GetLen();
+ xub_StrLen i;
+
+ for( i = nTmpPos; i < nEnd; ++i )
+ {
+ const xub_Unicode aChar = rTxt.GetChar( i );
+ if( CH_TAB != aChar && ' ' != aChar )
+ return i;
+ }
+ return i;
+}
+
+/*************************************************************************
+ * SwTxtMargin::GetTxtEnd()
+ *************************************************************************/
+
+xub_StrLen SwTxtMargin::GetTxtEnd() const
+{
+ const XubString &rTxt = GetInfo().GetTxt();
+ const xub_StrLen nTmpPos = nStart;
+ const xub_StrLen nEnd = nTmpPos + pCurr->GetLen();
+ long i;
+ for( i = nEnd - 1; i >= nTmpPos; --i )
+ {
+ xub_Unicode aChar = rTxt.GetChar( static_cast<xub_StrLen>(i) );
+ if( CH_TAB != aChar && CH_BREAK != aChar && ' ' != aChar )
+ return static_cast<xub_StrLen>(i + 1);
+ }
+ return static_cast<xub_StrLen>(i + 1);
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::IsOneLine()
+ *************************************************************************/
+
+// Passt der Absatz in eine Zeile?
+sal_Bool SwTxtFrmInfo::IsOneLine() const
+{
+ const SwLineLayout *pLay = pFrm->GetPara();
+ if( !pLay )
+ return sal_False;
+ else
+ {
+ // 6575: bei Follows natuerlich sal_False
+ if( pFrm->GetFollow() )
+ return sal_False;
+ pLay = pLay->GetNext();
+ while( pLay )
+ {
+ if( pLay->GetLen() )
+ return sal_False;
+ pLay = pLay->GetNext();
+ }
+ return sal_True;
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::IsFilled()
+ *************************************************************************/
+
+// Ist die Zeile zu X% gefuellt?
+sal_Bool SwTxtFrmInfo::IsFilled( const sal_uInt8 nPercent ) const
+{
+ const SwLineLayout *pLay = pFrm->GetPara();
+ if( !pLay )
+ return sal_False;
+ else
+ {
+ long nWidth = pFrm->Prt().Width();
+ nWidth *= nPercent;
+ nWidth /= 100;
+ return KSHORT(nWidth) <= pLay->Width();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::GetLineStart()
+ *************************************************************************/
+
+// Wo beginnt der Text (ohne whitespaces)? ( Dokument global )
+SwTwips SwTxtFrmInfo::GetLineStart( const SwTxtCursor &rLine ) const
+{
+ xub_StrLen nTxtStart = rLine.GetTxtStart();
+ SwTwips nStart;
+ if( rLine.GetStart() == nTxtStart )
+ nStart = rLine.GetLineStart();
+ else
+ {
+ SwRect aRect;
+ if( ((SwTxtCursor&)rLine).GetCharRect( &aRect, nTxtStart ) )
+ nStart = aRect.Left();
+ else
+ nStart = rLine.GetLineStart();
+ }
+ return nStart;
+}
+
+
+/*************************************************************************
+ * SwTxtFrmInfo::GetLineStart()
+ *************************************************************************/
+
+// Wo beginnt der Text (ohne whitespaces)? (rel. im Frame)
+SwTwips SwTxtFrmInfo::GetLineStart() const
+{
+ SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
+ SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
+ return GetLineStart( aLine ) - pFrm->Frm().Left() - pFrm->Prt().Left();
+}
+
+// errechne die Position des Zeichens und gebe die Mittelposition zurueck
+SwTwips SwTxtFrmInfo::GetCharPos( xub_StrLen nChar, sal_Bool bCenter ) const
+{
+ SWRECTFN( pFrm )
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
+ SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
+
+ SwTwips nStt, nNext;
+ SwRect aRect;
+ if( ((SwTxtCursor&)aLine).GetCharRect( &aRect, nChar ) )
+ {
+ if ( bVert )
+ pFrm->SwitchHorizontalToVertical( aRect );
+
+ nStt = (aRect.*fnRect->fnGetLeft)();
+ }
+ else
+ nStt = aLine.GetLineStart();
+
+ if( !bCenter )
+ return nStt - (pFrm->Frm().*fnRect->fnGetLeft)();
+
+ if( ((SwTxtCursor&)aLine).GetCharRect( &aRect, nChar+1 ) )
+ {
+ if ( bVert )
+ pFrm->SwitchHorizontalToVertical( aRect );
+
+ nNext = (aRect.*fnRect->fnGetLeft)();
+ }
+ else
+ nNext = aLine.GetLineStart();
+
+ return (( nNext + nStt ) / 2 ) - (pFrm->Frm().*fnRect->fnGetLeft)();
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::GetSpaces()
+ *************************************************************************/
+
+SwPaM *AddPam( SwPaM *pPam, const SwTxtFrm* pTxtFrm,
+ const xub_StrLen nPos, const xub_StrLen nLen )
+{
+ if( nLen )
+ {
+ // Es koennte auch der erste sein.
+ if( pPam->HasMark() )
+ {
+ // liegt die neue Position genau hinter der aktuellen, dann
+ // erweiter den Pam einfach
+ if( nPos == pPam->GetPoint()->nContent.GetIndex() )
+ {
+ pPam->GetPoint()->nContent += nLen;
+ return pPam;
+ }
+ pPam = new SwPaM( *pPam );
+ }
+
+ SwIndex &rContent = pPam->GetPoint()->nContent;
+ rContent.Assign( (SwTxtNode*)pTxtFrm->GetTxtNode(), nPos );
+ pPam->SetMark();
+ rContent += nLen;
+ }
+ return pPam;
+}
+
+// Sammelt die whitespaces am Zeilenbeginn und -ende im Pam
+void SwTxtFrmInfo::GetSpaces( SwPaM &rPam, sal_Bool bWithLineBreak ) const
+{
+ SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
+ SwTxtMargin aLine( (SwTxtFrm*)pFrm, &aInf );
+ SwPaM *pPam = &rPam;
+ sal_Bool bFirstLine = sal_True;
+ do {
+
+ if( aLine.GetCurr()->GetLen() )
+ {
+ xub_StrLen nPos = aLine.GetTxtStart();
+ // Bug 49649: von der ersten Line die Blanks/Tabs NICHT
+ // mit selektieren
+ if( !bFirstLine && nPos > aLine.GetStart() )
+ pPam = AddPam( pPam, pFrm, aLine.GetStart(),
+ nPos - aLine.GetStart() );
+
+ // Bug 49649: von der letzten Line die Blanks/Tabs NICHT
+ // mit selektieren
+ if( aLine.GetNext() )
+ {
+ nPos = aLine.GetTxtEnd();
+
+ if( nPos < aLine.GetEnd() )
+ {
+ MSHORT nOff = !bWithLineBreak && CH_BREAK ==
+ aLine.GetInfo().GetChar( aLine.GetEnd() - 1 )
+ ? 1 : 0;
+ pPam = AddPam( pPam, pFrm, nPos, aLine.GetEnd() - nPos - nOff );
+ }
+ }
+ }
+ bFirstLine = sal_False;
+ }
+ while( aLine.Next() );
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::IsBullet()
+ *************************************************************************/
+
+// Ist an der Textposition ein Bullet/Symbol etc?
+// Fonts: CharSet, SYMBOL und DONTKNOW
+sal_Bool SwTxtFrmInfo::IsBullet( xub_StrLen nTxtStart ) const
+{
+ SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
+ SwTxtMargin aLine( (SwTxtFrm*)pFrm, &aInf );
+ aInf.SetIdx( nTxtStart );
+ return aLine.IsSymbol( nTxtStart );
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::GetFirstIndent()
+ *************************************************************************/
+
+// Ermittelt Erstzeileneinzug
+// Voraussetzung fuer pos. oder neg. EZE ist, dass alle
+// Zeilen ausser der ersten Zeile den selben linken Rand haben.
+// Wir wollen nicht so knauserig sein und arbeiten mit einer Toleranz
+// von TOLERANCE Twips.
+
+#define TOLERANCE 20
+
+SwTwips SwTxtFrmInfo::GetFirstIndent() const
+{
+ SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
+ SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
+ const SwTwips nFirst = GetLineStart( aLine );
+ if( !aLine.Next() )
+ return 0;
+
+ SwTwips nLeft = GetLineStart( aLine );
+ while( aLine.Next() )
+ {
+ if( aLine.GetCurr()->GetLen() )
+ {
+ const SwTwips nCurrLeft = GetLineStart( aLine );
+ if( nLeft + TOLERANCE < nCurrLeft ||
+ nLeft - TOLERANCE > nCurrLeft )
+ return 0;
+ }
+ }
+
+ // Vorerst wird nur +1, -1 und 0 returnt.
+ if( nLeft == nFirst )
+ return 0;
+ else
+ if( nLeft > nFirst )
+ return -1;
+ else
+ return +1;
+}
+
+/*************************************************************************
+ * SwTxtFrmInfo::GetBigIndent()
+ *************************************************************************/
+
+KSHORT SwTxtFrmInfo::GetBigIndent( xub_StrLen& rFndPos,
+ const SwTxtFrm *pNextFrm ) const
+{
+ SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
+ SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
+ SwTwips nNextIndent = 0;
+
+ if( pNextFrm )
+ {
+ // ich bin einzeilig
+ SwTxtSizeInfo aNxtInf( (SwTxtFrm*)pNextFrm );
+ SwTxtCursor aNxtLine( (SwTxtFrm*)pNextFrm, &aNxtInf );
+ nNextIndent = GetLineStart( aNxtLine );
+ }
+ else
+ {
+ // ich bin mehrzeilig
+ if( aLine.Next() )
+ {
+ nNextIndent = GetLineStart( aLine );
+ aLine.Prev();
+ }
+ }
+
+ if( nNextIndent <= GetLineStart( aLine ) )
+ return 0;
+
+ const Point aPoint( nNextIndent, aLine.Y() );
+ rFndPos = aLine.GetCrsrOfst( 0, aPoint, sal_False );
+ if( 1 >= rFndPos )
+ return 0;
+
+ // steht vor einem "nicht Space"
+ const XubString& rTxt = aInf.GetTxt();
+ xub_Unicode aChar = rTxt.GetChar( rFndPos );
+ if( CH_TAB == aChar || CH_BREAK == aChar || ' ' == aChar ||
+ (( CH_TXTATR_BREAKWORD == aChar || CH_TXTATR_INWORD == aChar ) &&
+ aInf.HasHint( rFndPos ) ) )
+ return 0;
+
+ // und hinter einem "Space"
+ aChar = rTxt.GetChar( rFndPos - 1 );
+ if( CH_TAB != aChar && CH_BREAK != aChar &&
+ ( ( CH_TXTATR_BREAKWORD != aChar && CH_TXTATR_INWORD != aChar ) ||
+ !aInf.HasHint( rFndPos - 1 ) ) &&
+ // mehr als 2 Blanks !!
+ ( ' ' != aChar || ' ' != rTxt.GetChar( rFndPos - 2 ) ) )
+ return 0;
+
+ SwRect aRect;
+ return aLine.GetCharRect( &aRect, rFndPos )
+ ? KSHORT( aRect.Left() - pFrm->Frm().Left() - pFrm->Prt().Left())
+ : 0;
+}
+
+
+
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
new file mode 100644
index 000000000000..443900e1942c
--- /dev/null
+++ b/sw/source/core/text/frmpaint.cxx
@@ -0,0 +1,749 @@
+/*************************************************************************
+ *
+ * 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/text/HoriOrientation.hpp>
+#include <hintids.hxx>
+#include <vcl/sound.hxx>
+#include <tools/shl.hxx> // SW_MOD
+#include <editeng/pgrditem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <paratr.hxx>
+
+#ifndef _FMTLINE_HXX
+#include <fmtline.hxx>
+#endif
+#ifndef _LINEINFO_HXX
+#include <lineinfo.hxx>
+#endif
+#include <charfmt.hxx>
+#include <pagefrm.hxx>
+#include <viewsh.hxx> // ViewShell
+#include <viewimp.hxx> // SwViewImp
+#include <viewopt.hxx> // SwViewOption
+#include <frmtool.hxx> // DrawGraphic
+#include <txtcfg.hxx>
+#include <txtfrm.hxx> // SwTxtFrm
+#include <itrpaint.hxx> // SwTxtPainter
+#include <txtpaint.hxx> // SwSaveClip
+#include <txtcache.hxx> // SwTxtLineAccess
+#include <flyfrm.hxx> // SwFlyFrm
+#include <redlnitr.hxx> // SwRedlineItr
+#include <swmodule.hxx> // SW_MOD
+#include <tabfrm.hxx> // SwTabFrm (Redlining)
+#include <SwGrammarMarkUp.hxx>
+
+// --> FME 2004-06-08 #i12836# enhanced pdf export
+#include <EnhancedPDFExportHelper.hxx>
+// <--
+
+#include <IDocumentStylePoolAccess.hxx>
+#include <IDocumentLineNumberAccess.hxx>
+
+// --> OD 2006-06-27 #b6440955#
+// variable moved to class <numfunc:GetDefBulletConfig>
+//extern const sal_Char __FAR_DATA sBulletFntName[];
+namespace numfunc
+{
+ extern const String& GetDefBulletFontname();
+ extern bool IsDefBulletFontUserDefined();
+}
+// <--
+
+
+#define REDLINE_DISTANCE 567/4
+#define REDLINE_MINDIST 567/10
+
+using namespace ::com::sun::star;
+
+////////////////////////////////////////////////////////////
+
+sal_Bool bInitFont = sal_True;
+
+class SwExtraPainter
+{
+ SwSaveClip aClip;
+ SwRect aRect;
+ const SwTxtFrm* pTxtFrm;
+ ViewShell *pSh;
+ SwFont* pFnt;
+ const SwLineNumberInfo &rLineInf;
+ SwTwips nX;
+ SwTwips nRedX;
+ ULONG nLineNr;
+ MSHORT nDivider;
+ sal_Bool bGoLeft;
+ sal_Bool bLineNum;
+ inline sal_Bool IsClipChg() { return aClip.IsChg(); }
+public:
+ SwExtraPainter( const SwTxtFrm *pFrm, ViewShell *pVwSh,
+ const SwLineNumberInfo &rLnInf, const SwRect &rRct,
+ sal_Int16 eHor, sal_Bool bLnNm );
+ ~SwExtraPainter() { delete pFnt; }
+ inline SwFont* GetFont() const { return pFnt; }
+ inline void IncLineNr() { ++nLineNr; }
+ inline sal_Bool HasNumber() { return !( nLineNr % rLineInf.GetCountBy() ); }
+ inline sal_Bool HasDivider() { if( !nDivider ) return sal_False;
+ return !(nLineNr % rLineInf.GetDividerCountBy()); }
+
+ void PaintExtra( SwTwips nY, long nAsc, long nMax, sal_Bool bRed );
+ void PaintRedline( SwTwips nY, long nMax );
+};
+
+
+SwExtraPainter::SwExtraPainter( const SwTxtFrm *pFrm, ViewShell *pVwSh,
+ const SwLineNumberInfo &rLnInf, const SwRect &rRct,
+ sal_Int16 eHor, sal_Bool bLnNm )
+ : aClip( pVwSh->GetWin() || pFrm->IsUndersized() ? pVwSh->GetOut() : 0 ),
+ aRect( rRct ), pTxtFrm( pFrm ), pSh( pVwSh ), pFnt( 0 ), rLineInf( rLnInf ),
+ nLineNr( 1L ), bLineNum( bLnNm )
+{
+ if( pFrm->IsUndersized() )
+ {
+ SwTwips nBottom = pFrm->Frm().Bottom();
+ if( aRect.Bottom() > nBottom )
+ aRect.Bottom( nBottom );
+ }
+ MSHORT nVirtPageNum = 0;
+ if( bLineNum )
+ { /* initialisiert die Member, die bei Zeilennumerierung notwendig sind:
+
+ nDivider, wie oft ist ein Teilerstring gewuenscht, 0 == nie;
+ nX, X-Position der Zeilennummern;
+ pFnt, der Font der Zeilennummern;
+ nLineNr, die erste Zeilennummer;
+ bLineNum wird ggf.wieder auf sal_False gesetzt, wenn die Numerierung sich
+ komplett ausserhalb des Paint-Rechtecks aufhaelt. */
+ nDivider = rLineInf.GetDivider().Len() ? rLineInf.GetDividerCountBy() : 0;
+ nX = pFrm->Frm().Left();
+ SwCharFmt* pFmt = rLineInf.GetCharFmt( const_cast<IDocumentStylePoolAccess&>(*pFrm->GetNode()->getIDocumentStylePoolAccess()) );
+ ASSERT( pFmt, "PaintExtraData without CharFmt" );
+ pFnt = new SwFont( &pFmt->GetAttrSet(), pFrm->GetTxtNode()->getIDocumentSettingAccess() );
+ pFnt->Invalidate();
+ pFnt->ChgPhysFnt( pSh, *pSh->GetOut() );
+ pFnt->SetVertical( 0, pFrm->IsVertical() );
+ nLineNr += pFrm->GetAllLines() - pFrm->GetThisLines();
+ LineNumberPosition ePos = rLineInf.GetPos();
+ if( ePos != LINENUMBER_POS_LEFT && ePos != LINENUMBER_POS_RIGHT )
+ {
+ if( pFrm->FindPageFrm()->OnRightPage() )
+ {
+ nVirtPageNum = 1;
+ ePos = ePos == LINENUMBER_POS_INSIDE ?
+ LINENUMBER_POS_LEFT : LINENUMBER_POS_RIGHT;
+ }
+ else
+ {
+ nVirtPageNum = 2;
+ ePos = ePos == LINENUMBER_POS_OUTSIDE ?
+ LINENUMBER_POS_LEFT : LINENUMBER_POS_RIGHT;
+ }
+ }
+ if( LINENUMBER_POS_LEFT == ePos )
+ {
+ bGoLeft = sal_True;
+ nX -= rLineInf.GetPosFromLeft();
+ if( nX < aRect.Left() )
+ bLineNum = sal_False;
+ }
+ else
+ {
+ bGoLeft = sal_False;
+ nX += pFrm->Frm().Width() + rLineInf.GetPosFromLeft();
+ if( nX > aRect.Right() )
+ bLineNum = sal_False;
+ }
+ }
+ if( eHor != text::HoriOrientation::NONE )
+ {
+ if( text::HoriOrientation::INSIDE == eHor || text::HoriOrientation::OUTSIDE == eHor )
+ {
+ if( !nVirtPageNum )
+ nVirtPageNum = pFrm->FindPageFrm()->OnRightPage() ? 1 : 2;
+ if( nVirtPageNum % 2 )
+ eHor = eHor == text::HoriOrientation::INSIDE ? text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
+ else
+ eHor = eHor == text::HoriOrientation::OUTSIDE ? text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
+ }
+ const SwFrm* pTmpFrm = pFrm->FindTabFrm();
+ if( !pTmpFrm )
+ pTmpFrm = pFrm;
+ nRedX = text::HoriOrientation::LEFT == eHor ? pTmpFrm->Frm().Left() - REDLINE_DISTANCE :
+ pTmpFrm->Frm().Right() + REDLINE_DISTANCE;
+ }
+}
+
+/*************************************************************************
+ * SwExtraPainter::PaintExtra()
+ **************************************************************************/
+
+void SwExtraPainter::PaintExtra( SwTwips nY, long nAsc, long nMax, sal_Bool bRed )
+{
+ //Zeilennummer ist staerker als der Teiler
+ const XubString aTmp( HasNumber() ? rLineInf.GetNumType().GetNumStr( nLineNr )
+ : rLineInf.GetDivider() );
+
+ // get script type of line numbering:
+ pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmp, 0 ) );
+
+ SwDrawTextInfo aDrawInf( pSh, *pSh->GetOut(), 0, aTmp, 0, aTmp.Len() );
+ aDrawInf.SetSpace( 0 );
+ aDrawInf.SetWrong( NULL );
+ aDrawInf.SetGrammarCheck( NULL );
+ aDrawInf.SetSmartTags( NULL ); // SMARTTAGS
+ aDrawInf.SetLeft( 0 );
+ aDrawInf.SetRight( LONG_MAX );
+ aDrawInf.SetFrm( pTxtFrm );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( sal_False );
+ aDrawInf.SetIgnoreFrmRTL( sal_True );
+
+ sal_Bool bTooBig = pFnt->GetSize( pFnt->GetActual() ).Height() > nMax &&
+ pFnt->GetHeight( pSh, *pSh->GetOut() ) > nMax;
+ SwFont* pTmpFnt;
+ if( bTooBig )
+ {
+ pTmpFnt = new SwFont( *GetFont() );
+ if( nMax >= 20 )
+ {
+ nMax *= 17;
+ nMax /= 20;
+ }
+ pTmpFnt->SetSize( Size( 0, nMax ), pTmpFnt->GetActual() );
+ }
+ else
+ pTmpFnt = GetFont();
+ Point aTmpPos( nX, nY );
+ aTmpPos.Y() += nAsc;
+ sal_Bool bPaint = sal_True;
+ if( !IsClipChg() )
+ {
+ Size aSize = pTmpFnt->_GetTxtSize( aDrawInf );
+ if( bGoLeft )
+ aTmpPos.X() -= aSize.Width();
+ // calculate rectangle containing the line number
+ SwRect aRct( Point( aTmpPos.X(),
+ aTmpPos.Y() - pTmpFnt->GetAscent( pSh, *pSh->GetOut() )
+ ), aSize );
+ if( !aRect.IsInside( aRct ) )
+ {
+ if( aRct.Intersection( aRect ).IsEmpty() )
+ bPaint = sal_False;
+ else
+ aClip.ChgClip( aRect, pTxtFrm );
+ }
+ }
+ else if( bGoLeft )
+ aTmpPos.X() -= pTmpFnt->_GetTxtSize( aDrawInf ).Width();
+ aDrawInf.SetPos( aTmpPos );
+ if( bPaint )
+ pTmpFnt->_DrawText( aDrawInf );
+
+ if( bTooBig )
+ delete pTmpFnt;
+ if( bRed )
+ {
+ long nDiff = bGoLeft ? nRedX - nX : nX - nRedX;
+ if( nDiff > REDLINE_MINDIST )
+ PaintRedline( nY, nMax );
+ }
+}
+
+void SwExtraPainter::PaintRedline( SwTwips nY, long nMax )
+{
+ Point aStart( nRedX, nY );
+ Point aEnd( nRedX, nY + nMax );
+
+ if( !IsClipChg() )
+ {
+ SwRect aRct( aStart, aEnd );
+ if( !aRect.IsInside( aRct ) )
+ {
+ if( aRct.Intersection( aRect ).IsEmpty() )
+ return;
+ aClip.ChgClip( aRect, pTxtFrm );
+ }
+ }
+ const Color aOldCol( pSh->GetOut()->GetLineColor() );
+ pSh->GetOut()->SetLineColor( SW_MOD()->GetRedlineMarkColor() );
+
+ if ( pTxtFrm->IsVertical() )
+ {
+ pTxtFrm->SwitchHorizontalToVertical( aStart );
+ pTxtFrm->SwitchHorizontalToVertical( aEnd );
+ }
+
+ pSh->GetOut()->DrawLine( aStart, aEnd );
+ pSh->GetOut()->SetLineColor( aOldCol );
+}
+
+void SwTxtFrm::PaintExtraData( const SwRect &rRect ) const
+{
+ if( Frm().Top() > rRect.Bottom() || Frm().Bottom() < rRect.Top() )
+ return;
+
+ const SwTxtNode& rTxtNode = *GetTxtNode();
+ const IDocumentRedlineAccess* pIDRA = rTxtNode.getIDocumentRedlineAccess();
+ const SwLineNumberInfo &rLineInf = rTxtNode.getIDocumentLineNumberAccess()->GetLineNumberInfo();
+ const SwFmtLineNumber &rLineNum = GetAttrSet()->GetLineNumber();
+ sal_Bool bLineNum = !IsInTab() && rLineInf.IsPaintLineNumbers() &&
+ ( !IsInFly() || rLineInf.IsCountInFlys() ) && rLineNum.IsCount();
+ sal_Int16 eHor = (sal_Int16)SW_MOD()->GetRedlineMarkPos();
+ if( eHor != text::HoriOrientation::NONE && !IDocumentRedlineAccess::IsShowChanges( pIDRA->GetRedlineMode() ) )
+ eHor = text::HoriOrientation::NONE;
+ sal_Bool bRedLine = eHor != text::HoriOrientation::NONE;
+ if ( bLineNum || bRedLine )
+ {
+ if( IsLocked() || IsHiddenNow() || !Prt().Height() )
+ return;
+ ViewShell *pSh = GetShell();
+
+ SWAP_IF_NOT_SWAPPED( this )
+ SwRect rOldRect( rRect );
+
+ if ( IsVertical() )
+ SwitchVerticalToHorizontal( (SwRect&)rRect );
+
+ SwLayoutModeModifier aLayoutModeModifier( *pSh->GetOut() );
+ aLayoutModeModifier.Modify( sal_False );
+
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pSh->GetOut() );
+ // <--
+
+ SwExtraPainter aExtra( this, pSh, rLineInf, rRect, eHor, bLineNum );
+
+ if( HasPara() )
+ {
+ SwTxtFrmLocker aLock((SwTxtFrm*)this);
+
+ SwTxtLineAccess aAccess( (SwTxtFrm*)this );
+ aAccess.GetPara();
+
+ SwTxtPaintInfo aInf( (SwTxtFrm*)this, rRect );
+
+ aLayoutModeModifier.Modify( sal_False );
+
+ SwTxtPainter aLine( (SwTxtFrm*)this, &aInf );
+ sal_Bool bNoDummy = !aLine.GetNext(); // Nur eine Leerzeile!
+
+ while( aLine.Y() + aLine.GetLineHeight() <= rRect.Top() )
+ {
+ if( !aLine.GetCurr()->IsDummy() &&
+ ( rLineInf.IsCountBlankLines() ||
+ aLine.GetCurr()->HasCntnt() ) )
+ aExtra.IncLineNr();
+ if( !aLine.Next() )
+ {
+ (SwRect&)rRect = rOldRect;
+ UNDO_SWAP( this )
+ return;
+ }
+ }
+
+ long nBottom = rRect.Bottom();
+
+ sal_Bool bNoPrtLine = 0 == GetMinPrtLine();
+ if( !bNoPrtLine )
+ {
+ while ( aLine.Y() < GetMinPrtLine() )
+ {
+ if( ( rLineInf.IsCountBlankLines() || aLine.GetCurr()->HasCntnt() )
+ && !aLine.GetCurr()->IsDummy() )
+ aExtra.IncLineNr();
+ if( !aLine.Next() )
+ break;
+ }
+ bNoPrtLine = aLine.Y() >= GetMinPrtLine();
+ }
+ if( bNoPrtLine )
+ {
+ do
+ {
+ if( bNoDummy || !aLine.GetCurr()->IsDummy() )
+ {
+ sal_Bool bRed = bRedLine && aLine.GetCurr()->HasRedline();
+ if( rLineInf.IsCountBlankLines() || aLine.GetCurr()->HasCntnt() )
+ {
+ if( bLineNum &&
+ ( aExtra.HasNumber() || aExtra.HasDivider() ) )
+ {
+ KSHORT nTmpHeight, nTmpAscent;
+ aLine.CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+ aExtra.PaintExtra( aLine.Y(), nTmpAscent,
+ nTmpHeight, bRed );
+ bRed = sal_False;
+ }
+ aExtra.IncLineNr();
+ }
+ if( bRed )
+ aExtra.PaintRedline( aLine.Y(), aLine.GetLineHeight() );
+ }
+ } while( aLine.Next() && aLine.Y() <= nBottom );
+ }
+ }
+ else
+ {
+ bRedLine &= ( MSHRT_MAX!= pIDRA->GetRedlinePos(rTxtNode, USHRT_MAX) );
+
+ if( bLineNum && rLineInf.IsCountBlankLines() &&
+ ( aExtra.HasNumber() || aExtra.HasDivider() ) )
+ {
+ aExtra.PaintExtra( Frm().Top()+Prt().Top(), aExtra.GetFont()
+ ->GetAscent( pSh, *pSh->GetOut() ), Prt().Height(), bRedLine );
+ }
+ else if( bRedLine )
+ aExtra.PaintRedline( Frm().Top()+Prt().Top(), Prt().Height() );
+ }
+
+ (SwRect&)rRect = rOldRect;
+ UNDO_SWAP( this )
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::Paint()
+ *************************************************************************/
+
+SwRect SwTxtFrm::Paint()
+{
+#if OSL_DEBUG_LEVEL > 1
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+#endif
+
+ // finger layout
+ ASSERT( GetValidPosFlag(), "+SwTxtFrm::Paint: no Calc()" );
+
+ SwRect aRet( Prt() );
+ if ( IsEmpty() || !HasPara() )
+ aRet += Frm().Pos();
+ else
+ {
+ // AMA: Wir liefern jetzt mal das richtige Repaintrechteck zurueck,
+ // d.h. als linken Rand den berechneten PaintOfst!
+ SwRepaint *pRepaint = GetPara()->GetRepaint();
+ long l;
+ if( pRepaint->GetOfst() )
+ pRepaint->Left( pRepaint->GetOfst() );
+
+ l = pRepaint->GetRightOfst();
+ if( l && ( pRepaint->GetOfst() || l > pRepaint->Right() ) )
+ pRepaint->Right( l );
+ pRepaint->SetOfst( 0 );
+ aRet = *pRepaint;
+
+ if ( IsRightToLeft() )
+ SwitchLTRtoRTL( aRet );
+
+ if ( IsVertical() )
+ SwitchHorizontalToVertical( aRet );
+ }
+ ResetRepaint();
+
+ return aRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::Paint()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::PaintEmpty( const SwRect &rRect, sal_Bool bCheck ) const
+{
+ ViewShell *pSh = GetShell();
+ if( pSh && ( pSh->GetViewOptions()->IsParagraph() || bInitFont ) )
+ {
+ bInitFont = sal_False;
+ SwTxtFly aTxtFly( this );
+ aTxtFly.SetTopRule();
+ SwRect aRect;
+ if( bCheck && aTxtFly.IsOn() && aTxtFly.IsAnyObj( aRect ) )
+ return sal_False;
+ else if( pSh->GetWin() )
+ {
+ SwFont *pFnt;
+ const SwTxtNode& rTxtNode = *GetTxtNode();
+ if ( rTxtNode.HasSwAttrSet() )
+ {
+ const SwAttrSet *pAttrSet = &( rTxtNode.GetSwAttrSet() );
+ pFnt = new SwFont( pAttrSet, rTxtNode.getIDocumentSettingAccess() );
+ }
+ else
+ {
+ SwFontAccess aFontAccess( &rTxtNode.GetAnyFmtColl(), pSh );
+ pFnt = new SwFont( *aFontAccess.Get()->GetFont() );
+ }
+
+ const IDocumentRedlineAccess* pIDRA = rTxtNode.getIDocumentRedlineAccess();
+ if( IDocumentRedlineAccess::IsShowChanges( pIDRA->GetRedlineMode() ) )
+ {
+ MSHORT nRedlPos = pIDRA->GetRedlinePos( rTxtNode, USHRT_MAX );
+ if( MSHRT_MAX != nRedlPos )
+ {
+ SwAttrHandler aAttrHandler;
+ aAttrHandler.Init( rTxtNode.GetSwAttrSet(),
+ *rTxtNode.getIDocumentSettingAccess(), NULL );
+ SwRedlineItr aRedln( rTxtNode, *pFnt, aAttrHandler, nRedlPos, sal_True );
+ }
+ }
+
+ if( pSh->GetViewOptions()->IsParagraph() && Prt().Height() )
+ {
+ if( RTL_TEXTENCODING_SYMBOL == pFnt->GetCharSet( SW_LATIN ) &&
+ pFnt->GetName( SW_LATIN ) != numfunc::GetDefBulletFontname() )
+ {
+ pFnt->SetFamily( FAMILY_DONTKNOW, SW_LATIN );
+ pFnt->SetName( numfunc::GetDefBulletFontname(), SW_LATIN );
+ pFnt->SetStyleName( aEmptyStr, SW_LATIN );
+ pFnt->SetCharSet( RTL_TEXTENCODING_SYMBOL, SW_LATIN );
+ }
+ pFnt->SetVertical( 0, IsVertical() );
+ SwFrmSwapper aSwapper( this, sal_True );
+ SwLayoutModeModifier aLayoutModeModifier( *pSh->GetOut() );
+ aLayoutModeModifier.Modify( IsRightToLeft() );
+
+ pFnt->Invalidate();
+ pFnt->ChgPhysFnt( pSh, *pSh->GetOut() );
+ Point aPos = Frm().Pos() + Prt().Pos();
+
+ const SvxLRSpaceItem &rSpace =
+ GetTxtNode()->GetSwAttrSet().GetLRSpace();
+
+ if ( rSpace.GetTxtFirstLineOfst() > 0 )
+ aPos.X() += rSpace.GetTxtFirstLineOfst();
+
+ SwSaveClip *pClip;
+ if( IsUndersized() )
+ {
+ pClip = new SwSaveClip( pSh->GetOut() );
+ pClip->ChgClip( rRect );
+ }
+ else
+ pClip = NULL;
+
+ aPos.Y() += pFnt->GetAscent( pSh, *pSh->GetOut() );
+
+ if ( GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() &&
+ IsInDocBody() )
+ {
+ GETGRID( FindPageFrm() )
+ if ( pGrid )
+ {
+ // center character in grid line
+ aPos.Y() += ( pGrid->GetBaseHeight() -
+ pFnt->GetHeight( pSh, *pSh->GetOut() ) ) / 2;
+
+ if ( ! pGrid->GetRubyTextBelow() )
+ aPos.Y() += pGrid->GetRubyHeight();
+ }
+ }
+
+ const XubString aTmp( CH_PAR );
+ SwDrawTextInfo aDrawInf( pSh, *pSh->GetOut(), 0, aTmp, 0, 1 );
+ aDrawInf.SetLeft( rRect.Left() );
+ aDrawInf.SetRight( rRect.Right() );
+ aDrawInf.SetPos( aPos );
+ aDrawInf.SetSpace( 0 );
+ aDrawInf.SetKanaComp( 0 );
+ aDrawInf.SetWrong( NULL );
+ aDrawInf.SetGrammarCheck( NULL );
+ aDrawInf.SetSmartTags( NULL ); // SMARTTAGS
+ aDrawInf.SetFrm( this );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( sal_False );
+
+ pFnt->_DrawText( aDrawInf );
+ delete pClip;
+ }
+ delete pFnt;
+ return sal_True;
+ }
+ }
+ else
+ return sal_True;
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtFrm::Paint()
+ *************************************************************************/
+
+void SwTxtFrm::Paint( const SwRect &rRect, const SwPrtOptions * /*pPrintData*/ ) const
+{
+ ResetRepaint();
+
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ ViewShell *pSh = GetShell();
+
+ Num_Info aNumInfo( *this );
+ SwTaggedPDFHelper aTaggedPDFHelperNumbering( &aNumInfo, 0, 0, *pSh->GetOut() );
+
+ Frm_Info aFrmInfo( *this );
+ SwTaggedPDFHelper aTaggedPDFHelperParagraph( 0, &aFrmInfo, 0, *pSh->GetOut() );
+ // <--
+
+ DBG_LOOP_RESET;
+ if( !IsEmpty() || !PaintEmpty( rRect, sal_True ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+#endif
+
+#ifdef DBGTXT
+ if( IsDbg( this ) )
+ DBTXTFRM << "Paint()" << endl;
+#endif
+ if( IsLocked() || IsHiddenNow() || ! Prt().HasArea() )
+ return;
+
+ //Kann gut sein, dass mir der IdleCollector mir die gecachten
+ //Informationen entzogen hat.
+ if( !HasPara() )
+ {
+ ASSERT( GetValidPosFlag(), "+SwTxtFrm::Paint: no Calc()" );
+
+ // --> FME 2004-10-29 #i29062# pass info that we are currently
+ // painting.
+ ((SwTxtFrm*)this)->GetFormatted( true );
+ // <--
+ if( IsEmpty() )
+ {
+ PaintEmpty( rRect, sal_False );
+ return;
+ }
+ if( !HasPara() )
+ {
+ ASSERT( !this, "+SwTxtFrm::Paint: missing format information" );
+ return;
+ }
+ }
+
+ // Waehrend wir painten, wollen wir nicht gestoert werden.
+ // Aber erst hinter dem Format() !
+ SwTxtFrmLocker aLock((SwTxtFrm*)this);
+
+ //Hier wird ggf. nur der Teil des TxtFrm ausgegeben, der sich veraendert
+ //hat und der in dem Bereich liegt, dessen Ausgabe angefordert wurde.
+ //Man kann jetzt auf die Idee kommen, dass der Bereich rRect ausgegeben
+ //werden _muss_ obwohl rRepaint gesetzt ist; in der Tat kann dieses
+ //Problem nicht formal vermieden werden. Gluecklicherweise koennen
+ //wir davon ausgehen, dass rRepaint immer dann leer ist, wenn der Frm
+ //komplett gepainted werden muss.
+ SwTxtLineAccess aAccess( (SwTxtFrm*)this );
+ SwParaPortion *pPara = aAccess.GetPara();
+
+ SwRepaint &rRepaint = *(pPara->GetRepaint());
+
+ // Das Recycling muss abgeschaltet werden, wenn wir uns im
+ // FlyCntFrm befinden, weil ein DrawRect fuer die Retusche der
+ // Zeile aufgerufen wird.
+ if( rRepaint.GetOfst() )
+ {
+ const SwFlyFrm *pFly = FindFlyFrm();
+ if( pFly && pFly->IsFlyInCntFrm() )
+ rRepaint.SetOfst( 0 );
+ }
+
+ // Hier holen wir uns den String fuer die Ausgabe, besonders
+ // die Laenge ist immer wieder interessant.
+
+ // Rectangle
+ ASSERT( ! IsSwapped(), "A frame is swapped before Paint" );
+ SwRect aOldRect( rRect );
+
+ SWAP_IF_NOT_SWAPPED( this )
+
+ if ( IsVertical() )
+ SwitchVerticalToHorizontal( (SwRect&)rRect );
+
+ if ( IsRightToLeft() )
+ SwitchRTLtoLTR( (SwRect&)rRect );
+
+ SwTxtPaintInfo aInf( (SwTxtFrm*)this, rRect );
+ aInf.SetWrongList( ( (SwTxtNode*)GetTxtNode() )->GetWrong() );
+ aInf.SetGrammarCheckList( ( (SwTxtNode*)GetTxtNode() )->GetGrammarCheck() );
+ aInf.SetSmartTags( ( (SwTxtNode*)GetTxtNode() )->GetSmartTags() ); // SMARTTAGS
+ aInf.GetTxtFly()->SetTopRule();
+
+ SwTxtPainter aLine( (SwTxtFrm*)this, &aInf );
+ // Eine Optimierung, die sich lohnt: wenn kein freifliegender Frame
+ // in unsere Zeile ragt, schaltet sich der SwTxtFly einfach ab:
+ aInf.GetTxtFly()->Relax();
+
+ OutputDevice* pOut = aInf.GetOut();
+ const sal_Bool bOnWin = pSh->GetWin() != 0;
+
+ SwSaveClip aClip( bOnWin || IsUndersized() ? pOut : 0 );
+
+ // Ausgabeschleife: Fuer jede Zeile ... (die noch zu sehen ist) ...
+ // rRect muss angepasst werden (Top+1, Bottom-1), weil der Iterator
+ // die Zeilen nahtlos aneinanderfuegt.
+ aLine.TwipsToLine( rRect.Top() + 1 );
+ long nBottom = rRect.Bottom();
+
+ sal_Bool bNoPrtLine = 0 == GetMinPrtLine();
+ if( !bNoPrtLine )
+ {
+ while ( aLine.Y() < GetMinPrtLine() && aLine.Next() )
+ ;
+ bNoPrtLine = aLine.Y() >= GetMinPrtLine();
+ }
+ if( bNoPrtLine )
+ {
+ do
+ {
+ //DBG_LOOP; shadows declaration above.
+ //resolved into:
+#if OSL_DEBUG_LEVEL > 1
+#ifdef DBG_UTIL
+ DbgLoop aDbgLoop2( (const void*) this );
+#endif
+#endif
+ aLine.DrawTextLine( rRect, aClip, IsUndersized() );
+
+ } while( aLine.Next() && aLine.Y() <= nBottom );
+ }
+
+ // Einmal reicht:
+ if( aLine.IsPaintDrop() )
+ aLine.PaintDropPortion();
+
+ if( rRepaint.HasArea() )
+ rRepaint.Clear();
+
+ UNDO_SWAP( this )
+ (SwRect&)rRect = aOldRect;
+
+ ASSERT( ! IsSwapped(), "A frame is swapped after Paint" );
+ }
+}
+
diff --git a/sw/source/core/text/guess.cxx b/sw/source/core/text/guess.cxx
new file mode 100644
index 000000000000..4c9ad8022157
--- /dev/null
+++ b/sw/source/core/text/guess.cxx
@@ -0,0 +1,554 @@
+/*************************************************************************
+ *
+ * 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 <ctype.h>
+#include <editeng/unolingu.hxx>
+#include <tools/shl.hxx> // needed for SW_MOD() macro
+#include <errhdl.hxx> // ASSERTs
+#include <dlelstnr.hxx>
+#include <swmodule.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <txtcfg.hxx>
+#include <guess.hxx>
+#include <inftxt.hxx>
+#include <pagefrm.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <com/sun/star/i18n/BreakType.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <unotools/charclass.hxx>
+#include <porfld.hxx>
+
+using ::rtl::OUString;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::linguistic2;
+
+#define CH_FULL_BLANK 0x3000
+
+/*************************************************************************
+ * SwTxtGuess::Guess
+ *
+ * provides information for line break calculation
+ * returns true if no line break has to be performed
+ * otherwise possible break or hyphenation position is determined
+ *************************************************************************/
+
+sal_Bool SwTxtGuess::Guess( const SwTxtPortion& rPor, SwTxtFormatInfo &rInf,
+ const KSHORT nPorHeight )
+{
+ nCutPos = rInf.GetIdx();
+
+ // Leere Strings sind immer 0
+ if( !rInf.GetLen() || !rInf.GetTxt().Len() )
+ return sal_False;
+
+ ASSERT( rInf.GetIdx() < rInf.GetTxt().Len(),
+ "+SwTxtGuess::Guess: invalid SwTxtFormatInfo" );
+
+ ASSERT( nPorHeight, "+SwTxtGuess::Guess: no height" );
+
+ USHORT nMinSize;
+ USHORT nMaxSizeDiff;
+
+ const SwScriptInfo& rSI =
+ ((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo();
+
+ USHORT nMaxComp = ( SW_CJK == rInf.GetFont()->GetActual() ) &&
+ rSI.CountCompChg() &&
+ ! rInf.IsMulti() &&
+ ! rPor.InFldGrp() &&
+ ! rPor.IsDropPortion() ?
+ 10000 :
+ 0 ;
+
+ SwTwips nLineWidth = rInf.Width() - rInf.X();
+ xub_StrLen nMaxLen = rInf.GetTxt().Len() - rInf.GetIdx();
+
+ if ( rInf.GetLen() < nMaxLen )
+ nMaxLen = rInf.GetLen();
+
+ if( !nMaxLen )
+ return sal_False;
+
+ KSHORT nItalic = 0;
+ if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
+ {
+ sal_Bool bAddItalic = sal_True;
+
+ // do not add extra italic value if we have an active character grid
+ if ( rInf.SnapToGrid() )
+ {
+ GETGRID( rInf.GetTxtFrm()->FindPageFrm() )
+ bAddItalic = !pGrid || GRID_LINES_CHARS != pGrid->GetGridType();
+ }
+
+ // do not add extra italic value for an isolated blank:
+ if ( 1 == rInf.GetLen() &&
+ CH_BLANK == rInf.GetTxt().GetChar( rInf.GetIdx() ) )
+ bAddItalic = sal_False;
+
+ nItalic = bAddItalic ? nPorHeight / 12 : 0;
+
+ nLineWidth -= nItalic;
+
+ // --> FME 2005-05-13 #i46524# LineBreak bug with italics
+ if ( nLineWidth < 0 ) nLineWidth = 0;
+ // <--
+ }
+
+ // first check if everything fits to line
+ if ( long ( nLineWidth ) * 2 > long ( nMaxLen ) * nPorHeight )
+ {
+ // call GetTxtSize with maximum compression (for kanas)
+ rInf.GetTxtSize( &rSI, rInf.GetIdx(), nMaxLen,
+ nMaxComp, nMinSize, nMaxSizeDiff );
+
+ nBreakWidth = nMinSize;
+
+ if ( nBreakWidth <= nLineWidth )
+ {
+ // portion fits to line
+ nCutPos = rInf.GetIdx() + nMaxLen;
+ if( nItalic &&
+ ( nCutPos >= rInf.GetTxt().Len() ||
+ // --> FME 2005-05-13 #i48035# Needed for CalcFitToContent
+ // if first line ends with a manual line break
+ rInf.GetTxt().GetChar( nCutPos ) == CH_BREAK ) )
+ // <--
+ nBreakWidth = nBreakWidth + nItalic;
+
+ // save maximum width for later use
+ if ( nMaxSizeDiff )
+ rInf.SetMaxWidthDiff( (ULONG)&rPor, nMaxSizeDiff );
+
+ return sal_True;
+ }
+ }
+
+ sal_Bool bHyph = rInf.IsHyphenate() && !rInf.IsHyphForbud();
+ xub_StrLen nHyphPos = 0;
+
+ // nCutPos is the first character not fitting to the current line
+ // nHyphPos is the first character not fitting to the current line,
+ // considering an additional "-" for hyphenation
+ if( bHyph )
+ {
+ nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos );
+
+ if ( !nHyphPos && rInf.GetIdx() )
+ nHyphPos = rInf.GetIdx() - 1;
+ }
+ else
+ {
+ nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp );
+
+#ifdef DBG_UTIL
+ if ( STRING_LEN != nCutPos )
+ {
+ rInf.GetTxtSize( &rSI, rInf.GetIdx(), nCutPos - rInf.GetIdx(),
+ nMaxComp, nMinSize, nMaxSizeDiff );
+ ASSERT( nMinSize <= nLineWidth, "What a Guess!!!" );
+ }
+#endif
+ }
+
+ if( nCutPos > rInf.GetIdx() + nMaxLen )
+ {
+ // second check if everything fits to line
+ nCutPos = nBreakPos = rInf.GetIdx() + nMaxLen - 1;
+ rInf.GetTxtSize( &rSI, rInf.GetIdx(), nMaxLen, nMaxComp,
+ nMinSize, nMaxSizeDiff );
+
+ nBreakWidth = nMinSize;
+
+ // Der folgende Vergleich sollte eigenlich immer sal_True ergeben, sonst
+ // hat es wohl bei GetTxtBreak einen Pixel-Rundungsfehler gegeben...
+ if ( nBreakWidth <= nLineWidth )
+ {
+ if( nItalic && ( nBreakPos + 1 ) >= rInf.GetTxt().Len() )
+ nBreakWidth = nBreakWidth + nItalic;
+
+ // save maximum width for later use
+ if ( nMaxSizeDiff )
+ rInf.SetMaxWidthDiff( (ULONG)&rPor, nMaxSizeDiff );
+
+ return sal_True;
+ }
+ }
+
+ // we have to trigger an underflow for a footnote portion
+ // which does not fit to the current line
+ if ( rPor.IsFtnPortion() )
+ {
+ nBreakPos = rInf.GetIdx();
+ nCutPos = rInf.GetLen();
+ return sal_False;
+ }
+
+ xub_StrLen nPorLen = 0;
+ // do not call the break iterator nCutPos is a blank
+ xub_Unicode cCutChar = rInf.GetTxt().GetChar( nCutPos );
+ if( CH_BLANK == cCutChar || CH_FULL_BLANK == cCutChar )
+ {
+ nBreakPos = nCutPos;
+ xub_StrLen nX = nBreakPos;
+
+ // we step back until a non blank character has been found
+ // or there is only one more character left
+ while( nX && nBreakPos > rInf.GetLineStart() + 1 &&
+ ( CH_BLANK == ( cCutChar = rInf.GetChar( --nX ) ) ||
+ CH_FULL_BLANK == cCutChar ) )
+ --nBreakPos;
+
+ if( nBreakPos > rInf.GetIdx() )
+ nPorLen = nBreakPos - rInf.GetIdx();
+ while( ++nCutPos < rInf.GetTxt().Len() &&
+ ( CH_BLANK == ( cCutChar = rInf.GetChar( nCutPos ) ) ||
+ CH_FULL_BLANK == cCutChar ) )
+ ; // nothing
+
+ nBreakStart = nCutPos;
+ }
+ else if( pBreakIt->GetBreakIter().is() )
+ {
+ // New: We should have a look into the last portion, if it was a
+ // field portion. For this, we expand the text of the field portion
+ // into our string. If the line break position is inside of before
+ // the field portion, we trigger an underflow.
+
+ xub_StrLen nOldIdx = rInf.GetIdx();
+ xub_Unicode cFldChr = 0;
+
+#if OSL_DEBUG_LEVEL > 1
+ XubString aDebugString;
+#endif
+
+ // be careful: a field portion can be both: 0x01 (common field)
+ // or 0x02 (the follow of a footnode)
+ if ( rInf.GetLast() && rInf.GetLast()->InFldGrp() &&
+ ! rInf.GetLast()->IsFtnPortion() &&
+ rInf.GetIdx() > rInf.GetLineStart() &&
+ CH_TXTATR_BREAKWORD ==
+ ( cFldChr = rInf.GetTxt().GetChar( rInf.GetIdx() - 1 ) ) )
+ {
+ SwFldPortion* pFld = (SwFldPortion*)rInf.GetLast();
+ XubString aTxt;
+ pFld->GetExpTxt( rInf, aTxt );
+
+ if ( aTxt.Len() )
+ {
+ nFieldDiff = aTxt.Len() - 1;
+ nCutPos = nCutPos + nFieldDiff;
+ nHyphPos = nHyphPos + nFieldDiff;
+
+#if OSL_DEBUG_LEVEL > 1
+ aDebugString = rInf.GetTxt();
+#endif
+
+ XubString& rOldTxt = (XubString&)rInf.GetTxt();
+ rOldTxt.Erase( rInf.GetIdx() - 1, 1 );
+ rOldTxt.Insert( aTxt, rInf.GetIdx() - 1 );
+ rInf.SetIdx( rInf.GetIdx() + nFieldDiff );
+ }
+ else
+ cFldChr = 0;
+ }
+
+ LineBreakHyphenationOptions aHyphOpt;
+ Reference< XHyphenator > xHyph;
+ if( bHyph )
+ {
+ xHyph = ::GetHyphenator();
+ aHyphOpt = LineBreakHyphenationOptions( xHyph,
+ rInf.GetHyphValues(), nHyphPos );
+ }
+
+ // Get Language for break iterator.
+ // We have to switch the current language if we have a script
+ // change at nCutPos. Otherwise LATIN punctuation would never
+ // be allowed to be hanging punctuation.
+ // NEVER call GetLang if the string has been modified!!!
+ LanguageType aLang = rInf.GetFont()->GetLanguage();
+
+ // If we are inside a field portion, we use a temporar string which
+ // differs from the string at the textnode. Therefore we are not allowed
+ // to call the GetLang function.
+ if ( nCutPos && ! rPor.InFldGrp() )
+ {
+ const CharClass& rCC = GetAppCharClass();
+
+ // step back until a non-punctuation character is reached
+ xub_StrLen nLangIndex = nCutPos;
+
+ // If a field has been expanded right in front of us we do not
+ // step further than the beginning of the expanded field
+ // (which is the position of the field placeholder in our
+ // original string).
+ const xub_StrLen nDoNotStepOver = CH_TXTATR_BREAKWORD == cFldChr ?
+ rInf.GetIdx() - nFieldDiff - 1:
+ 0;
+
+ while ( nLangIndex > nDoNotStepOver &&
+ ! rCC.isLetterNumeric( rInf.GetTxt(), nLangIndex ) )
+ --nLangIndex;
+
+ // last "real" character is not inside our current portion
+ // we have to check the script type of the last "real" character
+ if ( nLangIndex < rInf.GetIdx() )
+ {
+ USHORT nScript = pBreakIt->GetRealScriptOfText( rInf.GetTxt(),
+ nLangIndex );
+ ASSERT( nScript, "Script is not between 1 and 4" );
+
+ // compare current script with script from last "real" character
+ if ( nScript - 1 != rInf.GetFont()->GetActual() )
+ aLang = rInf.GetTxtFrm()->GetTxtNode()->GetLang(
+ CH_TXTATR_BREAKWORD == cFldChr ?
+ nDoNotStepOver :
+ nLangIndex, 0, nScript );
+ }
+ }
+
+ const ForbiddenCharacters aForbidden(
+ *rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->getForbiddenCharacters( aLang, true ) );
+
+ const sal_Bool bAllowHanging = rInf.IsHanging() && ! rInf.IsMulti() &&
+ ! rPor.InFldGrp();
+
+ LineBreakUserOptions aUserOpt(
+ aForbidden.beginLine, aForbidden.endLine,
+ rInf.HasForbiddenChars(), bAllowHanging, sal_False );
+
+ //! register listener to LinguServiceEvents now in order to get
+ //! notified about relevant changes in the future
+ SwModule *pModule = SW_MOD();
+ if (!pModule->GetLngSvcEvtListener().is())
+ pModule->CreateLngSvcEvtListener();
+
+ // !!! We must have a local copy of the locale, because inside
+ // getLineBreak the LinguEventListener can trigger a new formatting,
+ // which can corrupt the locale pointer inside pBreakIt.
+ const lang::Locale aLocale = pBreakIt->GetLocale( aLang );
+
+ // determines first possible line break from nRightPos to
+ // start index of current line
+ LineBreakResults aResult = pBreakIt->GetBreakIter()->getLineBreak(
+ rInf.GetTxt(), nCutPos, aLocale,
+ rInf.GetLineStart(), aHyphOpt, aUserOpt );
+
+ nBreakPos = (xub_StrLen)aResult.breakIndex;
+
+ // if we are formatting multi portions we want to allow line breaks
+ // at the border between single line and multi line portion
+ // we have to be carefull with footnote portions, they always come in
+ // with an index 0
+ if ( nBreakPos < rInf.GetLineStart() && rInf.IsFirstMulti() &&
+ ! rInf.IsFtnInside() )
+ nBreakPos = rInf.GetLineStart();
+
+ nBreakStart = nBreakPos;
+
+ bHyph = BreakType::HYPHENATION == aResult.breakType;
+
+ if ( bHyph && nBreakPos != STRING_LEN)
+ {
+ // found hyphenation position within line
+ // nBreakPos is set to the hyphenation position
+ xHyphWord = aResult.rHyphenatedWord;
+ nBreakPos += xHyphWord->getHyphenationPos() + 1;
+
+#if OSL_DEBUG_LEVEL > 1
+ // e.g., Schif-fahrt, referes to our string
+ const String aWord = xHyphWord->getWord();
+ // e.g., Schiff-fahrt, referes to the word after hyphenation
+ const String aHyphenatedWord = xHyphWord->getHyphenatedWord();
+ // e.g., Schif-fahrt: 5, referes to our string
+ const USHORT nHyphenationPos = xHyphWord->getHyphenationPos();
+ (void)nHyphenationPos;
+ // e.g., Schiff-fahrt: 6, referes to the word after hyphenation
+ const USHORT nHyphenPos = xHyphWord->getHyphenPos();
+ (void)nHyphenPos;
+#endif
+
+ // if not in interactive mode, we have to break behind a soft hyphen
+ if ( ! rInf.IsInterHyph() && rInf.GetIdx() )
+ {
+ const long nSoftHyphPos =
+ xHyphWord->getWord().indexOf( CHAR_SOFTHYPHEN );
+
+ if ( nSoftHyphPos >= 0 &&
+ nBreakStart + nSoftHyphPos <= nBreakPos &&
+ nBreakPos > rInf.GetLineStart() )
+ nBreakPos = rInf.GetIdx() - 1;
+ }
+
+ if( nBreakPos >= rInf.GetIdx() )
+ {
+ nPorLen = nBreakPos - rInf.GetIdx();
+ if( '-' == rInf.GetTxt().GetChar( nBreakPos - 1 ) )
+ xHyphWord = NULL;
+ }
+ }
+ else if ( !bHyph && nBreakPos >= rInf.GetLineStart() )
+ {
+ ASSERT( nBreakPos != STRING_LEN, "we should have found a break pos" );
+
+ // found break position within line
+ xHyphWord = NULL;
+
+ // check, if break position is soft hyphen and an underflow
+ // has to be triggered
+ if( nBreakPos > rInf.GetLineStart() && rInf.GetIdx() &&
+ CHAR_SOFTHYPHEN == rInf.GetTxt().GetChar( nBreakPos - 1 ) )
+ nBreakPos = rInf.GetIdx() - 1;
+
+ // Delete any blanks at the end of a line, but be careful:
+ // If a field has been expanded, we do not want to delete any
+ // blanks inside the field portion. This would cause an unwanted
+ // underflow
+ xub_StrLen nX = nBreakPos;
+ while( nX > rInf.GetLineStart() &&
+ ( CH_TXTATR_BREAKWORD != cFldChr || nX > rInf.GetIdx() ) &&
+ ( CH_BLANK == rInf.GetChar( --nX ) ||
+ CH_FULL_BLANK == rInf.GetChar( nX ) ) )
+ nBreakPos = nX;
+ if( nBreakPos > rInf.GetIdx() )
+ nPorLen = nBreakPos - rInf.GetIdx();
+ }
+ else
+ {
+ // no line break found, setting nBreakPos to STRING_LEN
+ // causes a break cut
+ nBreakPos = STRING_LEN;
+ ASSERT( nCutPos >= rInf.GetIdx(), "Deep cut" );
+ nPorLen = nCutPos - rInf.GetIdx();
+ }
+
+ if( nBreakPos > nCutPos && nBreakPos != STRING_LEN )
+ {
+ const xub_StrLen nHangingLen = nBreakPos - nCutPos;
+ SwPosSize aTmpSize = rInf.GetTxtSize( &rSI, nCutPos,
+ nHangingLen, 0 );
+ ASSERT( !pHanging, "A hanging portion is hanging around" );
+ pHanging = new SwHangingPortion( aTmpSize );
+ pHanging->SetLen( nHangingLen );
+ nPorLen = nCutPos - rInf.GetIdx();
+ }
+
+ // If we expanded a field, we must repair the original string.
+ // In case we do not trigger an underflow, we correct the nBreakPos
+ // value, but we cannot correct the nBreakStart value:
+ // If we have found a hyphenation position, nBreakStart can lie before
+ // the field.
+ if ( CH_TXTATR_BREAKWORD == cFldChr )
+ {
+ if ( nBreakPos < rInf.GetIdx() )
+ nBreakPos = nOldIdx - 1;
+ else if ( STRING_LEN != nBreakPos )
+ {
+ ASSERT( nBreakPos >= nFieldDiff, "I've got field trouble!" );
+ nBreakPos = nBreakPos - nFieldDiff;
+ }
+
+ ASSERT( nCutPos >= rInf.GetIdx() && nCutPos >= nFieldDiff,
+ "I've got field trouble, part2!" );
+ nCutPos = nCutPos - nFieldDiff;
+
+ XubString& rOldTxt = (XubString&)rInf.GetTxt();
+ rOldTxt.Erase( nOldIdx - 1, nFieldDiff + 1 );
+ rOldTxt.Insert( cFldChr, nOldIdx - 1 );
+ rInf.SetIdx( nOldIdx );
+
+#if OSL_DEBUG_LEVEL > 1
+ ASSERT( aDebugString == rInf.GetTxt(),
+ "Somebody, somebody, somebody put something in my string" );
+#endif
+ }
+ }
+
+ if( nPorLen )
+ {
+ rInf.GetTxtSize( &rSI, rInf.GetIdx(), nPorLen,
+ nMaxComp, nMinSize, nMaxSizeDiff );
+
+ // save maximum width for later use
+ if ( nMaxSizeDiff )
+ rInf.SetMaxWidthDiff( (ULONG)&rPor, nMaxSizeDiff );
+
+ nBreakWidth = nItalic + nMinSize;
+ }
+ else
+ nBreakWidth = 0;
+
+ if( pHanging )
+ nBreakPos = nCutPos;
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtGuess::AlternativeSpelling
+ *************************************************************************/
+
+// returns true if word at position nPos has a diffenrent spelling
+// if hyphenated at this position (old german spelling)
+
+sal_Bool SwTxtGuess::AlternativeSpelling( const SwTxtFormatInfo &rInf,
+ const xub_StrLen nPos )
+{
+ // get word boundaries
+ xub_StrLen nWordLen;
+
+ Boundary aBound =
+ pBreakIt->GetBreakIter()->getWordBoundary( rInf.GetTxt(), nPos,
+ pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ),
+ WordType::DICTIONARY_WORD, sal_True );
+ nBreakStart = (xub_StrLen)aBound.startPos;
+ nWordLen = static_cast<xub_StrLen>(aBound.endPos - nBreakStart);
+
+ // if everything else fails, we want to cut at nPos
+ nCutPos = nPos;
+
+ XubString aTxt( rInf.GetTxt().Copy( nBreakStart, nWordLen ) );
+
+ // check, if word has alternative spelling
+ Reference< XHyphenator > xHyph( ::GetHyphenator() );
+ ASSERT( xHyph.is(), "Hyphenator is missing");
+ //! subtract 1 since the UNO-interface is 0 based
+ xHyphWord = xHyph->queryAlternativeSpelling( OUString(aTxt),
+ pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ),
+ nPos - nBreakStart, rInf.GetHyphValues() );
+ return xHyphWord.is() && xHyphWord->isAlternativeSpelling();
+}
+
diff --git a/sw/source/core/text/guess.hxx b/sw/source/core/text/guess.hxx
new file mode 100644
index 000000000000..d0ef7b4d5cdb
--- /dev/null
+++ b/sw/source/core/text/guess.hxx
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _GUESS_HXX
+#define _GUESS_HXX
+#include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
+
+#include "txttypes.hxx"
+#include "breakit.hxx"
+#include "porrst.hxx" // SwHangingPortion
+
+class SwTxtFormatInfo;
+
+/*************************************************************************
+ * class SwTxtGuess
+ *************************************************************************/
+
+class SwTxtGuess
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XHyphenatedWord > xHyphWord;
+ SwHangingPortion *pHanging; // for hanging punctuation
+ xub_StrLen nCutPos; // this character doesn't fit
+ xub_StrLen nBreakStart; // start index of word containing line break
+ xub_StrLen nBreakPos; // start index of break position
+ xub_StrLen nFieldDiff; // absolut positions can be wrong if we
+ // a field in the text has been expanded
+ KSHORT nBreakWidth; // width of the broken portion
+public:
+ inline SwTxtGuess(): pHanging( NULL ), nCutPos(0), nBreakStart(0),
+ nBreakPos(0), nFieldDiff(0), nBreakWidth(0)
+ { }
+ ~SwTxtGuess() { delete pHanging; }
+
+ // true, if current portion still fits to current line
+ sal_Bool Guess( const SwTxtPortion& rPor, SwTxtFormatInfo &rInf,
+ const KSHORT nHeight );
+ sal_Bool AlternativeSpelling( const SwTxtFormatInfo &rInf, const xub_StrLen nPos );
+
+ inline SwHangingPortion* GetHangingPortion() const { return pHanging; }
+ inline void ClearHangingPortion() { pHanging = NULL; }
+ inline KSHORT BreakWidth() const { return nBreakWidth; }
+ inline xub_StrLen CutPos() const { return nCutPos; }
+ inline xub_StrLen BreakStart() const { return nBreakStart; }
+ inline xub_StrLen BreakPos() const {return nBreakPos; }
+ inline xub_StrLen FieldDiff() const {return nFieldDiff; }
+ inline ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XHyphenatedWord > HyphWord() const
+ { return xHyphWord; }
+};
+
+#endif
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
new file mode 100644
index 000000000000..ffcf4b53afbd
--- /dev/null
+++ b/sw/source/core/text/inftxt.cxx
@@ -0,0 +1,1977 @@
+/*************************************************************************
+ *
+ * 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/uno/Sequence.h>
+#include <unotools/linguprops.hxx>
+#include <unotools/lingucfg.hxx>
+#include <hintids.hxx>
+#include <sfx2/printer.hxx>
+#include <editeng/hyznitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/hngpnctitem.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/splwrap.hxx>
+#include <editeng/pgrditem.hxx>
+// --> OD 2008-01-17 #newlistlevelattrs#
+#ifndef _SVX_TSTPITEM_HXX
+#include <editeng/tstpitem.hxx>
+#endif
+// <--
+
+#include <SwSmartTagMgr.hxx>
+#include <linguistic/lngprops.hxx>
+#include <editeng/unolingu.hxx>
+#include <breakit.hxx>
+#include <editeng/forbiddenruleitem.hxx>
+#include <txatbase.hxx>
+#include <fmtinfmt.hxx>
+#include <swmodule.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <viewsh.hxx> // ViewShell
+#include <viewopt.hxx> // SwViewOptions
+#include <frmtool.hxx> // DrawGraphic
+#include <IDocumentSettingAccess.hxx>
+#ifndef IDOCUMENTDEVICEACCESS_HXX_INCLUDED
+#include <IDocumentDeviceAccess.hxx>
+#endif
+#include <paratr.hxx> // SwFmtDrop
+#include <rootfrm.hxx> // SwRootFrm
+#include <inftxt.hxx> // SwTxtInfo
+#include <blink.hxx> // SwBlink
+#include <noteurl.hxx> // SwNoteURL
+#include <porftn.hxx> // SwFtnPortion
+#include <porrst.hxx> // SwHangingPortion
+#include <itratr.hxx>
+#include <accessibilityoptions.hxx>
+#include <wrong.hxx>
+#include <doc.hxx>
+#include <pam.hxx>
+#include <SwGrammarMarkUp.hxx>
+#include <cstdio>
+// --> FME 2004-06-08 #i12836# enhanced pdf export
+#include <EnhancedPDFExportHelper.hxx>
+// <--
+
+#include <unomid.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::linguistic2;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+
+#define CHAR_UNDERSCORE ((sal_Unicode)0x005F)
+#define CHAR_LEFT_ARROW ((sal_Unicode)0x25C0)
+#define CHAR_RIGHT_ARROW ((sal_Unicode)0x25B6)
+#define CHAR_TAB ((sal_Unicode)0x2192)
+#define CHAR_TAB_RTL ((sal_Unicode)0x2190)
+#define CHAR_LINEBREAK ((sal_Unicode)0x21B5)
+#define CHAR_LINEBREAK_RTL ((sal_Unicode)0x21B3)
+
+#define DRAW_SPECIAL_OPTIONS_CENTER 1
+#define DRAW_SPECIAL_OPTIONS_ROTATE 2
+
+// --> OD 2006-06-27 #b6440955#
+// variable moved to class <numfunc:GetDefBulletConfig>
+//extern const sal_Char __FAR_DATA sBulletFntName[];
+namespace numfunc
+{
+ extern const String& GetDefBulletFontname();
+ extern bool IsDefBulletFontUserDefined();
+}
+// <--
+
+#ifdef DBG_UTIL
+// Test2: WYSIWYG++
+// Test4: WYSIWYG debug
+static sal_Bool bDbgLow = sal_False;
+#endif
+
+#ifdef DBG_UTIL
+
+sal_Bool SwTxtSizeInfo::IsOptCalm() const { return !GetOpt().IsTest3(); }
+
+sal_Bool SwTxtSizeInfo::IsOptLow() const { return bDbgLow; }
+
+sal_Bool SwTxtSizeInfo::IsOptDbg() const { return GetOpt().IsTest4(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest1() const { return GetOpt().IsTest1(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest2() const { return GetOpt().IsTest2(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest3() const { return GetOpt().IsTest3(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest4() const { return GetOpt().IsTest4(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest5() const { return GetOpt().IsTest5(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest6() const { return GetOpt().IsTest6(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest7() const { return GetOpt().IsTest7(); }
+
+sal_Bool SwTxtSizeInfo::IsOptTest8() const { return GetOpt().IsTest8(); }
+
+#endif
+
+/*************************************************************************
+ * SwLineInfo::SwLineInfo()
+ *************************************************************************/
+
+// --> OD 2008-01-17 #newlistlevelattrs#
+SwLineInfo::SwLineInfo()
+ : pRuler( 0 ),
+ pSpace( 0 ),
+ nVertAlign( 0 ),
+ nDefTabStop( 0 ),
+ bListTabStopIncluded( false ),
+ nListTabStopPosition( 0 )
+{
+}
+
+SwLineInfo::~SwLineInfo()
+{
+ delete pRuler;
+}
+void SwLineInfo::CtorInitLineInfo( const SwAttrSet& rAttrSet,
+ const SwTxtNode& rTxtNode )
+// <--
+{
+ // --> OD 2008-01-17 #newlistlevelattrs#
+// pRuler = &rAttrSet.GetTabStops();
+ delete pRuler;
+ pRuler = new SvxTabStopItem( rAttrSet.GetTabStops() );
+ if ( rTxtNode.GetListTabStopPosition( nListTabStopPosition ) )
+ {
+ bListTabStopIncluded = true;
+
+ // insert the list tab stop into SvxTabItem instance <pRuler>
+ const SvxTabStop aListTabStop( nListTabStopPosition,
+ SVX_TAB_ADJUST_LEFT );
+ pRuler->Insert( aListTabStop );
+
+ // remove default tab stops, which are before the inserted list tab stop
+ for ( USHORT i = 0; i < pRuler->Count(); i++ )
+ {
+ if ( (*pRuler)[i].GetTabPos() < nListTabStopPosition &&
+ (*pRuler)[i].GetAdjustment() == SVX_TAB_ADJUST_DEFAULT )
+ {
+ pRuler->Remove(i);
+ continue;
+ }
+ }
+ }
+ // <--
+ // --> OD 2008-02-15 #newlistlevelattrs#
+ if ( !rTxtNode.getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) )
+ {
+ // remove default tab stop at position 0
+ for ( USHORT i = 0; i < pRuler->Count(); i++ )
+ {
+ if ( (*pRuler)[i].GetTabPos() == 0 &&
+ (*pRuler)[i].GetAdjustment() == SVX_TAB_ADJUST_DEFAULT )
+ {
+ pRuler->Remove(i);
+ break;
+ }
+ }
+ }
+ // <--
+ pSpace = &rAttrSet.GetLineSpacing();
+ nVertAlign = rAttrSet.GetParaVertAlign().GetValue();
+ nDefTabStop = MSHRT_MAX;
+}
+
+/*************************************************************************
+ * SwTxtInfo::CtorInitTxtInfo()
+ *************************************************************************/
+
+void SwTxtInfo::CtorInitTxtInfo( SwTxtFrm *pFrm )
+{
+ pPara = pFrm->GetPara();
+ nTxtStart = pFrm->GetOfst();
+ if( !pPara )
+ {
+ ASSERT( pPara, "+SwTxtInfo::CTOR: missing paragraph information" );
+ pFrm->Format();
+ pPara = pFrm->GetPara();
+ }
+}
+
+SwTxtInfo::SwTxtInfo( const SwTxtInfo &rInf )
+ : pPara( ((SwTxtInfo&)rInf).GetParaPortion() ),
+ nTxtStart( rInf.GetTxtStart() )
+{ }
+
+
+#ifdef DBG_UTIL
+/*************************************************************************
+ * ChkOutDev()
+ *************************************************************************/
+
+void ChkOutDev( const SwTxtSizeInfo &rInf )
+{
+ if ( !rInf.GetVsh() )
+ return;
+
+ const OutputDevice* pOut = rInf.GetOut();
+ const OutputDevice* pRef = rInf.GetRefDev();
+ ASSERT( pOut && pRef, "ChkOutDev: invalid output devices" )
+}
+#endif // PRODUCT
+
+
+inline xub_StrLen GetMinLen( const SwTxtSizeInfo &rInf )
+{
+ const xub_StrLen nInfLen = rInf.GetIdx() + rInf.GetLen();
+ return Min( rInf.GetTxt().Len(), nInfLen );
+}
+
+
+SwTxtSizeInfo::SwTxtSizeInfo( const SwTxtSizeInfo &rNew )
+ : SwTxtInfo( rNew ),
+ pKanaComp(((SwTxtSizeInfo&)rNew).GetpKanaComp()),
+ pVsh(((SwTxtSizeInfo&)rNew).GetVsh()),
+ pOut(((SwTxtSizeInfo&)rNew).GetOut()),
+ pRef(((SwTxtSizeInfo&)rNew).GetRefDev()),
+ pFnt(((SwTxtSizeInfo&)rNew).GetFont()),
+ pUnderFnt(((SwTxtSizeInfo&)rNew).GetUnderFnt()),
+ pFrm(rNew.pFrm),
+ pOpt(&rNew.GetOpt()),
+ pTxt(&rNew.GetTxt()),
+ nIdx(rNew.GetIdx()),
+ nLen(rNew.GetLen()),
+ nKanaIdx( rNew.GetKanaIdx() ),
+ bOnWin( rNew.OnWin() ),
+ bNotEOL( rNew.NotEOL() ),
+ bURLNotify( rNew.URLNotify() ),
+ bStopUnderFlow( rNew.StopUnderFlow() ),
+ bFtnInside( rNew.IsFtnInside() ),
+ bOtherThanFtnInside( rNew.IsOtherThanFtnInside() ),
+ bMulti( rNew.IsMulti() ),
+ bFirstMulti( rNew.IsFirstMulti() ),
+ bRuby( rNew.IsRuby() ),
+ bHanging( rNew.IsHanging() ),
+ bScriptSpace( rNew.HasScriptSpace() ),
+ bForbiddenChars( rNew.HasForbiddenChars() ),
+ bSnapToGrid( rNew.SnapToGrid() ),
+ nDirection( rNew.GetDirection() )
+{
+#ifdef DBG_UTIL
+ ChkOutDev( *this );
+#endif
+}
+
+void SwTxtSizeInfo::CtorInitTxtSizeInfo( SwTxtFrm *pFrame, SwFont *pNewFnt,
+ const xub_StrLen nNewIdx, const xub_StrLen nNewLen )
+{
+ pKanaComp = NULL;
+ nKanaIdx = 0;
+ pFrm = pFrame;
+ CtorInitTxtInfo( pFrm );
+ const SwTxtNode *pNd = pFrm->GetTxtNode();
+ pVsh = pFrm->GetShell();
+
+ // Get the output and reference device
+ if ( pVsh )
+ {
+ pOut = pVsh->GetOut();
+ pRef = &pVsh->GetRefDev();
+ bOnWin = pVsh->GetWin() || OUTDEV_WINDOW == pOut->GetOutDevType();
+ }
+ else
+ {
+ //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
+ if ( pNd->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) )
+ {
+ //in Ermangelung eines Besseren kann hier ja wohl nur noch das
+ //AppWin genommen werden?
+ pOut = GetpApp()->GetDefaultDevice();
+ }
+ else
+ pOut = pNd->getIDocumentDeviceAccess()->getPrinter( false );
+
+ pRef = pOut;
+ }
+
+#ifdef DBG_UTIL
+ ChkOutDev( *this );
+#endif
+
+ // Set default layout mode ( LTR or RTL ).
+ if ( pFrm->IsRightToLeft() )
+ {
+ pOut->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL );
+ pRef->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL );
+ nDirection = DIR_RIGHT2LEFT;
+ }
+ else
+ {
+ pOut->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG );
+ pRef->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG );
+ nDirection = DIR_LEFT2RIGHT;
+ }
+
+/* LanguageType eLang;
+ const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
+ if ( SvtCTLOptions::NUMERALS_HINDI == rCTLOptions.GetCTLTextNumerals() )
+ eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
+ else if ( SvtCTLOptions::NUMERALS_ARABIC == rCTLOptions.GetCTLTextNumerals() )
+ eLang = LANGUAGE_ENGLISH;
+ else
+ eLang = (LanguageType)::GetAppLanguage();
+
+ pOut->SetDigitLanguage( eLang );
+ pRef->SetDigitLanguage( eLang );*/
+
+ //
+ // The Options
+ //
+ pOpt = pVsh ?
+ pVsh->GetViewOptions() :
+ SW_MOD()->GetViewOption( pNd->getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) ); //Options vom Module wg. StarONE
+
+ // bURLNotify wird gesetzt, wenn MakeGraphic dies vorbereitet
+ // TODO: Aufdr?seln
+ bURLNotify = pNoteURL && !bOnWin;
+
+ SetSnapToGrid( pNd->GetSwAttrSet().GetParaGrid().GetValue() &&
+ pFrm->IsInDocBody() );
+
+ pFnt = pNewFnt;
+ pUnderFnt = 0;
+ pTxt = &pNd->GetTxt();
+
+ nIdx = nNewIdx;
+ nLen = nNewLen;
+ bNotEOL = sal_False;
+ bStopUnderFlow = bFtnInside = bOtherThanFtnInside = sal_False;
+ bMulti = bFirstMulti = bRuby = bHanging = bScriptSpace =
+ bForbiddenChars = sal_False;
+
+ SetLen( GetMinLen( *this ) );
+}
+
+SwTxtSizeInfo::SwTxtSizeInfo( const SwTxtSizeInfo &rNew, const XubString &rTxt,
+ const xub_StrLen nIndex, const xub_StrLen nLength )
+ : SwTxtInfo( rNew ),
+ pKanaComp(((SwTxtSizeInfo&)rNew).GetpKanaComp()),
+ pVsh(((SwTxtSizeInfo&)rNew).GetVsh()),
+ pOut(((SwTxtSizeInfo&)rNew).GetOut()),
+ pRef(((SwTxtSizeInfo&)rNew).GetRefDev()),
+ pFnt(((SwTxtSizeInfo&)rNew).GetFont()),
+ pUnderFnt(((SwTxtSizeInfo&)rNew).GetUnderFnt()),
+ pFrm( rNew.pFrm ),
+ pOpt(&rNew.GetOpt()),
+ pTxt(&rTxt),
+ nIdx(nIndex),
+ nLen(nLength),
+ nKanaIdx( rNew.GetKanaIdx() ),
+ bOnWin( rNew.OnWin() ),
+ bNotEOL( rNew.NotEOL() ),
+ bURLNotify( rNew.URLNotify() ),
+ bStopUnderFlow( rNew.StopUnderFlow() ),
+ bFtnInside( rNew.IsFtnInside() ),
+ bOtherThanFtnInside( rNew.IsOtherThanFtnInside() ),
+ bMulti( rNew.IsMulti() ),
+ bFirstMulti( rNew.IsFirstMulti() ),
+ bRuby( rNew.IsRuby() ),
+ bHanging( rNew.IsHanging() ),
+ bScriptSpace( rNew.HasScriptSpace() ),
+ bForbiddenChars( rNew.HasForbiddenChars() ),
+ bSnapToGrid( rNew.SnapToGrid() ),
+ nDirection( rNew.GetDirection() )
+{
+#ifdef DBG_UTIL
+ ChkOutDev( *this );
+#endif
+ SetLen( GetMinLen( *this ) );
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::SelectFont()
+ *************************************************************************/
+
+void SwTxtSizeInfo::SelectFont()
+{
+ // 8731: Der Weg muss ueber ChgPhysFnt gehen, sonst geraet
+ // der FontMetricCache durcheinander. In diesem Fall steht pLastMet
+ // auf dem alten Wert.
+ // Falsch: GetOut()->SetFont( GetFont()->GetFnt() );
+ GetFont()->Invalidate();
+ GetFont()->ChgPhysFnt( pVsh, *GetOut() );
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::NoteAnimation()
+ *************************************************************************/
+
+void SwTxtSizeInfo::NoteAnimation() const
+{
+ if( OnWin() )
+ SwRootFrm::FlushVout();
+
+ ASSERT( pOut == pVsh->GetOut(),
+ "SwTxtSizeInfo::NoteAnimation() changed pOut" )
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwTxtSizeInfo::GetTxtSize( OutputDevice* pOutDev,
+ const SwScriptInfo* pSI,
+ const XubString& rTxt,
+ const xub_StrLen nIndex,
+ const xub_StrLen nLength,
+ const USHORT nComp ) const
+{
+ SwDrawTextInfo aDrawInf( pVsh, *pOutDev, pSI, rTxt, nIndex, nLength );
+ aDrawInf.SetFrm( pFrm );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( SnapToGrid() );
+ aDrawInf.SetKanaComp( nComp );
+ SwPosSize aSize = pFnt->_GetTxtSize( aDrawInf );
+ return aSize;
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwTxtSizeInfo::GetTxtSize() const
+{
+ const SwScriptInfo& rSI =
+ ( (SwParaPortion*)GetParaPortion() )->GetScriptInfo();
+
+ // in some cases, compression is not allowed or surpressed for
+ // performance reasons
+ USHORT nComp =( SW_CJK == GetFont()->GetActual() &&
+ rSI.CountCompChg() &&
+ ! IsMulti() ) ?
+ GetKanaComp() :
+ 0 ;
+
+ SwDrawTextInfo aDrawInf( pVsh, *pOut, &rSI, *pTxt, nIdx, nLen );
+ aDrawInf.SetFrm( pFrm );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( SnapToGrid() );
+ aDrawInf.SetKanaComp( nComp );
+ return pFnt->_GetTxtSize( aDrawInf );
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::GetTxtSize()
+ *************************************************************************/
+
+void SwTxtSizeInfo::GetTxtSize( const SwScriptInfo* pSI, const xub_StrLen nIndex,
+ const xub_StrLen nLength, const USHORT nComp,
+ USHORT& nMinSize, USHORT& nMaxSizeDiff ) const
+{
+ SwDrawTextInfo aDrawInf( pVsh, *pOut, pSI, *pTxt, nIndex, nLength );
+ aDrawInf.SetFrm( pFrm );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( SnapToGrid() );
+ aDrawInf.SetKanaComp( nComp );
+ SwPosSize aSize = pFnt->_GetTxtSize( aDrawInf );
+ nMaxSizeDiff = (USHORT)aDrawInf.GetKanaDiff();
+ nMinSize = aSize.Width();
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::GetTxtBreak()
+ *************************************************************************/
+
+xub_StrLen SwTxtSizeInfo::GetTxtBreak( const long nLineWidth,
+ const xub_StrLen nMaxLen,
+ const USHORT nComp ) const
+{
+ const SwScriptInfo& rScriptInfo =
+ ( (SwParaPortion*)GetParaPortion() )->GetScriptInfo();
+
+ ASSERT( pRef == pOut, "GetTxtBreak is supposed to use the RefDev" )
+ SwDrawTextInfo aDrawInf( pVsh, *pOut, &rScriptInfo,
+ *pTxt, GetIdx(), nMaxLen );
+ aDrawInf.SetFrm( pFrm );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( SnapToGrid() );
+ aDrawInf.SetKanaComp( nComp );
+ aDrawInf.SetHyphPos( 0 );
+
+ return pFnt->GetTxtBreak( aDrawInf, nLineWidth );
+}
+
+/*************************************************************************
+ * SwTxtSizeInfo::GetTxtBreak()
+ *************************************************************************/
+
+xub_StrLen SwTxtSizeInfo::GetTxtBreak( const long nLineWidth,
+ const xub_StrLen nMaxLen,
+ const USHORT nComp,
+ xub_StrLen& rExtraCharPos ) const
+{
+ const SwScriptInfo& rScriptInfo =
+ ( (SwParaPortion*)GetParaPortion() )->GetScriptInfo();
+
+ ASSERT( pRef == pOut, "GetTxtBreak is supposed to use the RefDev" )
+ SwDrawTextInfo aDrawInf( pVsh, *pOut, &rScriptInfo,
+ *pTxt, GetIdx(), nMaxLen );
+ aDrawInf.SetFrm( pFrm );
+ aDrawInf.SetFont( pFnt );
+ aDrawInf.SetSnapToGrid( SnapToGrid() );
+ aDrawInf.SetKanaComp( nComp );
+ aDrawInf.SetHyphPos( &rExtraCharPos );
+
+ return pFnt->GetTxtBreak( aDrawInf, nLineWidth );
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::CtorInitTxtPaintInfo()
+ *************************************************************************/
+
+void SwTxtPaintInfo::CtorInitTxtPaintInfo( SwTxtFrm *pFrame, const SwRect &rPaint )
+{
+ CtorInitTxtSizeInfo( pFrame );
+ aTxtFly.CtorInitTxtFly( pFrame ),
+ aPaintRect = rPaint;
+ nSpaceIdx = 0;
+ pSpaceAdd = NULL;
+ pWrongList = NULL;
+ pGrammarCheckList = NULL;
+ pSmartTags = NULL; // SMARTTAGS
+
+#ifndef DBG_UTIL
+ pBrushItem = 0;
+#else
+ pBrushItem = ((SvxBrushItem*)-1);
+#endif
+}
+
+SwTxtPaintInfo::SwTxtPaintInfo( const SwTxtPaintInfo &rInf, const XubString &rTxt )
+ : SwTxtSizeInfo( rInf, rTxt ),
+ pWrongList( rInf.GetpWrongList() ),
+ pGrammarCheckList( rInf.GetGrammarCheckList() ),
+ pSmartTags( rInf.GetSmartTags() ), // SMARTTAGS
+ pSpaceAdd( rInf.GetpSpaceAdd() ),
+ pBrushItem( rInf.GetBrushItem() ),
+ aTxtFly( *rInf.GetTxtFly() ),
+ aPos( rInf.GetPos() ),
+ aPaintRect( rInf.GetPaintRect() ),
+ nSpaceIdx( rInf.GetSpaceIdx() )
+{ }
+
+SwTxtPaintInfo::SwTxtPaintInfo( const SwTxtPaintInfo &rInf )
+ : SwTxtSizeInfo( rInf ),
+ pWrongList( rInf.GetpWrongList() ),
+ pGrammarCheckList( rInf.GetGrammarCheckList() ),
+ pSmartTags( rInf.GetSmartTags() ), // SMARTTAGS
+ pSpaceAdd( rInf.GetpSpaceAdd() ),
+ pBrushItem( rInf.GetBrushItem() ),
+ aTxtFly( *rInf.GetTxtFly() ),
+ aPos( rInf.GetPos() ),
+ aPaintRect( rInf.GetPaintRect() ),
+ nSpaceIdx( rInf.GetSpaceIdx() )
+{ }
+
+extern Color aGlobalRetoucheColor;
+
+/*************************************************************************
+ * lcl_IsDarkBackground
+ *
+ * Returns if the current background color is dark.
+ *************************************************************************/
+
+sal_Bool lcl_IsDarkBackground( const SwTxtPaintInfo& rInf )
+{
+ const Color* pCol = rInf.GetFont()->GetBackColor();
+ if( ! pCol || COL_TRANSPARENT == pCol->GetColor() )
+ {
+ const SvxBrushItem* pItem;
+ SwRect aOrigBackRect;
+
+ /// OD 21.08.2002
+ /// consider, that [GetBackgroundBrush(...)] can set <pCol>
+ /// - see implementation in /core/layout/paintfrm.cxx
+ /// OD 21.08.2002 #99657#
+ /// There is a background color, if there is a background brush and
+ /// its color is *not* "no fill"/"auto fill".
+ if( rInf.GetTxtFrm()->GetBackgroundBrush( pItem, pCol, aOrigBackRect, FALSE ) )
+ {
+ if ( !pCol )
+ pCol = &pItem->GetColor();
+
+ /// OD 30.08.2002 #99657#
+ /// determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it.
+ if ( pCol->GetColor() == COL_TRANSPARENT)
+ pCol = NULL;
+ }
+ else
+ pCol = NULL;
+ }
+
+
+ if( !pCol )
+ pCol = &aGlobalRetoucheColor;
+
+ return pCol->IsDark();
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::_DrawText()
+ *************************************************************************/
+
+void SwTxtPaintInfo::_DrawText( const XubString &rText, const SwLinePortion &rPor,
+ const xub_StrLen nStart, const xub_StrLen nLength,
+ const sal_Bool bKern, const sal_Bool bWrong,
+ const sal_Bool bSmartTag,
+ const sal_Bool bGrammarCheck ) // SMARTTAGS
+{
+ if( !nLength )
+ return;
+
+ if( GetFont()->IsBlink() && OnWin() && rPor.Width() )
+ {
+ // check if accessibility options allow blinking portions:
+ const ViewShell* pSh = GetTxtFrm()->GetShell();
+ if ( pSh && ! pSh->GetAccessibilityOptions()->IsStopAnimatedText() &&
+ ! pSh->IsPreView() )
+ {
+ if( !pBlink )
+ pBlink = new SwBlink();
+
+ Point aPoint( aPos );
+
+ if ( GetTxtFrm()->IsRightToLeft() )
+ GetTxtFrm()->SwitchLTRtoRTL( aPoint );
+
+ if ( TEXT_LAYOUT_BIDI_STRONG != GetOut()->GetLayoutMode() )
+ aPoint.X() -= rPor.Width();
+
+ if ( GetTxtFrm()->IsVertical() )
+ GetTxtFrm()->SwitchHorizontalToVertical( aPoint );
+
+ pBlink->Insert( aPoint, &rPor, GetTxtFrm(), pFnt->GetOrientation() );
+
+ if( !pBlink->IsVisible() )
+ return;
+ }
+ else
+ {
+ delete pBlink;
+ pBlink = NULL;
+ }
+ }
+
+ // The SwScriptInfo is useless if we are inside a field portion
+ SwScriptInfo* pSI = 0;
+ if ( ! rPor.InFldGrp() )
+ pSI = &GetParaPortion()->GetScriptInfo();
+
+ // in some cases, kana compression is not allowed or surpressed for
+ // performance reasons
+ USHORT nComp = 0;
+ if ( ! IsMulti() )
+ nComp = GetKanaComp();
+
+ sal_Bool bCfgIsAutoGrammar = sal_False;
+ SvtLinguConfig().GetProperty( C2U( UPN_IS_GRAMMAR_AUTO ) ) >>= bCfgIsAutoGrammar;
+ const sal_Bool bBullet = OnWin() && GetOpt().IsBlank() && IsNoSymbol();
+ const sal_Bool bTmpWrong = bWrong && OnWin() && GetOpt().IsOnlineSpell();
+ const sal_Bool bTmpGrammarCheck = bGrammarCheck && OnWin() && bCfgIsAutoGrammar && GetOpt().IsOnlineSpell();
+ const sal_Bool bTmpSmart = bSmartTag && OnWin() && !GetOpt().IsPagePreview() && SwSmartTagMgr::Get().IsSmartTagsEnabled(); // SMARTTAGS
+
+ ASSERT( GetParaPortion(), "No paragraph!");
+ SwDrawTextInfo aDrawInf( pFrm->GetShell(), *pOut, pSI, rText, nStart, nLength,
+ rPor.Width(), bBullet );
+
+ aDrawInf.SetLeft( GetPaintRect().Left() );
+ aDrawInf.SetRight( GetPaintRect().Right() );
+ aDrawInf.SetUnderFnt( pUnderFnt );
+
+ const long nSpaceAdd = ( rPor.IsBlankPortion() || rPor.IsDropPortion() ||
+ rPor.InNumberGrp() ) ? 0 : GetSpaceAdd();
+ if ( nSpaceAdd )
+ {
+ xub_StrLen nCharCnt;
+ // --> FME 2005-04-04 #i41860# Thai justified alignemt needs some
+ // additional information:
+ aDrawInf.SetNumberOfBlanks( rPor.InTxtGrp() ?
+ static_cast<const SwTxtPortion&>(rPor).GetSpaceCnt( *this, nCharCnt ) :
+ 0 );
+ // <--
+ }
+
+ aDrawInf.SetSpace( nSpaceAdd );
+ aDrawInf.SetKanaComp( nComp );
+
+ // the font is used to identify the current script via nActual
+ aDrawInf.SetFont( pFnt );
+ // the frame is used to identify the orientation
+ aDrawInf.SetFrm( GetTxtFrm() );
+ // we have to know if the paragraph should snap to grid
+ aDrawInf.SetSnapToGrid( SnapToGrid() );
+ // for underlining we must know when not to add extra space behind
+ // a character in justified mode
+ aDrawInf.SetSpaceStop( ! rPor.GetPortion() ||
+ rPor.GetPortion()->InFixMargGrp() ||
+ rPor.GetPortion()->IsHolePortion() );
+
+ if( GetTxtFly()->IsOn() )
+ {
+ // aPos muss als TopLeft vorliegen, weil die ClipRects sonst
+ // nicht berechnet werden koennen.
+ const Point aPoint( aPos.X(), aPos.Y() - rPor.GetAscent() );
+ const Size aSize( rPor.Width(), rPor.Height() );
+ aDrawInf.SetPos( aPoint );
+ aDrawInf.SetSize( aSize );
+ aDrawInf.SetAscent( rPor.GetAscent() );
+ aDrawInf.SetKern( bKern ? rPor.Width() : 0 );
+ aDrawInf.SetWrong( bTmpWrong ? pWrongList : NULL );
+ aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? pGrammarCheckList : NULL );
+ aDrawInf.SetSmartTags( bTmpSmart ? pSmartTags : NULL ); // SMARTTAGS
+ GetTxtFly()->DrawTextOpaque( aDrawInf );
+ }
+ else
+ {
+ aDrawInf.SetPos( aPos );
+ if( bKern )
+ pFnt->_DrawStretchText( aDrawInf );
+ else
+ {
+ aDrawInf.SetWrong( bTmpWrong ? pWrongList : NULL );
+ aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? pGrammarCheckList : NULL );
+ aDrawInf.SetSmartTags( bTmpSmart ? pSmartTags : NULL ); // SMARTTAGS
+ pFnt->_DrawText( aDrawInf );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::CalcRect()
+ *************************************************************************/
+
+void SwTxtPaintInfo::CalcRect( const SwLinePortion& rPor,
+ SwRect* pRect, SwRect* pIntersect ) const
+{
+ Size aSize( rPor.Width(), rPor.Height() );
+ if( rPor.IsHangingPortion() )
+ aSize.Width() = ((SwHangingPortion&)rPor).GetInnerWidth();
+ if( rPor.InSpaceGrp() && GetSpaceAdd() )
+ {
+ SwTwips nAdd = rPor.CalcSpacing( GetSpaceAdd(), *this );
+ if( rPor.InFldGrp() && GetSpaceAdd() < 0 && nAdd )
+ nAdd += GetSpaceAdd() / SPACING_PRECISION_FACTOR;
+ aSize.Width() += nAdd;
+ }
+
+ Point aPoint;
+
+ if( IsRotated() )
+ {
+ long nTmp = aSize.Width();
+ aSize.Width() = aSize.Height();
+ aSize.Height() = nTmp;
+ if ( 1 == GetDirection() )
+ {
+ aPoint.A() = X() - rPor.GetAscent();
+ aPoint.B() = Y() - aSize.Height();
+ }
+ else
+ {
+ aPoint.A() = X() - rPor.Height() + rPor.GetAscent();
+ aPoint.B() = Y();
+ }
+ }
+ else
+ {
+ aPoint.A() = X();
+ aPoint.B() = Y() - rPor.GetAscent();
+ }
+
+ // Adjust x coordinate if we are inside a bidi portion
+ const BOOL bFrmDir = GetTxtFrm()->IsRightToLeft();
+ BOOL bCounterDir = ( ! bFrmDir && DIR_RIGHT2LEFT == GetDirection() ) ||
+ ( bFrmDir && DIR_LEFT2RIGHT == GetDirection() );
+
+ if ( bCounterDir )
+ aPoint.A() -= aSize.Width();
+
+ SwRect aRect( aPoint, aSize );
+
+ if ( GetTxtFrm()->IsRightToLeft() )
+ GetTxtFrm()->SwitchLTRtoRTL( aRect );
+
+ if ( GetTxtFrm()->IsVertical() )
+ GetTxtFrm()->SwitchHorizontalToVertical( aRect );
+
+ if ( pRect )
+ *pRect = aRect;
+
+ if( aRect.HasArea() && pIntersect )
+ {
+ ::SwAlignRect( aRect, (ViewShell*)GetVsh() );
+
+ if ( GetOut()->IsClipRegion() )
+ {
+ SwRect aClip( GetOut()->GetClipRegion().GetBoundRect() );
+ aRect.Intersection( aClip );
+ }
+
+ *pIntersect = aRect;
+ }
+}
+
+/*************************************************************************
+ * lcl_DrawSpecial
+ *
+ * Draws a special portion, e.g., line break portion, tab portion.
+ * rPor - The portion
+ * rRect - The rectangle surrounding the character
+ * pCol - Specify a color for the character
+ * bCenter - Draw the character centered, otherwise left aligned
+ * bRotate - Rotate the character if character rotation is set
+ *************************************************************************/
+
+static void lcl_DrawSpecial( const SwTxtPaintInfo& rInf, const SwLinePortion& rPor,
+ SwRect& rRect, const Color* pCol, sal_Unicode cChar,
+ BYTE nOptions )
+{
+ sal_Bool bCenter = 0 != ( nOptions & DRAW_SPECIAL_OPTIONS_CENTER );
+ sal_Bool bRotate = 0 != ( nOptions & DRAW_SPECIAL_OPTIONS_ROTATE );
+
+ // rRect is given in absolute coordinates
+ if ( rInf.GetTxtFrm()->IsRightToLeft() )
+ rInf.GetTxtFrm()->SwitchRTLtoLTR( rRect );
+ if ( rInf.GetTxtFrm()->IsVertical() )
+ rInf.GetTxtFrm()->SwitchVerticalToHorizontal( rRect );
+
+ const SwFont* pOldFnt = rInf.GetFont();
+
+ // Font is generated only once:
+ static SwFont* pFnt = 0;
+ if ( ! pFnt )
+ {
+ pFnt = new SwFont( *pOldFnt );
+ pFnt->SetFamily( FAMILY_DONTKNOW, pFnt->GetActual() );
+ pFnt->SetName( numfunc::GetDefBulletFontname(), pFnt->GetActual() );
+ pFnt->SetStyleName( aEmptyStr, pFnt->GetActual() );
+ pFnt->SetCharSet( RTL_TEXTENCODING_SYMBOL, pFnt->GetActual() );
+ }
+
+ // Some of the current values are set at the font:
+ if ( ! bRotate )
+ pFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() );
+ else
+ pFnt->SetVertical( pOldFnt->GetOrientation() );
+
+ if ( pCol )
+ pFnt->SetColor( *pCol );
+ else
+ pFnt->SetColor( pOldFnt->GetColor() );
+
+ Size aFontSize( 0, SPECIAL_FONT_HEIGHT );
+ pFnt->SetSize( aFontSize, pFnt->GetActual() );
+
+ ((SwTxtPaintInfo&)rInf).SetFont( pFnt );
+
+ // The maximum width depends on the current orientation
+ const USHORT nDir = pFnt->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
+ SwTwips nMaxWidth = 0;
+ switch ( nDir )
+ {
+ case 0 :
+ nMaxWidth = rRect.Width();
+ break;
+ case 900 :
+ case 2700 :
+ nMaxWidth = rRect.Height();
+ break;
+ default:
+ ASSERT( sal_False, "Unknown direction set at font" )
+ break;
+ }
+
+ // check if char fits into rectangle
+ const XubString aTmp( cChar );
+ aFontSize = rInf.GetTxtSize( aTmp ).SvLSize();
+ while ( aFontSize.Width() > nMaxWidth )
+ {
+ SwTwips nFactor = ( 100 * aFontSize.Width() ) / nMaxWidth;
+ const SwTwips nOldWidth = aFontSize.Width();
+
+ // new height for font
+ const BYTE nAct = pFnt->GetActual();
+ aFontSize.Height() = ( 100 * pFnt->GetSize( nAct ).Height() ) / nFactor;
+ aFontSize.Width() = ( 100 * pFnt->GetSize( nAct).Width() ) / nFactor;
+
+ if ( !aFontSize.Width() && !aFontSize.Height() )
+ break;
+
+ pFnt->SetSize( aFontSize, nAct );
+
+ aFontSize = rInf.GetTxtSize( aTmp ).SvLSize();
+
+ if ( aFontSize.Width() >= nOldWidth )
+ break;
+ }
+
+ const Point aOldPos( rInf.GetPos() );
+
+ // adjust values so that tab is vertically and horizontally centered
+ SwTwips nX = rRect.Left();
+ SwTwips nY = rRect.Top();
+ switch ( nDir )
+ {
+ case 0 :
+ if ( bCenter )
+ nX += ( rRect.Width() - aFontSize.Width() ) / 2;
+ nY += ( rRect.Height() - aFontSize.Height() ) / 2 + rInf.GetAscent();
+ break;
+ case 900 :
+ if ( bCenter )
+ nX += ( rRect.Width() - aFontSize.Height() ) / 2 + rInf.GetAscent();
+ nY += ( rRect.Height() + aFontSize.Width() ) / 2;
+ break;
+ case 2700 :
+ if ( bCenter )
+ nX += ( rRect.Width() + aFontSize.Height() ) / 2 - rInf.GetAscent();
+ nY += ( rRect.Height() - aFontSize.Width() ) / 2;
+ break;
+ }
+
+ Point aTmpPos( nX, nY );
+ ((SwTxtPaintInfo&)rInf).SetPos( aTmpPos );
+ USHORT nOldWidth = rPor.Width();
+ ((SwLinePortion&)rPor).Width( (USHORT)aFontSize.Width() );
+ rInf.DrawText( aTmp, rPor );
+ ((SwLinePortion&)rPor).Width( nOldWidth );
+ ((SwTxtPaintInfo&)rInf).SetFont( (SwFont*)pOldFnt );
+ ((SwTxtPaintInfo&)rInf).SetPos( aOldPos );
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawRect()
+ *************************************************************************/
+
+void SwTxtPaintInfo::DrawRect( const SwRect &rRect, sal_Bool bNoGraphic,
+ sal_Bool bRetouche ) const
+{
+ if ( OnWin() || !bRetouche )
+ {
+ if( aTxtFly.IsOn() )
+ ((SwTxtPaintInfo*)this)->GetTxtFly()->
+ DrawFlyRect( pOut, rRect, *this, bNoGraphic );
+ else if ( bNoGraphic )
+ pOut->DrawRect( rRect.SVRect() );
+ else
+ {
+ ASSERT( ((SvxBrushItem*)-1) != pBrushItem, "DrawRect: Uninitialized BrushItem!" );
+ ::DrawGraphic( pBrushItem, pOut, aItemRect, rRect );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawTab()
+ *************************************************************************/
+
+void SwTxtPaintInfo::DrawTab( const SwLinePortion &rPor ) const
+{
+ if( OnWin() )
+ {
+ SwRect aRect;
+ CalcRect( rPor, &aRect );
+
+ if ( ! aRect.HasArea() )
+ return;
+
+ const sal_Unicode cChar = GetTxtFrm()->IsRightToLeft() ?
+ CHAR_TAB_RTL : CHAR_TAB;
+ const BYTE nOptions = DRAW_SPECIAL_OPTIONS_CENTER |
+ DRAW_SPECIAL_OPTIONS_ROTATE;
+ lcl_DrawSpecial( *this, rPor, aRect, 0, cChar, nOptions );
+ }
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawLineBreak()
+ *************************************************************************/
+
+void SwTxtPaintInfo::DrawLineBreak( const SwLinePortion &rPor ) const
+{
+ if( OnWin() )
+ {
+ KSHORT nOldWidth = rPor.Width();
+ ((SwLinePortion&)rPor).Width( LINE_BREAK_WIDTH );
+
+ SwRect aRect;
+ CalcRect( rPor, &aRect );
+
+ if( aRect.HasArea() )
+ {
+ const sal_Unicode cChar = GetTxtFrm()->IsRightToLeft() ?
+ CHAR_LINEBREAK_RTL : CHAR_LINEBREAK;
+ const BYTE nOptions = 0;
+ lcl_DrawSpecial( *this, rPor, aRect, 0, cChar, nOptions );
+ }
+
+ ((SwLinePortion&)rPor).Width( nOldWidth );
+ }
+}
+
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawRedArrow()
+ *************************************************************************/
+
+void SwTxtPaintInfo::DrawRedArrow( const SwLinePortion &rPor ) const
+{
+ Size aSize( SPECIAL_FONT_HEIGHT, SPECIAL_FONT_HEIGHT );
+ SwRect aRect( ((SwArrowPortion&)rPor).GetPos(), aSize );
+ sal_Unicode cChar;
+ if( ((SwArrowPortion&)rPor).IsLeft() )
+ {
+ aRect.Pos().Y() += 20 - GetAscent();
+ aRect.Pos().X() += 20;
+ if( aSize.Height() > rPor.Height() )
+ aRect.Height( rPor.Height() );
+ cChar = CHAR_LEFT_ARROW;
+ }
+ else
+ {
+ if( aSize.Height() > rPor.Height() )
+ aRect.Height( rPor.Height() );
+ aRect.Pos().Y() -= aRect.Height() + 20;
+ aRect.Pos().X() -= aRect.Width() + 20;
+ cChar = CHAR_RIGHT_ARROW;
+ }
+
+ if ( GetTxtFrm()->IsVertical() )
+ GetTxtFrm()->SwitchHorizontalToVertical( aRect );
+
+ Color aCol( COL_LIGHTRED );
+
+ if( aRect.HasArea() )
+ {
+ const BYTE nOptions = 0;
+ lcl_DrawSpecial( *this, rPor, aRect, &aCol, cChar, nOptions );
+ }
+}
+
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawPostIts()
+ *************************************************************************/
+
+void SwTxtPaintInfo::DrawPostIts( const SwLinePortion&, sal_Bool bScript ) const
+{
+ if( OnWin() && pOpt->IsPostIts() )
+ {
+ Size aSize;
+ Point aTmp;
+
+ const USHORT nPostItsWidth = pOpt->GetPostItsWidth( GetOut() );
+ const USHORT nFontHeight = pFnt->GetHeight( pVsh, *GetOut() );
+ const USHORT nFontAscent = pFnt->GetAscent( pVsh, *GetOut() );
+
+ switch ( pFnt->GetOrientation( GetTxtFrm()->IsVertical() ) )
+ {
+ case 0 :
+ aSize.Width() = nPostItsWidth;
+ aSize.Height() = nFontHeight;
+ aTmp.X() = aPos.X();
+ aTmp.Y() = aPos.Y() - nFontAscent;
+ break;
+ case 900 :
+ aSize.Height() = nPostItsWidth;
+ aSize.Width() = nFontHeight;
+ aTmp.X() = aPos.X() - nFontAscent;
+ aTmp.Y() = aPos.Y();
+ break;
+ case 2700 :
+ aSize.Height() = nPostItsWidth;
+ aSize.Width() = nFontHeight;
+ aTmp.X() = aPos.X() - nFontHeight +
+ nFontAscent;
+ aTmp.Y() = aPos.Y();
+ break;
+ }
+
+ SwRect aTmpRect( aTmp, aSize );
+
+ if ( GetTxtFrm()->IsRightToLeft() )
+ GetTxtFrm()->SwitchLTRtoRTL( aTmpRect );
+
+ if ( GetTxtFrm()->IsVertical() )
+ GetTxtFrm()->SwitchHorizontalToVertical( aTmpRect );
+
+ const Rectangle aRect( aTmpRect.SVRect() );
+ pOpt->PaintPostIts( (OutputDevice*)GetOut(), aRect, bScript );
+ }
+}
+
+
+void SwTxtPaintInfo::DrawCheckBox( const SwFieldFormPortion &rPor, bool checked) const
+{
+ SwRect aIntersect;
+ CalcRect( rPor, &aIntersect, 0 );
+ if ( aIntersect.HasArea() )
+ {
+ if (OnWin() && SwViewOption::IsFieldShadings() &&
+ !GetOpt().IsPagePreview())
+ {
+ OutputDevice* pOut_ = (OutputDevice*)GetOut();
+ pOut_->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ pOut_->SetFillColor( SwViewOption::GetFieldShadingsColor() );
+ pOut_->SetLineColor();
+ pOut_->DrawRect( aIntersect.SVRect() );
+ pOut_->Pop();
+ }
+ const int delta=10;
+ Rectangle r(aIntersect.Left()+delta, aIntersect.Top()+delta, aIntersect.Right()-delta, aIntersect.Bottom()-delta);
+ pOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ pOut->SetLineColor( Color(0, 0, 0));
+ pOut->SetFillColor();
+ pOut->DrawRect( r );
+ if (checked) {
+ pOut->DrawLine(r.TopLeft(), r.BottomRight());
+ pOut->DrawLine(r.TopRight(), r.BottomLeft());
+ }
+ pOut->Pop();
+ }
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawBackGround()
+ *************************************************************************/
+void SwTxtPaintInfo::DrawBackground( const SwLinePortion &rPor ) const
+{
+ ASSERT( OnWin(), "SwTxtPaintInfo::DrawBackground: printer polution ?" );
+
+ SwRect aIntersect;
+ CalcRect( rPor, 0, &aIntersect );
+
+ if ( aIntersect.HasArea() )
+ {
+ OutputDevice* pTmpOut = (OutputDevice*)GetOut();
+ pTmpOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+
+ // For dark background we do not want to have a filled rectangle
+ if ( GetVsh() && GetVsh()->GetWin() && lcl_IsDarkBackground( *this ) )
+ {
+ pTmpOut->SetLineColor( SwViewOption::GetFontColor().GetColor() );
+ }
+ else
+ {
+ pTmpOut->SetFillColor( SwViewOption::GetFieldShadingsColor() );
+ pTmpOut->SetLineColor();
+ }
+
+ DrawRect( aIntersect, sal_True );
+ pTmpOut->Pop();
+ }
+}
+
+void SwTxtPaintInfo::_DrawBackBrush( const SwLinePortion &rPor ) const
+{
+ {
+ SwRect aIntersect;
+ CalcRect( rPor, &aIntersect, 0 );
+ if(aIntersect.HasArea())
+ {
+ SwTxtNode *pNd = pFrm->GetTxtNode();
+ const ::sw::mark::IMark* pFieldmark = NULL;
+ if(pNd)
+ {
+ const SwDoc *doc=pNd->GetDoc();
+ if(doc)
+ {
+ SwIndex aIndex(pNd, GetIdx());
+ SwPosition aPosition(*pNd, aIndex);
+ pFieldmark=doc->getIDocumentMarkAccess()->getFieldmarkFor(aPosition);
+ }
+ }
+ bool bIsStartMark=(1==GetLen() && CH_TXT_ATR_FIELDSTART==GetTxt().GetChar(GetIdx()));
+ if(pFieldmark) {
+ OSL_TRACE("Found Fieldmark");
+#if DEBUG
+ rtl::OUString str = pFieldmark->ToString( );
+ fprintf( stderr, "%s\n", rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr( ) );
+#endif
+ }
+ if(bIsStartMark) OSL_TRACE("Found StartMark");
+ if (OnWin() && (pFieldmark!=NULL || bIsStartMark) &&
+ SwViewOption::IsFieldShadings() &&
+ !GetOpt().IsPagePreview())
+ {
+ OutputDevice* pOutDev = (OutputDevice*)GetOut();
+ pOutDev->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ pOutDev->SetFillColor( SwViewOption::GetFieldShadingsColor() );
+ pOutDev->SetLineColor( );
+ pOutDev->DrawRect( aIntersect.SVRect() );
+ pOutDev->Pop();
+ }
+ }
+ }
+ if( !pFnt->GetBackColor() ) return;
+
+ ASSERT( pFnt->GetBackColor(), "DrawBackBrush: Lost Color" );
+
+ SwRect aIntersect;
+ CalcRect( rPor, 0, &aIntersect );
+
+ if ( aIntersect.HasArea() )
+ {
+ OutputDevice* pTmpOut = (OutputDevice*)GetOut();
+
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pTmpOut );
+ // <--
+
+ pTmpOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+
+ pTmpOut->SetFillColor( *pFnt->GetBackColor() );
+ pTmpOut->SetLineColor();
+
+ DrawRect( aIntersect, sal_True, sal_False );
+
+ pTmpOut->Pop();
+ }
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::DrawViewOpt()
+ *************************************************************************/
+
+void SwTxtPaintInfo::DrawViewOpt( const SwLinePortion &rPor,
+ const MSHORT nWhich ) const
+{
+ if( OnWin() && !IsMulti() )
+ {
+ sal_Bool bDraw = sal_False;
+ switch( nWhich )
+ {
+ case POR_FTN:
+ case POR_QUOVADIS:
+ case POR_NUMBER:
+ case POR_FLD:
+ case POR_URL:
+ case POR_HIDDEN:
+ case POR_TOX:
+ case POR_REF:
+ case POR_META:
+ case POR_CONTROLCHAR:
+ if ( !GetOpt().IsPagePreview() &&
+ !GetOpt().IsReadonly() &&
+ SwViewOption::IsFieldShadings() &&
+ (POR_NUMBER != nWhich ||
+ pFrm->GetTxtNode()->HasMarkedLabel())) // #i27615#
+ bDraw = sal_True;
+ break;
+ case POR_TAB: if ( GetOpt().IsTab() ) bDraw = sal_True; break;
+ case POR_SOFTHYPH: if ( GetOpt().IsSoftHyph() )bDraw = sal_True; break;
+ case POR_BLANK: if ( GetOpt().IsHardBlank())bDraw = sal_True; break;
+ default:
+ {
+ ASSERT( !this, "SwTxtPaintInfo::DrawViewOpt: don't know how to draw this" );
+ break;
+ }
+ }
+ if ( bDraw )
+ DrawBackground( rPor );
+ }
+}
+
+/*************************************************************************
+ * SwTxtPaintInfo::_NotifyURL()
+ *************************************************************************/
+
+void SwTxtPaintInfo::_NotifyURL( const SwLinePortion &rPor ) const
+{
+ ASSERT( pNoteURL, "NotifyURL: pNoteURL gone with the wind!" );
+
+ SwRect aIntersect;
+ CalcRect( rPor, 0, &aIntersect );
+
+ if( aIntersect.HasArea() )
+ {
+ SwTxtNode *pNd = (SwTxtNode*)GetTxtFrm()->GetTxtNode();
+ SwTxtAttr *const pAttr =
+ pNd->GetTxtAttrAt(GetIdx(), RES_TXTATR_INETFMT);
+ if( pAttr )
+ {
+ const SwFmtINetFmt& rFmt = pAttr->GetINetFmt();
+ pNoteURL->InsertURLNote( rFmt.GetValue(), rFmt.GetTargetFrame(),
+ aIntersect );
+ }
+ }
+}
+
+/*************************************************************************
+ * lcl_InitHyphValues()
+ *************************************************************************/
+
+static void lcl_InitHyphValues( PropertyValues &rVals,
+ INT16 nMinLeading, INT16 nMinTrailing )
+{
+ INT32 nLen = rVals.getLength();
+
+ if (0 == nLen) // yet to be initialized?
+ {
+ rVals.realloc( 2 );
+ PropertyValue *pVal = rVals.getArray();
+
+ pVal[0].Name = C2U( UPN_HYPH_MIN_LEADING );
+ pVal[0].Handle = UPH_HYPH_MIN_LEADING;
+ pVal[0].Value <<= nMinLeading;
+
+ pVal[1].Name = C2U( UPN_HYPH_MIN_TRAILING );
+ pVal[1].Handle = UPH_HYPH_MIN_TRAILING;
+ pVal[1].Value <<= nMinTrailing;
+ }
+ else if (2 == nLen) // already initialized once?
+ {
+ PropertyValue *pVal = rVals.getArray();
+ pVal[0].Value <<= nMinLeading;
+ pVal[1].Value <<= nMinTrailing;
+ }
+ else {
+ DBG_ERROR( "unxpected size of sequence" );
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::GetHyphValues()
+ *************************************************************************/
+
+const PropertyValues & SwTxtFormatInfo::GetHyphValues() const
+{
+ DBG_ASSERT( 2 == aHyphVals.getLength(),
+ "hyphenation values not yet initialized" );
+ return aHyphVals;
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::InitHyph()
+ *************************************************************************/
+
+sal_Bool SwTxtFormatInfo::InitHyph( const sal_Bool bAutoHyphen )
+{
+ const SwAttrSet& rAttrSet = GetTxtFrm()->GetTxtNode()->GetSwAttrSet();
+ SetHanging( rAttrSet.GetHangingPunctuation().GetValue() );
+ SetScriptSpace( rAttrSet.GetScriptSpace().GetValue() );
+ SetForbiddenChars( rAttrSet.GetForbiddenRule().GetValue() );
+ const SvxHyphenZoneItem &rAttr = rAttrSet.GetHyphenZone();
+ MaxHyph() = rAttr.GetMaxHyphens();
+ sal_Bool bAuto = bAutoHyphen || rAttr.IsHyphen();
+ if( bAuto || bInterHyph )
+ {
+ nHyphStart = nHyphWrdStart = STRING_LEN;
+ nHyphWrdLen = 0;
+
+ const INT16 nMinimalLeading = Max(rAttr.GetMinLead(), sal_uInt8(2));
+ const INT16 nMinimalTrailing = rAttr.GetMinTrail();
+ lcl_InitHyphValues( aHyphVals, nMinimalLeading, nMinimalTrailing);
+ }
+ return bAuto;
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::CtorInitTxtFormatInfo()
+ *************************************************************************/
+
+void SwTxtFormatInfo::CtorInitTxtFormatInfo( SwTxtFrm *pNewFrm, const sal_Bool bNewInterHyph,
+ const sal_Bool bNewQuick, const sal_Bool bTst )
+{
+ CtorInitTxtPaintInfo( pNewFrm, SwRect() );
+
+ bQuick = bNewQuick;
+ bInterHyph = bNewInterHyph;
+
+ //! needs to be done in this order
+ nMinLeading = 2;
+ nMinTrailing = 2;
+ nMinWordLength = 0;
+ bAutoHyph = InitHyph();
+
+ bIgnoreFly = sal_False;
+ bFakeLineStart = sal_False;
+ bShift = sal_False;
+ bDropInit = sal_False;
+ bTestFormat = bTst;
+ nLeft = 0;
+ nRight = 0;
+ nFirst = 0;
+ nRealWidth = 0;
+ nForcedLeftMargin = 0;
+ pRest = 0;
+ nLineHeight = 0;
+ nLineNettoHeight = 0;
+ SetLineStart(0);
+ Init();
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::IsHyphenate()
+ *************************************************************************/
+// Trennen oder nicht trennen, das ist hier die Frage:
+// - in keinem Fall trennen, wenn der Hyphenator ERROR zurueckliefert,
+// oder wenn als Sprache NOLANGUAGE eingestellt ist.
+// - ansonsten immer trennen, wenn interaktive Trennung vorliegt
+// - wenn keine interakt. Trennung, dann nur trennen, wenn im ParaFmt
+// automatische Trennung eingestellt ist.
+
+sal_Bool SwTxtFormatInfo::IsHyphenate() const
+{
+ if( !bInterHyph && !bAutoHyph )
+ return sal_False;
+
+ LanguageType eTmp = GetFont()->GetLanguage();
+ if( LANGUAGE_DONTKNOW == eTmp || LANGUAGE_NONE == eTmp )
+ return sal_False;
+
+ uno::Reference< XHyphenator > xHyph = ::GetHyphenator();
+ if (bInterHyph && xHyph.is())
+ SvxSpellWrapper::CheckHyphLang( xHyph, eTmp );
+
+ if( !xHyph.is() || !xHyph->hasLocale( pBreakIt->GetLocale(eTmp) ) )
+ return sal_False;
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::GetDropFmt()
+ *************************************************************************/
+
+// Dropcaps vom SwTxtFormatter::CTOR gerufen.
+const SwFmtDrop *SwTxtFormatInfo::GetDropFmt() const
+{
+ const SwFmtDrop *pDrop = &GetTxtFrm()->GetTxtNode()->GetSwAttrSet().GetDrop();
+ if( 1 >= pDrop->GetLines() ||
+ ( !pDrop->GetChars() && !pDrop->GetWholeWord() ) )
+ pDrop = 0;
+ return pDrop;
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::Init()
+ *************************************************************************/
+
+void SwTxtFormatInfo::Init()
+{
+ // Nicht initialisieren: pRest, nLeft, nRight, nFirst, nRealWidth
+ X(0);
+ bArrowDone = bFull = bFtnDone = bErgoDone = bNumDone = bNoEndHyph =
+ bNoMidHyph = bStop = bNewLine = bUnderFlow = sal_False;
+
+ // generally we do not allow number portions in follows, except...
+ if ( GetTxtFrm()->IsFollow() )
+ {
+ const SwTxtFrm* pMaster = GetTxtFrm()->FindMaster();
+ const SwLinePortion* pTmpPara = pMaster->GetPara();
+
+ // there is a master for this follow and the master does not have
+ // any contents (especially it does not have a number portion)
+ bNumDone = ! pTmpPara ||
+ ! ((SwParaPortion*)pTmpPara)->GetFirstPortion()->IsFlyPortion();
+ }
+
+ pRoot = 0;
+ pLast = 0;
+ pFly = 0;
+ pLastFld = 0;
+ pLastTab = 0;
+ pUnderFlow = 0;
+ cTabDecimal = 0;
+ nWidth = nRealWidth;
+ nForcedLeftMargin = 0;
+ nSoftHyphPos = 0;
+ nUnderScorePos = STRING_LEN;
+ cHookChar = 0;
+ SetIdx(0);
+ SetLen( GetTxt().Len() );
+ SetPaintOfst(0);
+}
+
+/*-----------------16.10.00 11:39-------------------
+ * There are a few differences between a copy constructor
+ * and the following constructor for multi-line formatting.
+ * The root is the first line inside the multi-portion,
+ * the line start is the actual position in the text,
+ * the line width is the rest width from the surrounding line
+ * and the bMulti and bFirstMulti-flag has to be set correctly.
+ * --------------------------------------------------*/
+
+SwTxtFormatInfo::SwTxtFormatInfo( const SwTxtFormatInfo& rInf,
+ SwLineLayout& rLay, SwTwips nActWidth ) : SwTxtPaintInfo( rInf )
+{
+ pRoot = &rLay;
+ pLast = &rLay;
+ pFly = NULL;
+ pLastFld = NULL;
+ pUnderFlow = NULL;
+ pRest = NULL;
+ pLastTab = NULL;
+
+ nSoftHyphPos = 0;
+ nUnderScorePos = STRING_LEN;
+ nHyphStart = 0;
+ nHyphWrdStart = 0;
+ nHyphWrdLen = 0;
+ nLineStart = rInf.GetIdx();
+ nLeft = rInf.nLeft;
+ nRight = rInf.nRight;
+ nFirst = rInf.nLeft;
+ nRealWidth = KSHORT(nActWidth);
+ nWidth = nRealWidth;
+ nLineHeight = 0;
+ nLineNettoHeight = 0;
+ nForcedLeftMargin = 0;
+
+ nMinLeading = 0;
+ nMinTrailing = 0;
+ nMinWordLength = 0;
+ bFull = FALSE;
+ bFtnDone = TRUE;
+ bErgoDone = TRUE;
+ bNumDone = TRUE;
+ bArrowDone = TRUE;
+ bStop = FALSE;
+ bNewLine = TRUE;
+ bShift = FALSE;
+ bUnderFlow = FALSE;
+ bInterHyph = FALSE;
+ bAutoHyph = FALSE;
+ bDropInit = FALSE;
+ bQuick = rInf.bQuick;
+ bNoEndHyph = FALSE;
+ bNoMidHyph = FALSE;
+ bIgnoreFly = FALSE;
+ bFakeLineStart = FALSE;
+
+ cTabDecimal = 0;
+ cHookChar = 0;
+ nMaxHyph = 0;
+ bTestFormat = rInf.bTestFormat;
+ SetMulti( sal_True );
+ SetFirstMulti( rInf.IsFirstMulti() );
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::_CheckFtnPortion()
+ *************************************************************************/
+
+sal_Bool SwTxtFormatInfo::_CheckFtnPortion( SwLineLayout* pCurr )
+{
+ KSHORT nHeight = pCurr->GetRealHeight();
+ SwLinePortion *pPor = pCurr->GetPortion();
+ sal_Bool bRet = sal_False;
+ while( pPor )
+ {
+ if( pPor->IsFtnPortion() && nHeight > ((SwFtnPortion*)pPor)->Orig() )
+ {
+ bRet = sal_True;
+ SetLineHeight( nHeight );
+ SetLineNettoHeight( pCurr->Height() );
+ break;
+ }
+ pPor = pPor->GetPortion();
+ }
+ return bRet;
+}
+
+
+
+
+/*************************************************************************
+ * SwTxtFormatInfo::ScanPortionEnd()
+ *************************************************************************/
+xub_StrLen SwTxtFormatInfo::ScanPortionEnd( const xub_StrLen nStart,
+ const xub_StrLen nEnd )
+{
+ cHookChar = 0;
+ xub_StrLen i = nStart;
+
+ //
+ // Used for decimal tab handling:
+ //
+ const xub_Unicode cTabDec = GetLastTab() ? (sal_Unicode)GetTabDecimal() : 0;
+ const xub_Unicode cThousandSep = ',' == cTabDec ? '.' : ',';
+ // --> FME 2006-01-23 #i45951# German (Switzerland) uses ' as thousand separator:
+ const xub_Unicode cThousandSep2 = ',' == cTabDec ? '.' : '\'';
+ // <--
+
+ bool bNumFound = false;
+ const bool bTabCompat = GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
+
+ // Removed for i7288. bSkip used to be passed from SwFldPortion::Format
+ // as IsFollow(). Therefore more than one special character was not
+ // handled correctly at the beginning of follow fields.
+// if ( bSkip && i < nEnd )
+// ++i;
+
+ for( ; i < nEnd; ++i )
+ {
+ const xub_Unicode cPos = GetChar( i );
+ switch( cPos )
+ {
+ case CH_TXTATR_BREAKWORD:
+ case CH_TXTATR_INWORD:
+ if( !HasHint( i ))
+ break;
+ // no break;
+
+ case CHAR_SOFTHYPHEN:
+ case CHAR_HARDHYPHEN:
+ case CHAR_HARDBLANK:
+ case CH_TAB:
+ case CH_BREAK:
+ case CHAR_ZWSP :
+ case CHAR_ZWNBSP :
+// case CHAR_RLM :
+// case CHAR_LRM :
+ cHookChar = cPos;
+ return i;
+
+ case CHAR_UNDERSCORE:
+ if ( STRING_LEN == nUnderScorePos )
+ nUnderScorePos = i;
+ break;
+
+ default:
+ if ( cTabDec )
+ {
+ if( cTabDec == cPos )
+ {
+ ASSERT( cPos, "Unexpected end of string" );
+ if( cPos ) // robust
+ {
+ cHookChar = cPos;
+ return i;
+ }
+ }
+
+ //
+ // Compatibility: First non-digit character behind a
+ // a digit character becomes the hook character
+ //
+ if ( bTabCompat )
+ {
+ if ( ( 0x2F < cPos && cPos < 0x3A ) ||
+ ( bNumFound && ( cPos == cThousandSep || cPos == cThousandSep2 ) ) )
+ {
+ bNumFound = true;
+ }
+ else
+ {
+ if ( bNumFound )
+ {
+ cHookChar = cPos;
+ SetTabDecimal( cPos );
+ return i;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // --> FME 2006-01-13 #130210# Check if character *behind* the portion has
+ // to become the hook:
+ if ( i == nEnd && i < GetTxt().Len() && bNumFound )
+ {
+ const xub_Unicode cPos = GetChar( i );
+ if ( cPos != cTabDec && cPos != cThousandSep && cPos !=cThousandSep2 && ( 0x2F >= cPos || cPos >= 0x3A ) )
+ {
+ cHookChar = GetChar( i );
+ SetTabDecimal( cHookChar );
+ }
+ }
+
+ return i;
+}
+
+BOOL SwTxtFormatInfo::LastKernPortion()
+{
+ if( GetLast() )
+ {
+ if( GetLast()->IsKernPortion() )
+ return TRUE;
+ if( GetLast()->Width() || ( GetLast()->GetLen() &&
+ !GetLast()->IsHolePortion() ) )
+ return FALSE;
+ }
+ SwLinePortion* pPor = GetRoot();
+ SwLinePortion *pKern = NULL;
+ while( pPor )
+ {
+ if( pPor->IsKernPortion() )
+ pKern = pPor;
+ else if( pPor->Width() || ( pPor->GetLen() && !pPor->IsHolePortion() ) )
+ pKern = NULL;
+ pPor = pPor->GetPortion();
+ }
+ if( pKern )
+ {
+ SetLast( pKern );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * class SwTxtSlot
+ *************************************************************************/
+
+SwTxtSlot::SwTxtSlot( const SwTxtSizeInfo *pNew, const SwLinePortion *pPor,
+ bool bTxtLen, bool bExgLists, const sal_Char *pCh )
+ : pOldTxt( 0 ),
+ pOldSmartTagList( 0 ),
+ pOldGrammarCheckList( 0 ),
+ pTempList( 0 )
+{
+ if( pCh )
+ {
+ aTxt = XubString( pCh, RTL_TEXTENCODING_MS_1252 );
+ bOn = sal_True;
+ }
+ else
+ bOn = pPor->GetExpTxt( *pNew, aTxt );
+
+ // Der Text wird ausgetauscht...
+ if( bOn )
+ {
+ pInf = (SwTxtSizeInfo*)pNew;
+ nIdx = pInf->GetIdx();
+ nLen = pInf->GetLen();
+ pOldTxt = &(pInf->GetTxt());
+ pInf->SetTxt( aTxt );
+ pInf->SetIdx( 0 );
+ pInf->SetLen( bTxtLen ? pInf->GetTxt().Len() : pPor->GetLen() );
+
+ // ST2
+ if ( bExgLists )
+ {
+ pOldSmartTagList = static_cast<SwTxtPaintInfo*>(pInf)->GetSmartTags();
+ if ( pOldSmartTagList )
+ {
+ const USHORT nPos = pOldSmartTagList->GetWrongPos(nIdx);
+ const xub_StrLen nListPos = pOldSmartTagList->Pos(nPos);
+ if( nListPos == nIdx )
+ ((SwTxtPaintInfo*)pInf)->SetSmartTags( pOldSmartTagList->SubList( nPos ) );
+ else if( !pTempList && nPos < pOldSmartTagList->Count() && nListPos < nIdx && aTxt.Len() )
+ {
+ pTempList = new SwWrongList( WRONGLIST_SMARTTAG );
+ pTempList->Insert( rtl::OUString(), 0, 0, aTxt.Len(), 0 );
+ ((SwTxtPaintInfo*)pInf)->SetSmartTags( pTempList );
+ }
+ else
+ ((SwTxtPaintInfo*)pInf)->SetSmartTags( 0);
+ }
+ pOldGrammarCheckList = static_cast<SwTxtPaintInfo*>(pInf)->GetGrammarCheckList();
+ if ( pOldGrammarCheckList )
+ {
+ const USHORT nPos = pOldGrammarCheckList->GetWrongPos(nIdx);
+ const xub_StrLen nListPos = pOldGrammarCheckList->Pos(nPos);
+ if( nListPos == nIdx )
+ ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( pOldGrammarCheckList->SubList( nPos ) );
+ else if( !pTempList && nPos < pOldGrammarCheckList->Count() && nListPos < nIdx && aTxt.Len() )
+ {
+ pTempList = new SwWrongList( WRONGLIST_GRAMMAR );
+ pTempList->Insert( rtl::OUString(), 0, 0, aTxt.Len(), 0 );
+ ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( pTempList );
+ }
+ else
+ ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( 0);
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtSlot::~SwTxtSlot()
+ *************************************************************************/
+
+SwTxtSlot::~SwTxtSlot()
+{
+ if( bOn )
+ {
+ pInf->SetTxt( *pOldTxt );
+ pInf->SetIdx( nIdx );
+ pInf->SetLen( nLen );
+
+ // ST2
+ // Restore old smart tag list
+ if ( pOldSmartTagList )
+ ((SwTxtPaintInfo*)pInf)->SetSmartTags( pOldSmartTagList );
+ if ( pOldGrammarCheckList )
+ ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( pOldGrammarCheckList );
+ delete pTempList;
+ }
+}
+
+/*************************************************************************
+ * SwFontSave::SwFontSave()
+ *************************************************************************/
+
+SwFontSave::SwFontSave( const SwTxtSizeInfo &rInf, SwFont *pNew,
+ SwAttrIter* pItr )
+ : pFnt( pNew ? ((SwTxtSizeInfo&)rInf).GetFont() : 0 )
+{
+ if( pFnt )
+ {
+ pInf = &((SwTxtSizeInfo&)rInf);
+ // In these cases we temporarily switch to the new font:
+ // 1. the fonts have a different magic number
+ // 2. they have different script types
+ // 3. their background colors differ (this is not covered by 1.)
+ if( pFnt->DifferentMagic( pNew, pFnt->GetActual() ) ||
+ pNew->GetActual() != pFnt->GetActual() ||
+ ( ! pNew->GetBackColor() && pFnt->GetBackColor() ) ||
+ ( pNew->GetBackColor() && ! pFnt->GetBackColor() ) ||
+ ( pNew->GetBackColor() && pFnt->GetBackColor() &&
+ ( *pNew->GetBackColor() != *pFnt->GetBackColor() ) ) )
+ {
+ pNew->SetTransparent( sal_True );
+ pNew->SetAlign( ALIGN_BASELINE );
+ pInf->SetFont( pNew );
+ }
+ else
+ pFnt = 0;
+ pNew->Invalidate();
+ pNew->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
+ if( pItr && pItr->GetFnt() == pFnt )
+ {
+ pIter = pItr;
+ pIter->SetFnt( pNew );
+ }
+ else
+ pIter = NULL;
+ }
+}
+
+/*************************************************************************
+ * SwFontSave::~SwFontSave()
+ *************************************************************************/
+
+SwFontSave::~SwFontSave()
+{
+ if( pFnt )
+ {
+ // SwFont zurueckstellen
+ pFnt->Invalidate();
+ pInf->SetFont( pFnt );
+ if( pIter )
+ {
+ pIter->SetFnt( pFnt );
+ pIter->nPos = STRING_LEN;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwDefFontSave::SwDefFontSave()
+ *************************************************************************/
+
+SwDefFontSave::SwDefFontSave( const SwTxtSizeInfo &rInf )
+ : pFnt( ((SwTxtSizeInfo&)rInf).GetFont() )
+{
+ const BOOL bTmpAlter = pFnt->GetFixKerning() ||
+ ( RTL_TEXTENCODING_SYMBOL == pFnt->GetCharSet(pFnt->GetActual()) )
+ ;
+
+ const sal_Bool bFamily = bTmpAlter &&
+ pFnt->GetName( pFnt->GetActual() ) != numfunc::GetDefBulletFontname();
+ const sal_Bool bRotation = (sal_Bool)pFnt->GetOrientation() &&
+ ! rInf.GetTxtFrm()->IsVertical();
+
+ if( bFamily || bRotation )
+ {
+ pNewFnt = new SwFont( *pFnt );
+
+ if ( bFamily )
+ {
+ pNewFnt->SetFamily( FAMILY_DONTKNOW, pFnt->GetActual() );
+ pNewFnt->SetName( numfunc::GetDefBulletFontname(), pFnt->GetActual() );
+ pNewFnt->SetStyleName( aEmptyStr, pFnt->GetActual() );
+ pNewFnt->SetCharSet( RTL_TEXTENCODING_SYMBOL, pFnt->GetActual() );
+ pNewFnt->SetFixKerning( 0 );
+ }
+
+ if ( bRotation )
+ pNewFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() );
+
+ pInf = &((SwTxtSizeInfo&)rInf);
+ pNewFnt->Invalidate();
+ pInf->SetFont( pNewFnt );
+ }
+ else
+ {
+ pFnt = 0;
+ pNewFnt = 0;
+ }
+}
+
+/*************************************************************************
+ * SwDefFontSave::~SwDefFontSave()
+ *************************************************************************/
+
+SwDefFontSave::~SwDefFontSave()
+{
+ if( pFnt )
+ {
+ delete pNewFnt;
+ // SwFont zurueckstellen
+ pFnt->Invalidate();
+ pInf->SetFont( pFnt );
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatInfo::ChgHyph()
+ *************************************************************************/
+
+sal_Bool SwTxtFormatInfo::ChgHyph( const sal_Bool bNew )
+{
+ const sal_Bool bOld = bAutoHyph;
+ if( bAutoHyph != bNew )
+ {
+ bAutoHyph = bNew;
+ InitHyph( bNew );
+ // 5744: Sprache am Hyphenator einstellen.
+ if( pFnt )
+ pFnt->ChgPhysFnt( pVsh, *pOut );
+ }
+ return bOld;
+}
+
+
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
new file mode 100644
index 000000000000..c0643653a1d6
--- /dev/null
+++ b/sw/source/core/text/inftxt.hxx
@@ -0,0 +1,905 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _INFTXT_HXX
+#define _INFTXT_HXX
+#include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+
+#ifndef _TABLE_HXX //autogen
+#include <tools/table.hxx>
+#endif
+
+#include "swtypes.hxx"
+#include "txttypes.hxx"
+#include "swrect.hxx"
+#include "txtfly.hxx"
+#include "swfont.hxx"
+#include "porlay.hxx"
+#include "txtfrm.hxx"
+#include "ndtxt.hxx"
+#include "txttypes.hxx"
+#include <editeng/paravertalignitem.hxx>
+
+class Font;
+class OutputDevice;
+class SvxBrushItem;
+class SvxLineSpacingItem;
+class SvxTabStop;
+class SvxTabStopItem;
+class SwAttrSet;
+class SwFldPortion;
+class SwFlyPortion;
+class SwFmtDrop;
+class SwLineLayout;
+class SwLinePortion;
+class SwParaPortion;
+class SwTabPortion;
+class SwTxtFrm;
+class SwTxtSizeInfo;
+class SwViewOption;
+class ViewShell;
+class SwTxtFtn;
+class SwAttrIter;
+struct SwMultiCreator;
+class SwMultiPortion;
+class SwWrongList;
+
+/* Minimum: Prozentwert fuers kernen */
+#define MINKERNPERCENT 5
+#define ARROW_WIDTH 200
+#define DIR_LEFT2RIGHT 0
+#define DIR_BOTTOM2TOP 1
+#define DIR_RIGHT2LEFT 2
+#define DIR_TOP2BOTTOM 3
+
+#ifdef DBG_UTIL
+#define OPTCALM( rInf ) (rInf).IsOptCalm()
+#define OPTLOW( rInf ) (rInf).IsOptLow()
+#define OPTDBG( rInf ) (rInf).IsOptDbg()
+#else
+#define OPTCALM( rInf ) sal_True
+#define OPTLOW( rInf ) sal_False
+#define OPTDBG( rInf ) sal_False
+#endif
+
+/*************************************************************************
+ * class SwLineInfo
+ *************************************************************************/
+
+// Beruecksichtigt das Attribut LineSpace bei der Hoehen/Ascentberechnung.
+
+class SwLineInfo
+{
+ friend class SwTxtIter;
+
+ SvxTabStopItem* pRuler;
+ const SvxLineSpacingItem *pSpace;
+ USHORT nVertAlign;
+ KSHORT nDefTabStop;
+ // --> OD 2008-02-04 #newlistlevelattrs#
+ bool bListTabStopIncluded;
+ long nListTabStopPosition;
+ // <--
+
+ // --> OD 2008-01-17 #newlistlevelattrs#
+ void CtorInitLineInfo( const SwAttrSet& rAttrSet,
+ const SwTxtNode& rTxtNode );
+ // <--
+
+ // --> OD 2008-01-17 #newlistlevelattrs#
+ SwLineInfo();
+ ~SwLineInfo();
+public:
+// const SvxTabStop *GetTabStop( const SwTwips nLinePos,
+// const SwTwips nLeft,
+ // #i24363# tab stops relative to indent - returns the tab stop following nSearchPos or NULL
+ const SvxTabStop *GetTabStop( const SwTwips nSearchPos,
+ const SwTwips nRight ) const;
+ inline const SvxLineSpacingItem *GetLineSpacing() const { return pSpace; }
+ inline KSHORT GetDefTabStop() const { return nDefTabStop; }
+ inline void SetDefTabStop( KSHORT nNew ) const
+ { ( (SwLineInfo*)this )->nDefTabStop = nNew; }
+
+ // vertical alignment
+ inline USHORT GetVertAlign() const { return nVertAlign; }
+ inline sal_Bool HasSpecialAlign( sal_Bool bVert ) const
+ { return bVert ?
+ ( SvxParaVertAlignItem::BASELINE != nVertAlign ) :
+ ( SvxParaVertAlignItem::BASELINE != nVertAlign &&
+ SvxParaVertAlignItem::AUTOMATIC != nVertAlign ); }
+
+ USHORT NumberOfTabStops() const;
+
+ // --> OD 2008-02-04 #newlistlevelattrs#
+ inline bool IsListTabStopIncluded() const
+ {
+ return bListTabStopIncluded;
+ }
+ inline long GetListTabStopPosition() const
+ {
+ return nListTabStopPosition;
+ }
+ // <--
+
+
+// friend ostream &operator<<( ostream &rOS, const SwLineInfo &rInf );
+ friend SvStream &operator<<( SvStream &rOS, const SwLineInfo &rInf );
+};
+
+/*************************************************************************
+ * class SwTxtInfo
+ *************************************************************************/
+
+class SwTxtInfo
+{
+ // Implementation in txthyph.cxx
+ friend void SetParaPortion( SwTxtInfo *pInf, SwParaPortion *pRoot );
+ SwParaPortion *pPara;
+ xub_StrLen nTxtStart; // TxtOfst bei Follows
+
+protected:
+ inline SwTxtInfo() { }
+public:
+ void CtorInitTxtInfo( SwTxtFrm *pFrm );
+ SwTxtInfo( const SwTxtInfo &rInf );
+ inline SwTxtInfo( SwTxtFrm *pFrm ) { CtorInitTxtInfo( pFrm ); }
+ inline SwParaPortion *GetParaPortion() { return pPara; }
+ inline const SwParaPortion *GetParaPortion() const { return pPara; }
+ inline xub_StrLen GetTxtStart() const { return nTxtStart; }
+
+ friend SvStream &operator<<( SvStream &rOS, const SwTxtInfo &rInf );
+};
+
+/*************************************************************************
+ * class SwTxtSizeInfo
+ *************************************************************************/
+
+DECLARE_TABLE( SwTxtPortionTable, sal_IntPtr )
+
+class SwTxtSizeInfo : public SwTxtInfo
+{
+protected:
+ // during formatting, a small database is built, mapping portion pointers
+ // to their maximum size (used for kana compression)
+ SwTxtPortionTable aMaxWidth;
+ // for each line, an array of compression values is calculated
+ // this array is passed over to the info structure
+ SvUShorts* pKanaComp;
+
+ ViewShell *pVsh;
+
+ // pOut is the output device, pRef is the device used for formatting
+ OutputDevice* pOut;
+ OutputDevice* pRef;
+
+ SwFont *pFnt;
+ SwUnderlineFont *pUnderFnt; // Font for underlining
+ SwTxtFrm *pFrm;
+ const SwViewOption *pOpt;
+ const XubString *pTxt;
+ xub_StrLen nIdx, nLen;
+ USHORT nKanaIdx;
+ sal_Bool bOnWin : 1;
+ sal_Bool bNotEOL : 1;
+ sal_Bool bURLNotify : 1;
+ sal_Bool bStopUnderFlow : 1;// Underflow gestoppt z.B. von einer FlyPortion
+ sal_Bool bFtnInside : 1; // the current line contains a footnote
+ sal_Bool bOtherThanFtnInside : 1; // the current line contains another portion than a footnote portion.
+ // needed for checking keep together of footnote portion with previous portion
+ sal_Bool bMulti : 1; // inside a multiportion
+ sal_Bool bFirstMulti : 1; // this flag is used for two purposes:
+ // - the multiportion is the first lineportion
+ // - indicates, if we are currently in second
+ // line of multi portion
+ sal_Bool bRuby : 1; // during the formatting of a phonetic line
+ sal_Bool bHanging : 1; // formatting of hanging punctuation allowed
+ sal_Bool bScriptSpace : 1; // space between different scripts (Asian/Latin)
+ sal_Bool bForbiddenChars : 1; // Forbidden start/endline characters
+ sal_Bool bSnapToGrid : 1; // paragraph snaps to grid
+ sal_uInt8 nDirection : 2; // writing direction: 0/90/180/270 degree
+
+protected:
+ void CtorInitTxtSizeInfo( SwTxtFrm *pFrm, SwFont *pFnt = 0,
+ const xub_StrLen nIdx = 0,
+ const xub_StrLen nLen = STRING_LEN );
+ SwTxtSizeInfo() {}
+public:
+ SwTxtSizeInfo( const SwTxtSizeInfo &rInf );
+ SwTxtSizeInfo( const SwTxtSizeInfo &rInf, const XubString &rTxt,
+ const xub_StrLen nIdx = 0,
+ const xub_StrLen nLen = STRING_LEN );
+
+ inline SwTxtSizeInfo( SwTxtFrm *pTxtFrm, SwFont *pTxtFnt = 0,
+ const xub_StrLen nIndex = 0,
+ const xub_StrLen nLength = STRING_LEN )
+ { CtorInitTxtSizeInfo( pTxtFrm, pTxtFnt, nIndex, nLength ); }
+
+ // GetMultiAttr returns the text attribute of the multiportion,
+ // if rPos is inside any multi-line part.
+ // rPos will set to the end of the multi-line part.
+ SwMultiCreator* GetMultiCreator( xub_StrLen &rPos, SwMultiPortion* pM ) const;
+
+ inline sal_Bool OnWin() const { return bOnWin; }
+ inline void SetOnWin( const sal_Bool bNew ) { bOnWin = bNew; }
+ inline sal_Bool NotEOL() const { return bNotEOL; }
+ inline void SetNotEOL( const sal_Bool bNew ) { bNotEOL = bNew; }
+ inline sal_Bool URLNotify() const { return bURLNotify; }
+ inline void SetURLNotify( const sal_Bool bNew ) { bURLNotify = bNew; }
+ inline sal_Bool StopUnderFlow() const { return bStopUnderFlow; }
+ inline void SetStopUnderFlow( const sal_Bool bNew ) { bStopUnderFlow = bNew; }
+ inline sal_Bool IsFtnInside() const { return bFtnInside; }
+ inline void SetFtnInside( const sal_Bool bNew ) { bFtnInside = bNew; }
+ inline sal_Bool IsOtherThanFtnInside() const { return bOtherThanFtnInside; }
+ inline void SetOtherThanFtnInside( const sal_Bool bNew ) { bOtherThanFtnInside = bNew; }
+ inline sal_Bool IsMulti() const { return bMulti; }
+ inline void SetMulti( const sal_Bool bNew ) { bMulti = bNew; }
+ inline sal_Bool IsFirstMulti() const { return bFirstMulti; }
+ inline void SetFirstMulti( const sal_Bool bNew ) { bFirstMulti = bNew; }
+ inline sal_Bool IsRuby() const { return bRuby; }
+ inline void SetRuby( const sal_Bool bNew ) { bRuby = bNew; }
+ inline sal_Bool IsHanging() const { return bHanging; }
+ inline void SetHanging( const sal_Bool bNew ) { bHanging = bNew; }
+ inline sal_Bool HasScriptSpace() const { return bScriptSpace; }
+ inline void SetScriptSpace( const sal_Bool bNew ) { bScriptSpace = bNew; }
+ inline sal_Bool HasForbiddenChars() const { return bForbiddenChars; }
+ inline void SetForbiddenChars( const sal_Bool bN ) { bForbiddenChars = bN; }
+ inline sal_Bool SnapToGrid() const { return bSnapToGrid; }
+ inline void SetSnapToGrid( const sal_Bool bN ) { bSnapToGrid = bN; }
+ inline sal_uInt8 GetDirection() const { return nDirection; }
+ inline void SetDirection( const sal_uInt8 nNew ) { nDirection = nNew; }
+ inline sal_Bool IsRotated() const { return 0 != ( 1 & nDirection ); }
+
+ inline ViewShell *GetVsh() { return pVsh; }
+ inline const ViewShell *GetVsh() const { return pVsh; }
+
+ inline OutputDevice *GetOut() { return pOut; }
+ inline const OutputDevice *GetOut() const { return pOut; }
+ inline void SetOut( OutputDevice* pNewOut ) { pOut = pNewOut; }
+
+ inline OutputDevice *GetRefDev() { return pRef; }
+ inline const OutputDevice *GetRefDev() const { return pRef; }
+
+ inline SwFont *GetFont() { return pFnt; }
+ inline const SwFont *GetFont() const { return pFnt; }
+ inline void SetFont( SwFont *pNew ) { pFnt = pNew; }
+ void SelectFont();
+ inline void SetUnderFnt( SwUnderlineFont* pNew ) { pUnderFnt = pNew; }
+ inline SwUnderlineFont* GetUnderFnt() const { return pUnderFnt; }
+
+ inline const SwViewOption &GetOpt() const { return *pOpt; }
+ inline const XubString &GetTxt() const { return *pTxt; }
+ inline xub_Unicode GetChar( const xub_StrLen nPos ) const
+ { return pTxt->GetChar( nPos ); }
+
+ inline KSHORT GetTxtHeight() const;
+
+ //
+ // GetTxtSize
+ //
+ SwPosSize GetTxtSize( OutputDevice* pOut, const SwScriptInfo* pSI,
+ const XubString& rTxt, const xub_StrLen nIdx,
+ const xub_StrLen nLen, const USHORT nComp ) const;
+ SwPosSize GetTxtSize() const;
+ void GetTxtSize( const SwScriptInfo* pSI, const xub_StrLen nIdx,
+ const xub_StrLen nLen, const USHORT nComp,
+ USHORT& nMinSize, USHORT& nMaxSizeDiff ) const;
+ inline SwPosSize GetTxtSize( const SwScriptInfo* pSI, const xub_StrLen nIdx,
+ const xub_StrLen nLen, const USHORT nComp ) const;
+ inline SwPosSize GetTxtSize( const XubString &rTxt ) const;
+
+ //
+ // GetTxtBreak
+ //
+ xub_StrLen GetTxtBreak( const long nLineWidth,
+ const xub_StrLen nMaxLen,
+ const USHORT nComp ) const;
+ xub_StrLen GetTxtBreak( const long nLineWidth,
+ const xub_StrLen nMaxLen,
+ const USHORT nComp,
+ xub_StrLen& rExtraCharPos ) const;
+
+ inline KSHORT GetAscent() const;
+
+ inline xub_StrLen GetIdx() const { return nIdx; }
+ inline void SetIdx( const xub_StrLen nNew ) { nIdx = nNew; }
+ inline xub_StrLen GetLen() const { return nLen; }
+ inline void SetLen( const xub_StrLen nNew ) { nLen = nNew; }
+ inline void SetTxt( const XubString &rNew ){ pTxt = &rNew; }
+
+ friend SvStream &operator<<( SvStream &rOS, const SwTxtSizeInfo &rInf );
+
+// 7780: Keine Bullets beim Symbol-Zeichensatz!
+ inline sal_Bool IsNoSymbol() const
+ { return RTL_TEXTENCODING_SYMBOL != pFnt->GetCharSet( pFnt->GetActual() ); }
+
+ void NoteAnimation() const;
+
+ // Home is where Your heart is...
+ inline SwTxtFrm *GetTxtFrm() { return pFrm; }
+ inline const SwTxtFrm *GetTxtFrm() const { return pFrm; }
+
+ inline sal_Bool HasHint( xub_StrLen nPos ) const
+ { return _HasHint( pFrm->GetTxtNode(), nPos ); }
+ static sal_Bool _HasHint( const SwTxtNode* pTxtNode, xub_StrLen nPos );
+
+ // If Kana Compression is enabled, a minimum and maximum portion width
+ // is calculated. We format lines with minimal size and share remaining
+ // space among compressed kanas.
+ // During formatting, the maximum values of compressable portions are
+ // stored in aMaxWidth and discarded after a line has been formatted.
+ inline void SetMaxWidthDiff( ULONG nKey, USHORT nVal )
+ {
+ aMaxWidth.Insert( nKey, nVal );
+ };
+ inline USHORT GetMaxWidthDiff( ULONG nKey )
+ {
+ return (USHORT)aMaxWidth.Get( nKey );
+ };
+ inline void ResetMaxWidthDiff()
+ {
+ aMaxWidth.Clear();
+ };
+ inline sal_Bool CompressLine()
+ {
+ return (sal_Bool)aMaxWidth.Count();
+ };
+
+ //
+ // Feature: Kana Compression
+ //
+ inline MSHORT GetKanaIdx() const { return nKanaIdx; }
+ inline void ResetKanaIdx(){ nKanaIdx = 0; }
+ inline void SetKanaIdx( MSHORT nNew ) { nKanaIdx = nNew; }
+ inline void IncKanaIdx() { ++nKanaIdx; }
+ inline void SetKanaComp( SvUShorts *pNew ){ pKanaComp = pNew; }
+ inline SvUShorts* GetpKanaComp() const { return pKanaComp; }
+ inline USHORT GetKanaComp() const
+ { return ( pKanaComp && nKanaIdx < pKanaComp->Count() )
+ ? (*pKanaComp)[nKanaIdx] : 0; }
+
+#ifdef DBG_UTIL
+ sal_Bool IsOptCalm() const;
+ sal_Bool IsOptLow() const;
+ sal_Bool IsOptDbg() const;
+ sal_Bool IsOptTest1() const;
+ sal_Bool IsOptTest2() const;
+ sal_Bool IsOptTest3() const;
+ sal_Bool IsOptTest4() const;
+ sal_Bool IsOptTest5() const;
+ sal_Bool IsOptTest6() const;
+ sal_Bool IsOptTest7() const;
+ sal_Bool IsOptTest8() const;
+#endif
+};
+
+/*************************************************************************
+ * class SwTxtPaintInfo
+ *************************************************************************/
+
+class SwTxtPaintInfo : public SwTxtSizeInfo
+{
+ const SwWrongList *pWrongList;
+ const SwWrongList *pGrammarCheckList;
+ const SwWrongList *pSmartTags; // SMARTTAGS
+ std::vector<long>* pSpaceAdd;
+ const SvxBrushItem *pBrushItem; // Fuer den Hintergrund
+ SwRect aItemRect; // ebenfalls fuer den Hintergrund
+ SwTxtFly aTxtFly; // FlyFrm-Berechnung
+ Point aPos; // Ausgabeposition
+ SwRect aPaintRect; // Original Ausgaberechteck (aus Layout-Paint)
+
+ MSHORT nSpaceIdx;
+ void _DrawText( const XubString &rText, const SwLinePortion &rPor,
+ const xub_StrLen nIdx, const xub_StrLen nLen,
+ const sal_Bool bKern, const sal_Bool bWrong = sal_False,
+ const sal_Bool bSmartTag = sal_False,
+ const sal_Bool bGrammarCheck = sal_False ); // SMARTTAGS
+
+ SwTxtPaintInfo &operator=(const SwTxtPaintInfo&);
+ void _NotifyURL( const SwLinePortion &rPor ) const;
+ void _DrawBackBrush( const SwLinePortion &rPor ) const;
+
+protected:
+#ifndef DBG_UTIL
+ SwTxtPaintInfo() { pFrm = 0; pWrongList = 0; pGrammarCheckList = 0; pWrongList = 0; pSmartTags = 0; pSpaceAdd = 0; pBrushItem = 0;}
+#else
+ SwTxtPaintInfo() { pFrm = 0; pWrongList = 0; pGrammarCheckList = 0; pSmartTags = 0; pSpaceAdd = 0;
+ pBrushItem = ((SvxBrushItem*)-1);}
+#endif
+public:
+ SwTxtPaintInfo( const SwTxtPaintInfo &rInf );
+ SwTxtPaintInfo( const SwTxtPaintInfo &rInf, const XubString &rTxt );
+
+ void CtorInitTxtPaintInfo( SwTxtFrm *pFrame, const SwRect &rPaint );
+
+ void SetBack( const SvxBrushItem *pItem,
+ const SwRect &rRect ) { pBrushItem = pItem; aItemRect = rRect;}
+ const SvxBrushItem *GetBrushItem() const { return pBrushItem; }
+ const SwRect &GetBrushRect() const { return aItemRect; }
+
+ inline SwTxtPaintInfo( SwTxtFrm *pFrame, const SwRect &rPaint )
+ { CtorInitTxtPaintInfo( pFrame, rPaint ); }
+
+ inline SwTwips X() const { return aPos.X(); }
+ inline void X( const long nNew ) { aPos.X() = nNew; }
+ inline SwTwips Y() const { return aPos.Y(); }
+ inline void Y( const SwTwips nNew ) { aPos.Y() = nNew; }
+
+ inline SwTxtFly *GetTxtFly() { return &aTxtFly; }
+ inline const SwTxtFly *GetTxtFly() const { return &aTxtFly; }
+ inline void DrawText( const XubString &rText, const SwLinePortion &rPor,
+ const xub_StrLen nIdx = 0,
+ const xub_StrLen nLen = STRING_LEN,
+ const sal_Bool bKern = sal_False) const;
+ inline void DrawText( const SwLinePortion &rPor, const xub_StrLen nLen,
+ const sal_Bool bKern = sal_False ) const;
+ inline void DrawMarkedText( const SwLinePortion &rPor, const xub_StrLen nLen,
+ const sal_Bool bKern,
+ const sal_Bool bWrong,
+ const sal_Bool bSmartTags,
+ const sal_Bool bGrammarCheck ) const;
+
+ void DrawRect( const SwRect &rRect, sal_Bool bNoGraphic = sal_False,
+ sal_Bool bRetouche = sal_True ) const;
+ void DrawTab( const SwLinePortion &rPor ) const;
+ void DrawLineBreak( const SwLinePortion &rPor ) const;
+ void DrawRedArrow( const SwLinePortion &rPor ) const;
+ void DrawPostIts( const SwLinePortion &rPor, sal_Bool bScript ) const;
+ void DrawBackground( const SwLinePortion &rPor ) const;
+ void DrawViewOpt( const SwLinePortion &rPor, const MSHORT nWhich ) const;
+ inline void DrawBackBrush( const SwLinePortion &rPor ) const
+ { /* if( pFnt->GetBackColor() ) */ _DrawBackBrush( rPor ); }
+
+ void DrawCheckBox( const SwFieldFormPortion &rPor, bool checked) const;
+
+ inline void NotifyURL( const SwLinePortion &rPor ) const
+ { if( URLNotify() ) _NotifyURL( rPor ); }
+
+ void CalcRect( const SwLinePortion& rPor, SwRect* pRect, SwRect* pIntersect = 0 ) const;
+
+ inline SwTwips GetPaintOfst() const;
+ inline void SetPaintOfst( const SwTwips nNew );
+ inline const Point &GetPos() const { return aPos; }
+ inline void SetPos( const Point &rNew ) { aPos = rNew; }
+
+ inline const SwRect &GetPaintRect() const { return aPaintRect; }
+ inline void SetPaintRect( const SwRect &rNew ) { aPaintRect = rNew; }
+
+ friend SvStream &operator<<( SvStream &rOS, const SwTxtPaintInfo &rInf );
+
+ //
+ // STUFF FOR JUSTIFIED ALIGNMENT
+ //
+ inline MSHORT GetSpaceIdx() const { return nSpaceIdx; }
+ inline void ResetSpaceIdx(){nSpaceIdx = 0; }
+ inline void SetSpaceIdx( MSHORT nNew ) { nSpaceIdx = nNew; }
+ inline void IncSpaceIdx() { ++nSpaceIdx; }
+ inline void RemoveFirstSpaceAdd() { pSpaceAdd->erase( pSpaceAdd->begin() ); }
+ inline long GetSpaceAdd() const
+ { return ( pSpaceAdd && nSpaceIdx < pSpaceAdd->size() )
+ ? (*pSpaceAdd)[nSpaceIdx] : 0; }
+
+ inline void SetpSpaceAdd( std::vector<long>* pNew ){ pSpaceAdd = pNew; }
+ inline std::vector<long>* GetpSpaceAdd() const { return pSpaceAdd; }
+
+
+ inline void SetWrongList( const SwWrongList *pNew ){ pWrongList = pNew; }
+ inline const SwWrongList* GetpWrongList() const { return pWrongList; }
+
+ inline void SetGrammarCheckList( const SwWrongList *pNew ){ pGrammarCheckList = pNew; }
+ inline const SwWrongList* GetGrammarCheckList() const { return pGrammarCheckList; }
+
+ // SMARTTAGS
+ inline void SetSmartTags( const SwWrongList *pNew ){ pSmartTags = pNew; }
+ inline const SwWrongList* GetSmartTags() const { return pSmartTags; }
+};
+
+/*************************************************************************
+ * class SwTxtFormatInfo
+ *************************************************************************/
+
+class SwTxtFormatInfo : public SwTxtPaintInfo
+{
+ // temporary arguments for hyphenation
+ com::sun::star::beans::PropertyValues aHyphVals;
+
+ SwLineLayout *pRoot; // die Root der aktuellen Zeile (pCurr)
+ SwLinePortion *pLast; // die letzte Portion
+ SwFlyPortion *pFly; // die nachfolgende FlyPortion
+ SwFldPortion *pLastFld; // umgebrochenes Feld
+ SwLinePortion *pUnderFlow; // Unterlaufsituation: letzte Portion
+ SwLinePortion *pRest; // Rest ist der Beginn der naechsten Zeile
+
+ SwTabPortion *pLastTab; // die _letzte_ TabPortion
+
+ xub_StrLen nSoftHyphPos; // SoftHyphPos fuer Hyphenate
+ xub_StrLen nHyphStart; // TxtPos, an der die interakt.Tr.z.Z. steht
+ xub_StrLen nHyphWrdStart; // gefundene Wort-Position
+ xub_StrLen nHyphWrdLen; // gefundene Wort-Laenge
+ xub_StrLen nLineStart; // aktueller Zeilenbeginn im rTxt
+ xub_StrLen nUnderScorePos; // enlarge repaint if underscore has been found
+ // --> FME 2004-11-25 #i34348# Changed type from USHORT to SwTwips
+ SwTwips nLeft; // linker Rand
+ SwTwips nRight; // rechter Rand
+ SwTwips nFirst; // EZE
+ // <--
+ KSHORT nRealWidth; // "echte" Zeilenbreite
+ KSHORT nWidth; // "virtuelle" Zeilenbreite
+ KSHORT nLineHeight; // endgueltige Hoehe nach CalcLine
+ KSHORT nLineNettoHeight; // line height without spacing
+ KSHORT nForcedLeftMargin; // Verschiebung des linken Rands wg. Rahmen
+
+ INT16 nMinLeading; // minimum number of chars before hyphenation point
+ INT16 nMinTrailing; // minimum number of chars after hyphenation point
+ INT16 nMinWordLength; // minimum length of word to be hyphenated
+
+ sal_Bool bFull : 1; // Zeile ist voll
+ sal_Bool bFtnDone : 1; // Ftn bereits formatiert
+ sal_Bool bErgoDone : 1; // ErgoDone bereits formatiert
+ sal_Bool bNumDone : 1; // bNumDone bereits formatiert
+ sal_Bool bArrowDone : 1; // Pfeil nach links bei gescrollten Absaetzen
+ sal_Bool bStop : 1; // Sofort abbrechen, Zeile verwerfen.
+ sal_Bool bNewLine : 1; // Noch eine weitere Zeile formatieren.
+ sal_Bool bShift : 1; // Positionsaend.: Repaint bis auf Weiteres
+ sal_Bool bUnderFlow : 1; // Kontext: UnderFlow() ?
+ sal_Bool bInterHyph: 1; // interaktive Trennung ?
+ sal_Bool bAutoHyph : 1; // automatische Trennung ?
+ sal_Bool bDropInit : 1; // DropWidth einstellen.
+ sal_Bool bQuick : 1; // FormatQuick()
+ sal_Bool bNoEndHyph : 1; // Trennung am Zeilenende abgeschaltet wg. MaxHyphens
+ sal_Bool bNoMidHyph : 1; // Trennung vor Flies abgeschaltet wg. MaxHyphens
+ sal_Bool bIgnoreFly: 1; // FitToContent ignoriert Flies
+ sal_Bool bFakeLineStart: 1; // String has been replaced by field portion
+ // info structure only pretends that we are at
+ // the beginning of a line
+
+ xub_Unicode cTabDecimal; // das _aktuelle_ Dezimalzeichen
+ xub_Unicode cHookChar; // fuer Tabs in Feldern etc.
+ sal_uInt8 nMaxHyph; // max. Zeilenanz. aufeinanderfolg. Trenn.
+ sal_Bool bTestFormat; // Testformatierung aus WouldFit, keine Benachrichtigungen etc.
+
+ // Hyphenating ...
+ sal_Bool InitHyph( const sal_Bool bAuto = sal_False );
+ sal_Bool _CheckFtnPortion( SwLineLayout* pCurr );
+
+public:
+ void CtorInitTxtFormatInfo( SwTxtFrm *pFrm, const sal_Bool bInterHyph = sal_False,
+ const sal_Bool bQuick = sal_False, const sal_Bool bTst = sal_False );
+ inline SwTxtFormatInfo(SwTxtFrm *pFrame,const sal_Bool bInterHyphL=sal_False,
+ const sal_Bool bQuickL = sal_False, const sal_Bool bTst = sal_False )
+ { CtorInitTxtFormatInfo( pFrame, bInterHyphL, bQuickL, bTst ); }
+
+ // For the formatting inside a double line in a line (multi-line portion)
+ // we need a modified text-format-info:
+ SwTxtFormatInfo( const SwTxtFormatInfo& rInf, SwLineLayout& rLay,
+ SwTwips nActWidth );
+
+ inline KSHORT Width() const { return nWidth; }
+ inline void Width( const KSHORT nNew ) { nWidth = nNew; }
+ void Init();
+
+ // liefert die erste veraenderte Position im Absatz zurueck
+ inline xub_StrLen GetReformatStart() const;
+
+ // Raender
+ inline SwTwips Left() const { return nLeft; }
+ inline void Left( const SwTwips nNew ) { nLeft = nNew; }
+ inline SwTwips Right() const { return nRight; }
+ inline void Right( const SwTwips nNew ) { nRight = nNew; }
+ inline SwTwips First() const { return nFirst; }
+ inline void First( const SwTwips nNew ) { nFirst = nNew; }
+ inline SwTwips CurrLeft() const { return (nLineStart ? nLeft : nFirst); }
+ inline KSHORT RealWidth() const { return nRealWidth; }
+ inline void RealWidth( const KSHORT nNew ) { nRealWidth = nNew; }
+ inline KSHORT ForcedLeftMargin() const { return nForcedLeftMargin; }
+ inline void ForcedLeftMargin( const KSHORT nN ) { nForcedLeftMargin = nN; }
+
+ inline sal_uInt8 &MaxHyph() { return nMaxHyph; }
+ inline const sal_uInt8 &MaxHyph() const { return nMaxHyph; }
+
+ inline SwLineLayout *GetRoot() { return pRoot; }
+ inline const SwLineLayout *GetRoot() const { return pRoot; }
+
+ inline void SetRoot( SwLineLayout *pNew ) { pRoot = pNew; }
+ inline SwLinePortion *GetLast() { return pLast; }
+ inline void SetLast( SwLinePortion *pNewLast ) { pLast = pNewLast; }
+ inline sal_Bool IsFull() const { return bFull; }
+ inline void SetFull( const sal_Bool bNew ) { bFull = bNew; }
+ inline sal_Bool IsHyphForbud() const
+ { return pFly ? bNoMidHyph : bNoEndHyph; }
+ inline void SetHyphForbud( const sal_Bool bNew )
+ { if ( pFly ) bNoMidHyph = bNew; else bNoEndHyph = bNew; }
+ inline void ChkNoHyph( const sal_uInt8 bEnd, const sal_uInt8 bMid )
+ { bNoEndHyph = (nMaxHyph && bEnd >= nMaxHyph);
+ bNoMidHyph = (nMaxHyph && bMid >= nMaxHyph); }
+ inline sal_Bool IsIgnoreFly() const { return bIgnoreFly; }
+ inline void SetIgnoreFly( const sal_Bool bNew ) { bIgnoreFly = bNew; }
+ inline sal_Bool IsFakeLineStart() const { return bFakeLineStart; }
+ inline void SetFakeLineStart( const sal_Bool bNew ) { bFakeLineStart = bNew; }
+ inline sal_Bool IsStop() const { return bStop; }
+ inline void SetStop( const sal_Bool bNew ) { bStop = bNew; }
+ inline SwLinePortion *GetRest() { return pRest; }
+ inline void SetRest( SwLinePortion *pNewRest ) { pRest = pNewRest; }
+ inline sal_Bool IsNewLine() const { return bNewLine; }
+ inline void SetNewLine( const sal_Bool bNew ) { bNewLine = bNew; }
+ inline sal_Bool IsShift() const { return bShift; }
+ inline void SetShift( const sal_Bool bNew ) { bShift = bNew; }
+ inline sal_Bool IsInterHyph() const { return bInterHyph; }
+ inline sal_Bool IsAutoHyph() const { return bAutoHyph; }
+ inline sal_Bool IsUnderFlow() const { return bUnderFlow; }
+ inline void ClrUnderFlow() { bUnderFlow = sal_False; }
+ inline sal_Bool IsDropInit() const { return bDropInit; }
+ inline void SetDropInit( const sal_Bool bNew ) { bDropInit = bNew; }
+ inline sal_Bool IsQuick() const { return bQuick; }
+ inline sal_Bool IsTest() const { return bTestFormat; }
+
+ inline xub_StrLen GetLineStart() const { return nLineStart; }
+ inline void SetLineStart( const xub_StrLen nNew ) { nLineStart = nNew; }
+
+ // these are used during fly calculation
+ inline KSHORT GetLineHeight() const { return nLineHeight; }
+ inline void SetLineHeight( const KSHORT nNew ) { nLineHeight = nNew; }
+ inline KSHORT GetLineNettoHeight() const { return nLineNettoHeight; }
+ inline void SetLineNettoHeight( const KSHORT nNew ) { nLineNettoHeight = nNew; }
+
+ inline const SwLinePortion *GetUnderFlow() const { return pUnderFlow; }
+ inline SwLinePortion *GetUnderFlow() { return pUnderFlow; }
+ inline void SetUnderFlow( SwLinePortion *pNew )
+ { pUnderFlow = pNew; bUnderFlow = sal_True; }
+ inline xub_StrLen GetSoftHyphPos() const { return nSoftHyphPos; }
+ inline void SetSoftHyphPos( const xub_StrLen nNew ) { nSoftHyphPos = nNew; }
+
+ inline void SetParaFtn();
+
+ // FlyFrms
+ inline SwFlyPortion *GetFly() { return pFly; }
+ inline void SetFly( SwFlyPortion *pNew ) { pFly = pNew; }
+
+ inline const SwAttrSet& GetCharAttr() const;
+
+ // Tabs
+ inline SwTabPortion *GetLastTab() { return pLastTab; }
+ inline void SetLastTab( SwTabPortion *pNew ) { pLastTab = pNew; }
+ inline xub_Unicode GetTabDecimal() const { return cTabDecimal; }
+ inline void SetTabDecimal( const xub_Unicode cNew ) { cTabDecimal = cNew;}
+
+ // Last*
+ inline SwFldPortion *GetLastFld() { return pLastFld; }
+ inline void SetLastFld( SwFldPortion *pNew ) { pLastFld = pNew; }
+
+ inline void ClearHookChar() { cHookChar = 0; }
+ inline void SetHookChar( const xub_Unicode cNew ) { cHookChar = cNew; }
+ inline xub_Unicode GetHookChar() const { return cHookChar; }
+
+ // Done-Flags
+ inline sal_Bool IsFtnDone() const { return bFtnDone; }
+ inline void SetFtnDone( const sal_Bool bNew ) { bFtnDone = bNew; }
+ inline sal_Bool IsErgoDone() const { return bErgoDone; }
+ inline void SetErgoDone( const sal_Bool bNew ) { bErgoDone = bNew; }
+ inline sal_Bool IsNumDone() const { return bNumDone; }
+ inline void SetNumDone( const sal_Bool bNew ) { bNumDone = bNew; }
+ inline sal_Bool IsArrowDone() const { return bArrowDone; }
+ inline void SetArrowDone( const sal_Bool bNew ) { bArrowDone = bNew; }
+
+ // Fuer SwTxtPortion::Hyphenate
+ inline sal_Bool IsSoftHyph( const xub_StrLen nPos ) const;
+ sal_Bool ChgHyph( const sal_Bool bNew );
+
+ // Soll die Trennhilfe angeschmissen werden?
+ sal_Bool IsHyphenate() const;
+ inline void SetHyphStart( const xub_StrLen nNew ) { nHyphStart = nNew; }
+ inline xub_StrLen GetHyphStart() const { return nHyphStart; }
+ inline void SetHyphWrdStart( const xub_StrLen nNew ) { nHyphWrdStart = nNew; }
+ inline xub_StrLen GetHyphWrdStart() const { return nHyphWrdStart; }
+ inline void SetHyphWrdLen( const xub_StrLen nNew ) { nHyphWrdLen = nNew; }
+ inline xub_StrLen GetHyphWrdLen() const { return nHyphWrdLen; }
+ inline xub_StrLen GetUnderScorePos() const { return nUnderScorePos; }
+ inline void SetUnderScorePos( xub_StrLen nNew ) { nUnderScorePos = nNew; }
+
+ // ruft HyphenateWord() des Hyphenators
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XHyphenatedWord >
+ HyphWord( const String &rTxt, const USHORT nMinTrail );
+ const com::sun::star::beans::PropertyValues &
+ GetHyphValues() const;
+
+ sal_Bool CheckFtnPortion( SwLineLayout* pCurr )
+ { return IsFtnInside() && _CheckFtnPortion( pCurr ); }
+
+ // Dropcaps vom SwTxtFormatter::CTOR gerufen.
+ const SwFmtDrop *GetDropFmt() const;
+
+ // setzt die FormatInfo wieder in den Anfangszustand
+ void Reset( const SwTxtFrm *pFrame); // , const sal_Bool bAll );
+
+ // Sets the last SwKernPortion as pLast, if it is followed by empty portions
+ BOOL LastKernPortion();
+
+ // Sucht ab nIdx bis nEnd nach Tabs, TabDec, TXTATR und BRK.
+ // Return: gefundene Position, setzt ggf. cHookChar
+ xub_StrLen ScanPortionEnd( const xub_StrLen nStart, const xub_StrLen nEnd );
+
+// friend ostream &operator<<( ostream &rOS, const SwTxtFormatInfo &rInf );
+ friend SvStream &operator<<( SvStream &rOS, const SwTxtFormatInfo &rInf );
+};
+
+/*************************************************************************
+ * class SwTxtSlot
+ *************************************************************************/
+
+// Fuer die Textersetzung und Restaurierung der SwTxtSizeInfo.
+// Die Art und Weise ist etwas kriminell, rInf ist const und wird
+// trotzdem veraendert. Da rInf im DTOR wieder restauriert wird,
+// ist dies zulaessig, es handelt sich um ein "logisches const".
+
+class SwTxtSlot
+{
+ XubString aTxt;
+ const XubString *pOldTxt;
+ const SwWrongList* pOldSmartTagList;
+ const SwWrongList* pOldGrammarCheckList;
+ SwWrongList* pTempList;
+ xub_StrLen nIdx;
+ xub_StrLen nLen;
+ sal_Bool bOn;
+protected:
+ SwTxtSizeInfo *pInf;
+public:
+ // Der Ersetzungstring kommt wahlweise aus der Portion via GetExpText()
+ // oder aus dem char Pointer pCh, wenn dieser ungleich NULL ist.
+ SwTxtSlot( const SwTxtSizeInfo *pNew, const SwLinePortion *pPor, bool bTxtLen,
+ bool bExgLists, const sal_Char *pCh = NULL );
+ ~SwTxtSlot();
+ inline sal_Bool IsOn() const { return bOn; }
+};
+
+/*************************************************************************
+ * class SwFontSave
+ *************************************************************************/
+
+class SwFontSave
+{
+ SwTxtSizeInfo *pInf;
+ SwFont *pFnt;
+ SwAttrIter *pIter;
+public:
+ SwFontSave( const SwTxtSizeInfo &rInf, SwFont *pFnt,
+ SwAttrIter* pItr = NULL );
+ ~SwFontSave();
+};
+
+/*************************************************************************
+ * class SwDefFontSave
+ *************************************************************************/
+
+class SwDefFontSave
+{
+ SwTxtSizeInfo *pInf;
+ SwFont *pFnt;
+ SwFont *pNewFnt;
+ sal_Bool bAlter;
+public:
+ SwDefFontSave( const SwTxtSizeInfo &rInf );
+ ~SwDefFontSave();
+};
+
+/*************************************************************************
+ * Inline-Implementierungen SwTxtSizeInfo
+ *************************************************************************/
+
+inline KSHORT SwTxtSizeInfo::GetAscent() const
+{
+ ASSERT( GetOut(), "SwTxtSizeInfo::GetAscent() without pOut" )
+ return ((SwFont*)GetFont())->GetAscent( pVsh, *GetOut() );
+}
+
+inline KSHORT SwTxtSizeInfo::GetTxtHeight() const
+{
+ ASSERT( GetOut(), "SwTxtSizeInfo::GetTxtHeight() without pOut" )
+ return ((SwFont*)GetFont())->GetHeight( pVsh, *GetOut() );
+}
+
+inline SwPosSize SwTxtSizeInfo::GetTxtSize( const XubString &rTxt ) const
+{
+ return GetTxtSize( pOut, 0, rTxt, 0, rTxt.Len(), 0 );
+}
+
+inline SwPosSize SwTxtSizeInfo::GetTxtSize( const SwScriptInfo* pSI,
+ const xub_StrLen nNewIdx,
+ const xub_StrLen nNewLen,
+ const USHORT nCompress ) const
+{
+ return GetTxtSize( pOut, pSI, *pTxt, nNewIdx, nNewLen, nCompress );
+}
+
+/*************************************************************************
+ * Inline-Implementierungen SwTxtPaintInfo
+ *************************************************************************/
+
+inline SwTwips SwTxtPaintInfo::GetPaintOfst() const
+{
+ return GetParaPortion()->GetRepaint()->GetOfst();
+}
+
+inline void SwTxtPaintInfo::SetPaintOfst( const SwTwips nNew )
+{
+ GetParaPortion()->GetRepaint()->SetOfst( nNew );
+}
+
+
+inline void SwTxtPaintInfo::DrawText( const XubString &rText,
+ const SwLinePortion &rPor,
+ const xub_StrLen nStart, const xub_StrLen nLength,
+ const sal_Bool bKern ) const
+{
+ ((SwTxtPaintInfo*)this)->_DrawText( rText, rPor, nStart, nLength, bKern );
+}
+
+inline void SwTxtPaintInfo::DrawText( const SwLinePortion &rPor,
+ const xub_StrLen nLength, const sal_Bool bKern ) const
+{
+ ((SwTxtPaintInfo*)this)->_DrawText( *pTxt, rPor, nIdx, nLength, bKern );
+}
+
+inline void SwTxtPaintInfo::DrawMarkedText( const SwLinePortion &rPor,
+ const xub_StrLen nLength,
+ const sal_Bool bKern,
+ const sal_Bool bWrong,
+ const sal_Bool bSmartTags,
+ const sal_Bool bGrammarCheck ) const
+{
+ ((SwTxtPaintInfo*)this)->_DrawText( *pTxt, rPor, nIdx, nLength, bKern, bWrong, bSmartTags, bGrammarCheck );
+}
+
+/*************************************************************************
+ * Inline-Implementierungen SwTxtFormatInfo
+ *************************************************************************/
+
+inline xub_StrLen SwTxtFormatInfo::GetReformatStart() const
+{
+ return GetParaPortion()->GetReformat()->Start();
+}
+
+inline const SwAttrSet& SwTxtFormatInfo::GetCharAttr() const
+{
+ return GetTxtFrm()->GetTxtNode()->GetSwAttrSet();
+}
+
+inline void SwTxtFormatInfo::SetParaFtn()
+{
+ GetTxtFrm()->SetFtn( sal_True );
+}
+
+inline sal_Bool SwTxtFormatInfo::IsSoftHyph( const xub_StrLen nPos ) const
+{
+ return CHAR_SOFTHYPHEN == GetTxtFrm()->GetTxtNode()->GetTxt().GetChar(nPos);
+}
+
+
+
+#endif
+
diff --git a/sw/source/core/text/itradj.cxx b/sw/source/core/text/itradj.cxx
new file mode 100644
index 000000000000..b8e361bcae6c
--- /dev/null
+++ b/sw/source/core/text/itradj.cxx
@@ -0,0 +1,919 @@
+ /*************************************************************************
+ *
+ * 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"
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <vcl/outdev.hxx>
+#include <IDocumentSettingAccess.hxx>
+
+#include "frame.hxx" // CalcFlyAdjust()
+#include "paratr.hxx"
+#include "txtcfg.hxx"
+#include "itrtxt.hxx"
+#include "porglue.hxx"
+#include "porlay.hxx"
+#include "porfly.hxx" // CalcFlyAdjust()
+#include "pordrop.hxx" // CalcFlyAdjust()
+#include "pormulti.hxx"
+#include <portab.hxx>
+
+#define MIN_TAB_WIDTH 60
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * SwTxtAdjuster::FormatBlock()
+ *************************************************************************/
+
+void SwTxtAdjuster::FormatBlock( )
+{
+ // In der letzten Zeile gibt's keinen Blocksatz.
+ // Und bei Tabulatoren aus Tradition auch nicht.
+ // 7701: wenn Flys im Spiel sind, geht's weiter
+
+ const SwLinePortion *pFly = 0;
+
+ sal_Bool bSkip = !IsLastBlock() &&
+ nStart + pCurr->GetLen() >= GetInfo().GetTxt().Len();
+
+ // ????: mehrzeilige Felder sind fies: wir muessen kontrollieren,
+ // ob es noch andere Textportions im Absatz gibt.
+ if( bSkip )
+ {
+ const SwLineLayout *pLay = pCurr->GetNext();
+ while( pLay && !pLay->GetLen() )
+ {
+ const SwLinePortion *pPor = pCurr->GetFirstPortion();
+ while( pPor && bSkip )
+ {
+ if( pPor->InTxtGrp() )
+ bSkip = sal_False;
+ pPor = pPor->GetPortion();
+ }
+ pLay = bSkip ? pLay->GetNext() : 0;
+ }
+ }
+
+ if( bSkip )
+ {
+ if( !GetInfo().GetParaPortion()->HasFly() )
+ {
+ if( IsLastCenter() )
+ CalcFlyAdjust( pCurr );
+ pCurr->FinishSpaceAdd();
+ return;
+ }
+ else
+ {
+ const SwLinePortion *pTmpFly = NULL;
+
+ // 7701: beim letzten Fly soll Schluss sein
+ const SwLinePortion *pPos = pCurr->GetFirstPortion();
+ while( pPos )
+ {
+ // Ich suche jetzt den letzten Fly, hinter dem noch Text ist:
+ if( pPos->IsFlyPortion() )
+ pTmpFly = pPos; // Ein Fly wurde gefunden
+ else if ( pTmpFly && pPos->InTxtGrp() )
+ {
+ pFly = pTmpFly; // Ein Fly mit nachfolgendem Text!
+ pTmpFly = NULL;
+ }
+ pPos = pPos->GetPortion();
+ }
+ // 8494: Wenn keiner gefunden wurde, ist sofort Schluss!
+ if( !pFly )
+ {
+ if( IsLastCenter() )
+ CalcFlyAdjust( pCurr );
+ pCurr->FinishSpaceAdd();
+ return;
+ }
+ }
+ }
+
+ const xub_StrLen nOldIdx = GetInfo().GetIdx();
+ GetInfo().SetIdx( nStart );
+ CalcNewBlock( pCurr, pFly );
+ GetInfo().SetIdx( nOldIdx );
+ GetInfo().GetParaPortion()->GetRepaint()->SetOfst(0);
+}
+
+/*************************************************************************
+ * lcl_CheckKashidaPositions()
+ *************************************************************************/
+bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr,
+ xub_StrLen& nKashidas, xub_StrLen& nGluePortion )
+{
+ // i60594 validate Kashida justification
+ xub_StrLen nIdx = rItr.GetStart();
+ xub_StrLen nEnd = rItr.GetEnd();
+
+ // Note on calling KashidaJustify():
+ // Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
+ // total number of kashida positions, or the number of kashida positions after some positions
+ // have been dropped.
+ // Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before.
+ nKashidas = rSI.KashidaJustify ( 0, 0, rItr.GetStart(), rItr.GetLength(), 0 );
+
+ if (!nKashidas) // nothing to do
+ return true;
+
+ // kashida positions found in SwScriptInfo are not necessarily valid in every font
+ // if two characters are replaced by a ligature glyph, there will be no place for a kashida
+ xub_StrLen* pKashidaPos = new xub_StrLen [ nKashidas ];
+ xub_StrLen* pKashidaPosDropped = new xub_StrLen [ nKashidas ];
+ rSI.GetKashidaPositions ( nIdx, rItr.GetLength(), pKashidaPos );
+ xub_StrLen nKashidaIdx = 0;
+ while ( nKashidas && nIdx < nEnd )
+ {
+ rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() );
+ xub_StrLen nNext = rItr.GetNextAttr();
+
+ // is there also a script change before?
+ // if there is, nNext should point to the script change
+ xub_StrLen nNextScript = rSI.NextScriptChg( nIdx );
+ if( nNextScript < nNext )
+ nNext = nNextScript;
+
+ if ( nNext == STRING_LEN || nNext > nEnd )
+ nNext = nEnd;
+ xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx );
+ if ( nKashidasInAttr )
+ {
+ xub_StrLen nKashidasDropped = 0;
+ if ( !SwScriptInfo::IsArabicText( rInf.GetTxt(), nIdx, nNext - nIdx ) )
+ {
+ nKashidasDropped = nKashidasInAttr;
+ nKashidas -= nKashidasDropped;
+ }
+ else
+ {
+ ULONG nOldLayout = rInf.GetOut()->GetLayoutMode();
+ rInf.GetOut()->SetLayoutMode ( nOldLayout | TEXT_LAYOUT_BIDI_RTL );
+ nKashidasDropped = rInf.GetOut()->ValidateKashidas ( rInf.GetTxt(), nIdx, nNext - nIdx,
+ nKashidasInAttr, pKashidaPos + nKashidaIdx,
+ pKashidaPosDropped );
+ rInf.GetOut()->SetLayoutMode ( nOldLayout );
+ if ( nKashidasDropped )
+ {
+ rSI.MarkKashidasInvalid ( nKashidasDropped, pKashidaPosDropped );
+ nKashidas -= nKashidasDropped;
+ nGluePortion -= nKashidasDropped;
+ }
+ }
+ nKashidaIdx += nKashidasInAttr;
+ }
+ nIdx = nNext;
+ }
+ delete[] pKashidaPos;
+ delete[] pKashidaPosDropped;
+
+ // return false if all kashidas have been eliminated
+ return (nKashidas > 0);
+}
+
+/*************************************************************************
+ * lcl_CheckKashidaWidth()
+ *************************************************************************/
+bool lcl_CheckKashidaWidth ( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, xub_StrLen& nKashidas,
+ xub_StrLen& nGluePortion, const long nGluePortionWidth, long& nSpaceAdd )
+{
+ // check kashida width
+ // if width is smaller than minimal kashida width allowed by fonts in the current line
+ // drop one kashida after the other until kashida width is OK
+ bool bAddSpaceChanged;
+ while ( nKashidas )
+ {
+ bAddSpaceChanged = false;
+ xub_StrLen nIdx = rItr.GetStart();
+ xub_StrLen nEnd = rItr.GetEnd();
+ while ( nIdx < nEnd )
+ {
+ rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() );
+ xub_StrLen nNext = rItr.GetNextAttr();
+
+ // is there also a script change before?
+ // if there is, nNext should point to the script change
+ xub_StrLen nNextScript = rSI.NextScriptChg( nIdx );
+ if( nNextScript < nNext )
+ nNext = nNextScript;
+
+ if ( nNext == STRING_LEN || nNext > nEnd )
+ nNext = nEnd;
+ xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx );
+
+ long nFontMinKashida = rInf.GetOut()->GetMinKashida();
+ if ( nFontMinKashida && nKashidasInAttr && SwScriptInfo::IsArabicText( rInf.GetTxt(), nIdx, nNext - nIdx ) )
+ {
+ xub_StrLen nKashidasDropped = 0;
+ while ( nKashidas && nGluePortion && nKashidasInAttr &&
+ nSpaceAdd / SPACING_PRECISION_FACTOR < nFontMinKashida )
+ {
+ --nGluePortion;
+ --nKashidas;
+ --nKashidasInAttr;
+ ++nKashidasDropped;
+ if( !nKashidas || !nGluePortion ) // nothing left, return false to
+ return false; // do regular blank justification
+
+ nSpaceAdd = nGluePortionWidth / nGluePortion;
+ bAddSpaceChanged = true;
+ }
+ if( nKashidasDropped )
+ rSI.MarkKashidasInvalid( nKashidasDropped, nIdx, nNext - nIdx );
+ }
+ if ( bAddSpaceChanged )
+ break; // start all over again
+ nIdx = nNext;
+ }
+ if ( !bAddSpaceChanged )
+ break; // everything was OK
+ }
+ return true;
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcNewBlock()
+ *
+ * CalcNewBlock() darf erst nach CalcLine() gerufen werden !
+ * Aufgespannt wird immer zwischen zwei RandPortions oder FixPortions
+ * (Tabs und Flys). Dabei werden die Glues gezaehlt und ExpandBlock gerufen.
+ *************************************************************************/
+
+void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent,
+ const SwLinePortion *pStopAt, SwTwips nReal, bool bSkipKashida )
+{
+ ASSERT( GetInfo().IsMulti() || SVX_ADJUST_BLOCK == GetAdjust(),
+ "CalcNewBlock: Why?" );
+ ASSERT( pCurrent->Height(), "SwTxtAdjuster::CalcBlockAdjust: missing CalcLine()" );
+
+ pCurrent->InitSpaceAdd();
+ xub_StrLen nGluePortion = 0;
+ xub_StrLen nCharCnt = 0;
+ MSHORT nSpaceIdx = 0;
+
+ // i60591: hennerdrews
+ SwScriptInfo& rSI = GetInfo().GetParaPortion()->GetScriptInfo();
+ SwTxtSizeInfo aInf ( GetTxtFrm() );
+ SwTxtIter aItr ( GetTxtFrm(), &aInf );
+
+ if ( rSI.CountKashida() )
+ {
+ while (aItr.GetCurr() != pCurrent && aItr.GetNext())
+ aItr.Next();
+
+ if( bSkipKashida )
+ {
+ rSI.SetNoKashidaLine ( aItr.GetStart(), aItr.GetLength());
+ }
+ else
+ {
+ rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() );
+ rSI.ClearNoKashidaLine( aItr.GetStart(), aItr.GetLength() );
+ }
+ }
+
+ // Nicht vergessen:
+ // CalcRightMargin() setzt pCurrent->Width() auf die Zeilenbreite !
+ if (!bSkipKashida)
+ CalcRightMargin( pCurrent, nReal );
+
+ // --> FME 2005-06-08 #i49277#
+ const sal_Bool bDoNotJustifyLinesWithManualBreak =
+ GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK);
+ // <--
+
+ SwLinePortion *pPos = pCurrent->GetPortion();
+
+ while( pPos )
+ {
+ if ( bDoNotJustifyLinesWithManualBreak &&
+ pPos->IsBreakPortion() && !IsLastBlock() )
+ {
+ pCurrent->FinishSpaceAdd();
+ break;
+ }
+
+ if ( pPos->InTxtGrp() )
+ nGluePortion = nGluePortion + ((SwTxtPortion*)pPos)->GetSpaceCnt( GetInfo(), nCharCnt );
+ else if( pPos->IsMultiPortion() )
+ {
+ SwMultiPortion* pMulti = (SwMultiPortion*)pPos;
+ // a multiportion with a tabulator inside breaks the text adjustment
+ // a ruby portion will not be stretched by text adjustment
+ // a double line portion takes additional space for each blank
+ // in the wider line
+ if( pMulti->HasTabulator() )
+ {
+ if ( nSpaceIdx == pCurrent->GetLLSpaceAddCount() )
+ pCurrent->SetLLSpaceAdd( 0, nSpaceIdx );
+
+ nSpaceIdx++;
+ nGluePortion = 0;
+ nCharCnt = 0;
+ }
+ else if( pMulti->IsDouble() )
+ nGluePortion = nGluePortion + ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
+ else if ( pMulti->IsBidi() )
+ nGluePortion = nGluePortion + ((SwBidiPortion*)pMulti)->GetSpaceCnt( GetInfo() ); // i60594
+ }
+
+ if( pPos->InGlueGrp() )
+ {
+ if( pPos->InFixMargGrp() )
+ {
+ if ( nSpaceIdx == pCurrent->GetLLSpaceAddCount() )
+ pCurrent->SetLLSpaceAdd( 0, nSpaceIdx );
+
+ const long nGluePortionWidth = static_cast<SwGluePortion*>(pPos)->GetPrtGlue() *
+ SPACING_PRECISION_FACTOR;
+
+ xub_StrLen nKashidas = 0;
+ if( nGluePortion && rSI.CountKashida() && !bSkipKashida )
+ {
+ // kashida positions found in SwScriptInfo are not necessarily valid in every font
+ // if two characters are replaced by a ligature glyph, there will be no place for a kashida
+ if ( !lcl_CheckKashidaPositions ( rSI, aInf, aItr, nKashidas, nGluePortion ))
+ {
+ // all kashida positions are invalid
+ // do regular blank justification
+ pCurrent->FinishSpaceAdd();
+ GetInfo().SetIdx( nStart );
+ CalcNewBlock( pCurrent, pStopAt, nReal, true );
+ return;
+ }
+ }
+
+ if( nGluePortion )
+ {
+ long nSpaceAdd = nGluePortionWidth / nGluePortion;
+
+ // i60594
+ if( rSI.CountKashida() && !bSkipKashida )
+ {
+ if( !lcl_CheckKashidaWidth( rSI, aInf, aItr, nKashidas, nGluePortion, nGluePortionWidth, nSpaceAdd ))
+ {
+ // no kashidas left
+ // do regular blank justification
+ pCurrent->FinishSpaceAdd();
+ GetInfo().SetIdx( nStart );
+ CalcNewBlock( pCurrent, pStopAt, nReal, true );
+ return;
+ }
+ }
+
+ pCurrent->SetLLSpaceAdd( nSpaceAdd , nSpaceIdx );
+ pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() );
+ }
+ else if ( IsOneBlock() && nCharCnt > 1 )
+ {
+ const long nSpaceAdd = - nGluePortionWidth / ( nCharCnt - 1 );
+ pCurrent->SetLLSpaceAdd( nSpaceAdd, nSpaceIdx );
+ pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() );
+ }
+
+ nSpaceIdx++;
+ nGluePortion = 0;
+ nCharCnt = 0;
+ }
+ else
+ ++nGluePortion;
+ }
+ GetInfo().SetIdx( GetInfo().GetIdx() + pPos->GetLen() );
+ if ( pPos == pStopAt )
+ {
+ pCurrent->SetLLSpaceAdd( 0, nSpaceIdx );
+ break;
+ }
+ pPos = pPos->GetPortion();
+ }
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcKanaAdj()
+ *************************************************************************/
+
+SwTwips SwTxtAdjuster::CalcKanaAdj( SwLineLayout* pCurrent )
+{
+ ASSERT( pCurrent->Height(), "SwTxtAdjuster::CalcBlockAdjust: missing CalcLine()" );
+ ASSERT( !pCurrent->GetpKanaComp(), "pKanaComp already exists!!" );
+
+ SvUShorts *pNewKana = new SvUShorts;
+ pCurrent->SetKanaComp( pNewKana );
+
+ const USHORT nNull = 0;
+ MSHORT nKanaIdx = 0;
+ long nKanaDiffSum = 0;
+ SwTwips nRepaintOfst = 0;
+ SwTwips nX = 0;
+ sal_Bool bNoCompression = sal_False;
+
+ // Nicht vergessen:
+ // CalcRightMargin() setzt pCurrent->Width() auf die Zeilenbreite !
+ CalcRightMargin( pCurrent, 0 );
+
+ SwLinePortion* pPos = pCurrent->GetPortion();
+
+ while( pPos )
+ {
+ if ( pPos->InTxtGrp() )
+ {
+ // get maximum portion width from info structure, calculated
+ // during text formatting
+ USHORT nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (ULONG)pPos );
+
+ // check, if information is stored under other key
+ if ( !nMaxWidthDiff && pPos == pCurrent->GetFirstPortion() )
+ nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (ULONG)pCurrent );
+
+ // calculate difference between portion width and max. width
+ nKanaDiffSum += nMaxWidthDiff;
+
+ // we store the beginning of the first compressable portion
+ // for repaint
+ if ( nMaxWidthDiff && !nRepaintOfst )
+ nRepaintOfst = nX + GetLeftMargin();
+ }
+ else if( pPos->InGlueGrp() && pPos->InFixMargGrp() )
+ {
+ if ( nKanaIdx == pCurrent->GetKanaComp().Count() )
+ pCurrent->GetKanaComp().Insert( nNull, nKanaIdx );
+
+ USHORT nRest;
+
+ if ( pPos->InTabGrp() )
+ {
+ nRest = ! bNoCompression &&
+ ( pPos->Width() > MIN_TAB_WIDTH ) ?
+ pPos->Width() - MIN_TAB_WIDTH :
+ 0;
+
+ // for simplifying the handling of left, right ... tabs,
+ // we do expand portions, which are lying behind
+ // those special tabs
+ bNoCompression = !pPos->IsTabLeftPortion();
+ }
+ else
+ {
+ nRest = ! bNoCompression ?
+ ((SwGluePortion*)pPos)->GetPrtGlue() :
+ 0;
+
+ bNoCompression = sal_False;
+ }
+
+ if( nKanaDiffSum )
+ {
+ ULONG nCompress = ( 10000 * nRest ) / nKanaDiffSum;
+
+ if ( nCompress >= 10000 )
+ // kanas can be expanded to 100%, and there is still
+ // some space remaining
+ nCompress = 0;
+
+ else
+ nCompress = 10000 - nCompress;
+
+ ( pCurrent->GetKanaComp() )[ nKanaIdx ] = (USHORT)nCompress;
+ nKanaDiffSum = 0;
+ }
+
+ nKanaIdx++;
+ }
+
+ nX += pPos->Width();
+ pPos = pPos->GetPortion();
+ }
+
+ // set portion width
+ nKanaIdx = 0;
+ USHORT nCompress = ( pCurrent->GetKanaComp() )[ nKanaIdx ];
+ pPos = pCurrent->GetPortion();
+ long nDecompress = 0;
+ nKanaDiffSum = 0;
+
+ while( pPos )
+ {
+ if ( pPos->InTxtGrp() )
+ {
+ const USHORT nMinWidth = pPos->Width();
+
+ // get maximum portion width from info structure, calculated
+ // during text formatting
+ USHORT nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (ULONG)pPos );
+
+ // check, if information is stored under other key
+ if ( !nMaxWidthDiff && pPos == pCurrent->GetFirstPortion() )
+ nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (ULONG)pCurrent );
+ nKanaDiffSum += nMaxWidthDiff;
+ pPos->Width( nMinWidth +
+ ( ( 10000 - nCompress ) * nMaxWidthDiff ) / 10000 );
+ nDecompress += pPos->Width() - nMinWidth;
+ }
+ else if( pPos->InGlueGrp() && pPos->InFixMargGrp() )
+ {
+ if( nCompress )
+ {
+ nKanaDiffSum *= nCompress;
+ nKanaDiffSum /= 10000;
+ }
+
+ pPos->Width( static_cast<USHORT>(pPos->Width() - nDecompress) );
+
+ if ( pPos->InTabGrp() )
+ // set fix width to width
+ ((SwTabPortion*)pPos)->SetFixWidth( pPos->Width() );
+
+ const SvUShorts& rKanaComp = pCurrent->GetKanaComp();
+ if ( ++nKanaIdx < rKanaComp.Count() )
+ nCompress = ( pCurrent->GetKanaComp() )[ nKanaIdx ];
+
+ nKanaDiffSum = 0;
+ nDecompress = 0;
+ }
+ pPos = pPos->GetPortion();
+ }
+
+ return nRepaintOfst;
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcRightMargin()
+ *************************************************************************/
+
+SwMarginPortion *SwTxtAdjuster::CalcRightMargin( SwLineLayout *pCurrent,
+ SwTwips nReal )
+{
+ long nRealWidth;
+ const USHORT nRealHeight = GetLineHeight();
+ const USHORT nLineHeight = pCurrent->Height();
+
+ KSHORT nPrtWidth = pCurrent->PrtWidth();
+ SwLinePortion *pLast = pCurrent->FindLastPortion();
+
+ if( GetInfo().IsMulti() )
+ nRealWidth = nReal;
+ else
+ {
+ nRealWidth = GetLineWidth();
+ // Fuer jeden FlyFrm, der in den rechten Rand hineinragt,
+ // wird eine FlyPortion angelegt.
+ const long nLeftMar = GetLeftMargin();
+ SwRect aCurrRect( nLeftMar + nPrtWidth, Y() + nRealHeight - nLineHeight,
+ nRealWidth - nPrtWidth, nLineHeight );
+
+ SwFlyPortion *pFly = CalcFlyPortion( nRealWidth, aCurrRect );
+ while( pFly && long( nPrtWidth )< nRealWidth )
+ {
+ pLast->Append( pFly );
+ pLast = pFly;
+ if( pFly->Fix() > nPrtWidth )
+ pFly->Width( ( pFly->Fix() - nPrtWidth) + pFly->Width() + 1);
+ nPrtWidth += pFly->Width() + 1;
+ aCurrRect.Left( nLeftMar + nPrtWidth );
+ pFly = CalcFlyPortion( nRealWidth, aCurrRect );
+ }
+ if( pFly )
+ delete pFly;
+ }
+
+ SwMarginPortion *pRight = new SwMarginPortion( 0 );
+ pLast->Append( pRight );
+
+ if( long( nPrtWidth )< nRealWidth )
+ pRight->PrtWidth( KSHORT( nRealWidth - nPrtWidth ) );
+
+ // pCurrent->Width() wird auf die reale Groesse gesetzt,
+ // da jetzt die MarginPortions eingehaengt sind.
+ // Dieser Trick hat wundersame Auswirkungen.
+ // Wenn pCurrent->Width() == nRealWidth ist, dann wird das gesamte
+ // Adjustment implizit ausgecontert. GetLeftMarginAdjust() und
+ // IsBlocksatz() sind der Meinung, sie haetten eine mit Zeichen
+ // gefuellte Zeile.
+
+ pCurrent->PrtWidth( KSHORT( nRealWidth ) );
+ return pRight;
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcFlyAdjust()
+ *************************************************************************/
+
+void SwTxtAdjuster::CalcFlyAdjust( SwLineLayout *pCurrent )
+{
+ // 1) Es wird ein linker Rand eingefuegt:
+ SwMarginPortion *pLeft = pCurrent->CalcLeftMargin();
+ SwGluePortion *pGlue = pLeft; // die letzte GluePortion
+
+
+ // 2) Es wird ein rechter Rand angehaengt:
+ // CalcRightMargin berechnet auch eventuelle Ueberlappungen mit
+ // FlyFrms.
+ CalcRightMargin( pCurrent );
+
+ SwLinePortion *pPos = pLeft->GetPortion();
+ xub_StrLen nLen = 0;
+
+ // Wenn wir nur eine Zeile vorliegen haben und die Textportion zusammen
+ // haengend ist und wenn zentriert wird, dann ...
+
+ sal_Bool bComplete = 0 == nStart;
+ const sal_Bool bTabCompat = GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
+ sal_Bool bMultiTab = sal_False;
+
+ while( pPos )
+ {
+ if ( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasTabulator() )
+ bMultiTab = sal_True;
+ else if( pPos->InFixMargGrp() &&
+ ( bTabCompat ? ! pPos->InTabGrp() : ! bMultiTab ) )
+ {
+ // in tab compat mode we do not want to change tab portions
+ // in non tab compat mode we do not want to change margins if we
+ // found a multi portion with tabs
+ if( SVX_ADJUST_RIGHT == GetAdjust() )
+ ((SwGluePortion*)pPos)->MoveAllGlue( pGlue );
+ else
+ {
+ // Eine schlaue Idee von MA:
+ // Fuer die erste Textportion wird rechtsbuendig eingestellt,
+ // fuer die letzte linksbuendig.
+
+ // Die erste Textportion kriegt den ganzen Glue
+ // Aber nur, wenn wir mehr als eine Zeile besitzen.
+ if( bComplete && GetInfo().GetTxt().Len() == nLen )
+ ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
+ else
+ {
+ if ( ! bTabCompat )
+ {
+ if( pLeft == pGlue )
+ {
+ // Wenn es nur einen linken und rechten Rand gibt,
+ // dann teilen sich die Raender den Glue.
+ if( nLen + pPos->GetLen() >= pCurrent->GetLen() )
+ ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
+ else
+ ((SwGluePortion*)pPos)->MoveAllGlue( pGlue );
+ }
+ else
+ {
+ // Die letzte Textportion behaelt sein Glue
+ if( !pPos->IsMarginPortion() )
+ ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
+ }
+ }
+ else
+ ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
+ }
+ }
+
+ pGlue = (SwFlyPortion*)pPos;
+ bComplete = sal_False;
+ }
+ nLen = nLen + pPos->GetLen();
+ pPos = pPos->GetPortion();
+ }
+
+ if( ! bTabCompat && ! bMultiTab && SVX_ADJUST_RIGHT == GetAdjust() )
+ // portions are moved to the right if possible
+ pLeft->AdjustRight( pCurrent );
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcAdjLine()
+ *************************************************************************/
+
+void SwTxtAdjuster::CalcAdjLine( SwLineLayout *pCurrent )
+{
+ ASSERT( pCurrent->IsFormatAdj(), "CalcAdjLine: Why?" );
+
+ pCurrent->SetFormatAdj(sal_False);
+
+ SwParaPortion* pPara = GetInfo().GetParaPortion();
+
+ switch( GetAdjust() )
+ {
+ case SVX_ADJUST_RIGHT:
+ case SVX_ADJUST_CENTER:
+ {
+ CalcFlyAdjust( pCurrent );
+ pPara->GetRepaint()->SetOfst( 0 );
+ break;
+ }
+ case SVX_ADJUST_BLOCK:
+ {
+ // disabled for #i13507#
+ // 8311: In Zeilen mit LineBreaks gibt es keinen Blocksatz!
+/* if( pCurrent->GetLen() &&
+ CH_BREAK == GetInfo().GetChar( nStart + pCurrent->GetLen() - 1 ) &&
+ !IsLastBlock() )
+ {
+ if( IsLastCenter() )
+ {
+ CalcFlyAdjust( pCurrent );
+ pPara->GetRepaint()->SetOfst( 0 );
+ break;
+ }
+ return;
+ }
+*/ FormatBlock();
+ break;
+ }
+ default : return;
+ }
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcFlyPortion()
+ *
+ * Die Berechnung hat es in sich: nCurrWidth geibt die Breite _vor_ dem
+ * aufaddieren des Wortes das noch auf die Zeile passt! Aus diesem Grund
+ * stimmt die Breite der FlyPortion auch, wenn die Blockierungssituation
+ * bFirstWord && !WORDFITS eintritt.
+ *************************************************************************/
+
+SwFlyPortion *SwTxtAdjuster::CalcFlyPortion( const long nRealWidth,
+ const SwRect &rCurrRect )
+{
+ SwTxtFly aTxtFly( GetTxtFrm() );
+
+ const KSHORT nCurrWidth = pCurr->PrtWidth();
+ SwFlyPortion *pFlyPortion = 0;
+
+ SwRect aLineVert( rCurrRect );
+ if ( GetTxtFrm()->IsRightToLeft() )
+ GetTxtFrm()->SwitchLTRtoRTL( aLineVert );
+ if ( GetTxtFrm()->IsVertical() )
+ GetTxtFrm()->SwitchHorizontalToVertical( aLineVert );
+
+ // aFlyRect ist dokumentglobal !
+ SwRect aFlyRect( aTxtFly.GetFrm( aLineVert ) );
+
+ if ( GetTxtFrm()->IsRightToLeft() )
+ GetTxtFrm()->SwitchRTLtoLTR( aFlyRect );
+ if ( GetTxtFrm()->IsVertical() )
+ GetTxtFrm()->SwitchVerticalToHorizontal( aFlyRect );
+
+ // Wenn ein Frame ueberlappt, wird eine Portion eroeffnet.
+ if( aFlyRect.HasArea() )
+ {
+ // aLocal ist framelokal
+ SwRect aLocal( aFlyRect );
+ aLocal.Pos( aLocal.Left() - GetLeftMargin(), aLocal.Top() );
+ if( nCurrWidth > aLocal.Left() )
+ aLocal.Left( nCurrWidth );
+
+ // Wenn das Rechteck breiter als die Zeile ist, stutzen
+ // wir es ebenfalls zurecht.
+ KSHORT nLocalWidth = KSHORT( aLocal.Left() + aLocal.Width() );
+ if( nRealWidth < long( nLocalWidth ) )
+ aLocal.Width( nRealWidth - aLocal.Left() );
+ GetInfo().GetParaPortion()->SetFly( sal_True );
+ pFlyPortion = new SwFlyPortion( aLocal );
+ pFlyPortion->Height( KSHORT( rCurrRect.Height() ) );
+ // Die Width koennte kleiner sein als die FixWidth, daher:
+ pFlyPortion->AdjFixWidth();
+ }
+ return pFlyPortion;
+}
+
+/*************************************************************************
+ * SwTxtPainter::_CalcDropAdjust()
+ *************************************************************************/
+
+// 6721: Drops und Adjustment
+// CalcDropAdjust wird ggf. am Ende von Format() gerufen.
+
+void SwTxtAdjuster::CalcDropAdjust()
+{
+ ASSERT( 1<GetDropLines() && SVX_ADJUST_LEFT!=GetAdjust() && SVX_ADJUST_BLOCK!=GetAdjust(),
+ "CalcDropAdjust: No reason for DropAdjustment." )
+
+ const MSHORT nLineNumber = GetLineNr();
+
+ // 1) Dummies ueberspringen
+ Top();
+
+ if( !pCurr->IsDummy() || NextLine() )
+ {
+ // Erst adjustieren.
+ GetAdjusted();
+
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+
+ // 2) Sicherstellen, dass die DropPortion dabei ist.
+ // 3) pLeft: Die GluePor vor der DropPor
+ if( pPor->InGlueGrp() && pPor->GetPortion()
+ && pPor->GetPortion()->IsDropPortion() )
+ {
+ const SwLinePortion *pDropPor = (SwDropPortion*) pPor->GetPortion();
+ SwGluePortion *pLeft = (SwGluePortion*) pPor;
+
+ // 4) pRight: Die GluePor hinter der DropPor suchen
+ pPor = pPor->GetPortion();
+ while( pPor && !pPor->InFixMargGrp() )
+ pPor = pPor->GetPortion();
+
+ SwGluePortion *pRight = ( pPor && pPor->InGlueGrp() ) ?
+ (SwGluePortion*) pPor : 0;
+ if( pRight && pRight != pLeft )
+ {
+ // 5) nMinLeft berechnen. Wer steht am weitesten links?
+ const KSHORT nDropLineStart =
+ KSHORT(GetLineStart()) + pLeft->Width() + pDropPor->Width();
+ KSHORT nMinLeft = nDropLineStart;
+ for( MSHORT i = 1; i < GetDropLines(); ++i )
+ {
+ if( NextLine() )
+ {
+ // Erst adjustieren.
+ GetAdjusted();
+
+ pPor = pCurr->GetFirstPortion();
+ const SwMarginPortion *pMar = pPor->IsMarginPortion() ?
+ (SwMarginPortion*)pPor : 0;
+ if( !pMar )
+ nMinLeft = 0;
+ else
+ {
+ const KSHORT nLineStart =
+ KSHORT(GetLineStart()) + pMar->Width();
+ if( nMinLeft > nLineStart )
+ nMinLeft = nLineStart;
+ }
+ }
+ }
+
+ // 6) Den Glue zwischen pLeft und pRight neu verteilen.
+ if( nMinLeft < nDropLineStart )
+ {
+ // Glue wird immer von pLeft nach pRight abgegeben,
+ // damit der Text nach links wandert.
+ const short nGlue = nDropLineStart - nMinLeft;
+ if( !nMinLeft )
+ pLeft->MoveAllGlue( pRight );
+ else
+ pLeft->MoveGlue( pRight, nGlue );
+#ifdef DBGTXT
+ aDbstream << "Drop adjusted: " << nGlue << endl;
+#endif
+ }
+ }
+ }
+ }
+
+ if( nLineNumber != GetLineNr() )
+ {
+ Top();
+ while( nLineNumber != GetLineNr() && Next() )
+ ;
+ }
+}
+
+/*************************************************************************
+ * SwTxtAdjuster::CalcDropRepaint()
+ *************************************************************************/
+
+void SwTxtAdjuster::CalcDropRepaint()
+{
+ Top();
+ SwRepaint &rRepaint = *GetInfo().GetParaPortion()->GetRepaint();
+ if( rRepaint.Top() > Y() )
+ rRepaint.Top( Y() );
+ for( MSHORT i = 1; i < GetDropLines(); ++i )
+ NextLine();
+ const SwTwips nBottom = Y() + GetLineHeight() - 1;
+ if( rRepaint.Bottom() < nBottom )
+ rRepaint.Bottom( nBottom );
+}
+
+
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
new file mode 100644
index 000000000000..60b476839705
--- /dev/null
+++ b/sw/source/core/text/itratr.cxx
@@ -0,0 +1,1078 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <txtatr.hxx>
+#include <sfx2/printer.hxx>
+#include <editeng/lrspitem.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <fmtanchr.hxx>
+#include <fmtfsize.hxx>
+#include <fmtornt.hxx>
+#include <fmtflcnt.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtftn.hxx>
+#include <frmatr.hxx>
+#include <frmfmt.hxx>
+#include <fmtfld.hxx>
+#include <doc.hxx>
+#include <viewsh.hxx> // ViewShell
+#include <rootfrm.hxx>
+#include <docary.hxx>
+#include <ndtxt.hxx>
+#include <dcontact.hxx>
+#include <fldbas.hxx> // SwField
+#include <pam.hxx> // SwPosition (lcl_MinMaxNode)
+#include <itratr.hxx>
+#include <htmltbl.hxx>
+#include <swtable.hxx>
+#include <redlnitr.hxx>
+#include <fmtsrnd.hxx>
+#include <itrtxt.hxx>
+#include <breakit.hxx>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/i18n/ScriptType.hdl>
+
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * SwAttrIter::Chg()
+ *************************************************************************/
+
+void SwAttrIter::Chg( SwTxtAttr *pHt )
+{
+ ASSERT( pHt && pFnt, "No attribute of font available for change");
+ if( pRedln && pRedln->IsOn() )
+ pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True );
+ else
+ aAttrHandler.PushAndChg( *pHt, *pFnt );
+ nChgCnt++;
+}
+
+/*************************************************************************
+ * SwAttrIter::Rst()
+ *************************************************************************/
+
+void SwAttrIter::Rst( SwTxtAttr *pHt )
+{
+ ASSERT( pHt && pFnt, "No attribute of font available for reset");
+ // get top from stack after removing pHt
+ if( pRedln && pRedln->IsOn() )
+ pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False );
+ else
+ aAttrHandler.PopAndChg( *pHt, *pFnt );
+ nChgCnt--;
+}
+
+/*************************************************************************
+ * virtual SwAttrIter::~SwAttrIter()
+ *************************************************************************/
+
+SwAttrIter::~SwAttrIter()
+{
+ delete pRedln;
+ delete pFnt;
+}
+
+/*************************************************************************
+ * SwAttrIter::GetAttr()
+ *
+ * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf
+ * der Position nPos liegt und kein EndIndex besitzt.
+ * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen
+ * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten"
+ * Attribute sind z.B. Felder (die expandierten Text bereit halten) und
+ * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen
+ * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs
+ * an der Startposition ein Sonderzeichen in den String einfuegt.
+ * Der Formatierer stoesst auf das Sonderzeichen und holt sich per
+ * GetAttr() das entartete Attribut.
+ *************************************************************************/
+
+SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const
+{
+ return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0;
+}
+
+/*************************************************************************
+ * SwAttrIter::SeekAndChg()
+ *************************************************************************/
+
+sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut )
+{
+ sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos );
+ if ( pLastOut != pOut )
+ {
+ pLastOut = pOut;
+ pFnt->SetFntChg( sal_True );
+ bChg = sal_True;
+ }
+ if( bChg )
+ {
+ // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
+ // des gewuenschten Fonts ...
+ if ( !nChgCnt && !nPropFont )
+ pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
+ aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
+ pFnt->ChgPhysFnt( pShell, *pOut );
+ }
+ return bChg;
+}
+
+sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos )
+{
+ Seek( nNewPos );
+ if ( !nChgCnt && !nPropFont )
+ pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
+ aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
+ return pFnt->IsSymbol( pShell );
+}
+
+/*************************************************************************
+ * SwAttrIter::SeekStartAndChg()
+ *************************************************************************/
+
+sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont )
+{
+ if ( pRedln && pRedln->ExtOn() )
+ pRedln->LeaveExtend( *pFnt, 0 );
+
+ // reset font to its original state
+ aAttrHandler.Reset();
+ aAttrHandler.ResetFont( *pFnt );
+
+ nStartIndex = nEndIndex = nPos = nChgCnt = 0;
+ if( nPropFont )
+ pFnt->SetProportion( nPropFont );
+ if( pRedln )
+ {
+ pRedln->Clear( pFnt );
+ if( !bParaFont )
+ nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN );
+ else
+ pRedln->Reset();
+ }
+
+ if ( pHints && !bParaFont )
+ {
+ SwTxtAttr *pTxtAttr;
+ // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
+ // das TextAttribut an Position 0 beginnt ...
+ while ( ( nStartIndex < pHints->GetStartCount() ) &&
+ !(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) )
+ {
+ // oeffne die TextAttribute
+ Chg( pTxtAttr );
+ nStartIndex++;
+ }
+ }
+
+ sal_Bool bChg = pFnt->IsFntChg();
+ if ( pLastOut != pOut )
+ {
+ pLastOut = pOut;
+ pFnt->SetFntChg( sal_True );
+ bChg = sal_True;
+ }
+ if( bChg )
+ {
+ // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
+ // des gewuenschten Fonts ...
+ if ( !nChgCnt && !nPropFont )
+ pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
+ aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
+ pFnt->ChgPhysFnt( pShell, *pOut );
+ }
+ return bChg;
+}
+
+/*************************************************************************
+ * SwAttrIter::SeekFwd()
+ *************************************************************************/
+
+// AMA: Neuer AttrIter Nov 94
+
+void SwAttrIter::SeekFwd( const xub_StrLen nNewPos )
+{
+ SwTxtAttr *pTxtAttr;
+
+ if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden...
+ {
+ // Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden.
+
+ // Solange wir noch nicht am Ende des EndArrays angekommen sind &&
+ // das TextAttribut vor oder an der neuen Position endet ...
+ while ( ( nEndIndex < pHints->GetEndCount() ) &&
+ (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
+ {
+ // schliesse die TextAttribute, deren StartPos vor
+ // oder an der alten nPos lag, die z.Z. geoeffnet sind.
+ if (*pTxtAttr->GetStart() <= nPos) Rst( pTxtAttr );
+ nEndIndex++;
+ }
+ }
+ else // ueberlies die nicht geoeffneten Enden
+ {
+ while ( ( nEndIndex < pHints->GetEndCount() ) &&
+ (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
+ {
+ nEndIndex++;
+ }
+ }
+ // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
+ // das TextAttribut vor oder an der neuen Position beginnt ...
+ while ( ( nStartIndex < pHints->GetStartCount() ) &&
+ (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos))
+ {
+ // oeffne die TextAttribute, deren Ende hinter der neuen Position liegt
+ if ( *pTxtAttr->GetAnyEnd() > nNewPos ) Chg( pTxtAttr );
+ nStartIndex++;
+ }
+
+}
+
+/*************************************************************************
+ * SwAttrIter::Seek()
+ *************************************************************************/
+
+sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos )
+{
+ if ( pRedln && pRedln->ExtOn() )
+ pRedln->LeaveExtend( *pFnt, nNewPos );
+
+ if( pHints )
+ {
+ if( !nNewPos || nNewPos < nPos )
+ {
+ if( pRedln )
+ pRedln->Clear( NULL );
+
+ // reset font to its original state
+ aAttrHandler.Reset();
+ aAttrHandler.ResetFont( *pFnt );
+
+ if( nPropFont )
+ pFnt->SetProportion( nPropFont );
+ nStartIndex = nEndIndex = nPos = 0;
+ nChgCnt = 0;
+
+ // Achtung!
+ // resetting the font here makes it necessary to apply any
+ // changes for extended input directly to the font
+ if ( pRedln && pRedln->ExtOn() )
+ {
+ pRedln->UpdateExtFont( *pFnt );
+ ++nChgCnt;
+ }
+ }
+ SeekFwd( nNewPos );
+ }
+
+ pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) );
+
+ if( pRedln )
+ nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos );
+ nPos = nNewPos;
+
+ if( nPropFont )
+ pFnt->SetProportion( nPropFont );
+
+ return pFnt->IsFntChg();
+}
+
+/*************************************************************************
+ * SwAttrIter::GetNextAttr()
+ *************************************************************************/
+
+xub_StrLen SwAttrIter::GetNextAttr( ) const
+{
+ xub_StrLen nNext = STRING_LEN;
+ if( pHints )
+ {
+ if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts?
+ nNext = (*pHints->GetStart(nStartIndex)->GetStart());
+ if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden?
+ {
+ xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd());
+ if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher?
+ }
+ }
+ if (m_pTxtNode!=NULL) {
+ //TODO maybe use hints like FieldHints for this instead of looking at the text...
+ int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len());
+ USHORT p=nPos;
+ const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer();
+ while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++;
+ if ((p<l && p>nPos) || nNext<=p)
+ nNext=p;
+ else
+ nNext=p+1;
+ }
+ if( pRedln )
+ return pRedln->GetNextRedln( nNext );
+ return nNext;
+}
+
+#if OSL_DEBUG_LEVEL > 1
+/*************************************************************************
+ * SwAttrIter::Dump()
+ *************************************************************************/
+
+void SwAttrIter::Dump( SvStream &/*rOS*/ ) const
+{
+// Noch nicht an den neuen Attributiterator angepasst ...
+}
+
+#endif
+
+class SwMinMaxArgs
+{
+public:
+ OutputDevice* pOut;
+ ViewShell* pSh;
+ ULONG &rMin;
+ ULONG &rMax;
+ ULONG &rAbsMin;
+ long nRowWidth;
+ long nWordWidth;
+ long nWordAdd;
+ xub_StrLen nNoLineBreak;
+ SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, ULONG& rMinI, ULONG &rMaxI, ULONG &rAbsI )
+ : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI )
+ { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; }
+ void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; }
+ void NewWord() { nWordAdd = nWordWidth = 0; }
+};
+
+sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt,
+ xub_StrLen nIdx, xub_StrLen nEnd )
+{
+ sal_Bool bRet = sal_False;
+ while( nIdx < nEnd )
+ {
+ xub_StrLen nStop = nIdx;
+ sal_Bool bClear;
+ LanguageType eLang = pFnt->GetLanguage();
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ bClear = CH_BLANK == rTxt.GetChar( nStop );
+ Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx,
+ pBreakIt->GetLocale( eLang ),
+ WordType::DICTIONARY_WORD, TRUE ) );
+ nStop = (xub_StrLen)aBndry.endPos;
+ if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
+ rArg.NewWord();
+ if( nStop == nIdx )
+ ++nStop;
+ if( nStop > nEnd )
+ nStop = nEnd;
+ }
+ else
+ {
+ while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) )
+ ++nStop;
+ bClear = nStop == nIdx;
+ if ( bClear )
+ {
+ rArg.NewWord();
+ while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) )
+ ++nStop;
+ }
+ }
+
+ SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx );
+ long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width();
+ rArg.nRowWidth += nAktWidth;
+ if( bClear )
+ rArg.NewWord();
+ else
+ {
+ rArg.nWordWidth += nAktWidth;
+ if( (long)rArg.rAbsMin < rArg.nWordWidth )
+ rArg.rAbsMin = rArg.nWordWidth;
+ rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
+ bRet = sal_True;
+ }
+ nIdx = nStop;
+ }
+ return bRet;
+}
+
+sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const
+{
+ SwScriptInfo aScriptInfo;
+ SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
+ aIter.Seek( nBegin );
+ const SwRootFrm* pTmpRootFrm = getIDocumentLayoutAccess()->GetRootFrm();
+ return aIter.GetFnt()->IsSymbol( pTmpRootFrm ?
+ pTmpRootFrm->GetCurrShell() :
+ 0 );
+}
+
+class SwMinMaxNodeArgs
+{
+public:
+ ULONG nMaxWidth; // Summe aller Rahmenbreite
+ long nMinWidth; // Breitester Rahmen
+ long nLeftRest; // noch nicht von Rahmen ueberdeckter Platz im l. Rand
+ long nRightRest; // noch nicht von Rahmen ueberdeckter Platz im r. Rand
+ long nLeftDiff; // Min/Max-Differenz des Rahmens im linken Rand
+ long nRightDiff; // Min/Max-Differenz des Rahmens im rechten Rand
+ ULONG nIndx; // Indexnummer des Nodes
+ void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
+};
+
+sal_Bool lcl_MinMaxNode( const SwFrmFmtPtr& rpNd, void* pArgs )
+{
+ const SwFmtAnchor& rFmtA = ((SwFrmFmt*)rpNd)->GetAnchor();
+
+ bool bCalculate = false;
+ if ((FLY_AT_PARA == rFmtA.GetAnchorId()) ||
+ (FLY_AT_CHAR == rFmtA.GetAnchorId()))
+ {
+ bCalculate = true;
+ }
+
+ if (bCalculate)
+ {
+ const SwMinMaxNodeArgs *pIn = (const SwMinMaxNodeArgs*)pArgs;
+ const SwPosition *pPos = rFmtA.GetCntntAnchor();
+ ASSERT(pPos && pIn, "Unexpected NULL arguments");
+ if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
+ bCalculate = false;
+ }
+
+ if (bCalculate)
+ {
+ long nMin, nMax;
+ SwHTMLTableLayout *pLayout = 0;
+ MSHORT nWhich = ((SwFrmFmt*)rpNd)->Which();
+ if( RES_DRAWFRMFMT != nWhich )
+ {
+ // Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle?
+ const SwNodes& rNodes = static_cast<SwFrmFmt*>(rpNd)->GetDoc()->GetNodes();
+ const SwFmtCntnt& rFlyCntnt = ((SwFrmFmt*)rpNd)->GetCntnt();
+ ULONG nStt = rFlyCntnt.GetCntntIdx()->GetIndex();
+ SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode();
+ if( !pTblNd )
+ {
+ SwNode *pNd = rNodes[nStt];
+ pNd = rNodes[pNd->EndOfSectionIndex()-1];
+ if( pNd->IsEndNode() )
+ pTblNd = pNd->StartOfSectionNode()->GetTableNode();
+ }
+
+ if( pTblNd )
+ pLayout = pTblNd->GetTable().GetHTMLTableLayout();
+ }
+
+ const SwFmtHoriOrient& rOrient = ((SwFrmFmt*)rpNd)->GetHoriOrient();
+ sal_Int16 eHoriOri = rOrient.GetHoriOrient();
+
+ long nDiff;
+ if( pLayout )
+ {
+ nMin = pLayout->GetMin();
+ nMax = pLayout->GetMax();
+ nDiff = nMax - nMin;
+ }
+ else
+ {
+ if( RES_DRAWFRMFMT == nWhich )
+ {
+ const SdrObject* pSObj = rpNd->FindSdrObject();
+ if( pSObj )
+ nMin = pSObj->GetCurrentBoundRect().GetWidth();
+ else
+ nMin = 0;
+
+ }
+ else
+ {
+ const SwFmtFrmSize &rSz = ( (SwFrmFmt*)rpNd )->GetFrmSize();
+ nMin = rSz.GetWidth();
+ }
+ nMax = nMin;
+ nDiff = 0;
+ }
+
+ const SvxLRSpaceItem &rLR = ( (SwFrmFmt*)rpNd )->GetLRSpace();
+ nMin += rLR.GetLeft();
+ nMin += rLR.GetRight();
+ nMax += rLR.GetLeft();
+ nMax += rLR.GetRight();
+
+ if( SURROUND_THROUGHT == ((SwFrmFmt*)rpNd)->GetSurround().GetSurround() )
+ {
+ ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
+ return sal_True;
+ }
+
+ // Rahmen, die recht bzw. links ausgerichtet sind, gehen nur
+ // teilweise in die Max-Berechnung ein, da der Rand schon berueck-
+ // sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen,
+ // wird dieser Teil hinzuaddiert.
+ switch( eHoriOri )
+ {
+ case text::HoriOrientation::RIGHT:
+ {
+ if( nDiff )
+ {
+ ((SwMinMaxNodeArgs*)pArgs)->nRightRest -=
+ ((SwMinMaxNodeArgs*)pArgs)->nRightDiff;
+ ((SwMinMaxNodeArgs*)pArgs)->nRightDiff = nDiff;
+ }
+ if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
+ {
+ if( ((SwMinMaxNodeArgs*)pArgs)->nRightRest > 0 )
+ ((SwMinMaxNodeArgs*)pArgs)->nRightRest = 0;
+ }
+ ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= nMin;
+ break;
+ }
+ case text::HoriOrientation::LEFT:
+ {
+ if( nDiff )
+ {
+ ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -=
+ ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff;
+ ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff = nDiff;
+ }
+ if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
+ ((SwMinMaxNodeArgs*)pArgs)->nLeftRest < 0 )
+ ((SwMinMaxNodeArgs*)pArgs)->nLeftRest = 0;
+ ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= nMin;
+ break;
+ }
+ default:
+ {
+ ( (SwMinMaxNodeArgs*)pArgs )->nMaxWidth += nMax;
+ ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
+ }
+ }
+ }
+ return sal_True;
+}
+
+#define FLYINCNT_MIN_WIDTH 284
+
+// changing this method very likely requires changing of
+// "GetScalingOfSelectedText"
+void SwTxtNode::GetMinMaxSize( ULONG nIndex, ULONG& rMin, ULONG &rMax,
+ ULONG& rAbsMin, OutputDevice* pOut ) const
+{
+ ViewShell* pSh = 0;
+ GetDoc()->GetEditShell( &pSh );
+ if( !pOut )
+ {
+ if( pSh )
+ pOut = pSh->GetWin();
+ if( !pOut )
+ pOut = GetpApp()->GetDefaultDevice();
+ }
+
+ MapMode aOldMap( pOut->GetMapMode() );
+ pOut->SetMapMode( MapMode( MAP_TWIP ) );
+
+ rMin = 0;
+ rMax = 0;
+ rAbsMin = 0;
+
+ const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
+ long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True );
+ short nFLOffs;
+ // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich
+ // bereits gefuellt...
+ if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
+ nLROffset = nFLOffs;
+
+ SwMinMaxNodeArgs aNodeArgs;
+ aNodeArgs.nMinWidth = 0;
+ aNodeArgs.nMaxWidth = 0;
+ aNodeArgs.nLeftRest = nLROffset;
+ aNodeArgs.nRightRest = rSpace.GetRight();
+ aNodeArgs.nLeftDiff = 0;
+ aNodeArgs.nRightDiff = 0;
+ if( nIndex )
+ {
+ SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts();
+ if( pTmp )
+ {
+ aNodeArgs.nIndx = nIndex;
+ pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs );
+ }
+ }
+ if( aNodeArgs.nLeftRest < 0 )
+ aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
+ aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
+ if( aNodeArgs.nLeftRest < 0 )
+ aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
+
+ if( aNodeArgs.nRightRest < 0 )
+ aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
+ aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
+ if( aNodeArgs.nRightRest < 0 )
+ aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
+
+ SwScriptInfo aScriptInfo;
+ SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
+ xub_StrLen nIdx = 0;
+ aIter.SeekAndChgAttrIter( nIdx, pOut );
+ xub_StrLen nLen = m_Text.Len();
+ long nAktWidth = 0;
+ MSHORT nAdd = 0;
+ SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
+ while( nIdx < nLen )
+ {
+ xub_StrLen nNextChg = aIter.GetNextAttr();
+ xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
+ if( nNextChg > nStop )
+ nNextChg = nStop;
+ SwTxtAttr *pHint = NULL;
+ xub_Unicode cChar = CH_BLANK;
+ nStop = nIdx;
+ while( nStop < nLen && nStop < nNextChg &&
+ CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) &&
+ CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
+ CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
+ !pHint )
+ {
+ if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
+ || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
+ ++nStop;
+ }
+ if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
+ {
+ nAdd = 20;
+ }
+ nIdx = nStop;
+ aIter.SeekAndChgAttrIter( nIdx, pOut );
+ switch( cChar )
+ {
+ case CH_BREAK :
+ {
+ if( (long)rMax < aArg.nRowWidth )
+ rMax = aArg.nRowWidth;
+ aArg.nRowWidth = 0;
+ aArg.NewWord();
+ aIter.SeekAndChgAttrIter( ++nIdx, pOut );
+ }
+ break;
+ case CH_TAB :
+ {
+ aArg.NewWord();
+ aIter.SeekAndChgAttrIter( ++nIdx, pOut );
+ }
+ break;
+ case CHAR_SOFTHYPHEN:
+ ++nIdx;
+ break;
+ case CHAR_HARDBLANK:
+ case CHAR_HARDHYPHEN:
+ {
+ XubString sTmp( cChar );
+ const SwRootFrm* pTmpRootFrm = getIDocumentLayoutAccess()->GetRootFrm();
+ SwDrawTextInfo aDrawInf( pTmpRootFrm ?
+ pTmpRootFrm->GetCurrShell() :
+ 0, *pOut, 0, sTmp, 0, 1, 0, sal_False );
+ nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
+ aArg.nWordWidth += nAktWidth;
+ aArg.nRowWidth += nAktWidth;
+ if( (long)rAbsMin < aArg.nWordWidth )
+ rAbsMin = aArg.nWordWidth;
+ aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
+ aArg.nNoLineBreak = nIdx++;
+ }
+ break;
+ case CH_TXTATR_BREAKWORD:
+ case CH_TXTATR_INWORD:
+ {
+ if( !pHint )
+ break;
+ long nOldWidth = aArg.nWordWidth;
+ long nOldAdd = aArg.nWordAdd;
+ aArg.NewWord();
+
+ switch( pHint->Which() )
+ {
+ case RES_TXTATR_FLYCNT :
+ {
+ SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt();
+ const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace();
+ if( RES_DRAWFRMFMT == pFrmFmt->Which() )
+ {
+ const SdrObject* pSObj = pFrmFmt->FindSdrObject();
+ if( pSObj )
+ nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
+ else
+ nAktWidth = 0;
+ }
+ else
+ {
+ const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize();
+ if( RES_FLYFRMFMT == pFrmFmt->Which()
+ && rTmpSize.GetWidthPercent() )
+ {
+/*-----------------24.01.97 14:09----------------------------------------------
+ * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich
+ * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale
+ * Breite 0,5 cm und als maximale KSHRT_MAX.
+ * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt
+ * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen.
+ * --------------------------------------------------------------------------*/
+ nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm
+ if( (long)rMax < KSHRT_MAX )
+ rMax = KSHRT_MAX;
+ }
+ else
+ nAktWidth = pFrmFmt->GetFrmSize().GetWidth();
+ }
+ nAktWidth += rLR.GetLeft();
+ nAktWidth += rLR.GetRight();
+ aArg.nWordAdd = nOldWidth + nOldAdd;
+ aArg.nWordWidth = nAktWidth;
+ aArg.nRowWidth += nAktWidth;
+ if( (long)rAbsMin < aArg.nWordWidth )
+ rAbsMin = aArg.nWordWidth;
+ aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
+ break;
+ }
+ case RES_TXTATR_FTN :
+ {
+ const XubString aTxt = pHint->GetFtn().GetNumStr();
+ if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
+ aTxt.Len() ) )
+ nAdd = 20;
+ break;
+ }
+ case RES_TXTATR_FIELD :
+ {
+ SwField *pFld = (SwField*)pHint->GetFld().GetFld();
+ const String aTxt = pFld->GetCntnt( FALSE );
+ if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
+ aTxt.Len() ) )
+ nAdd = 20;
+ break;
+ }
+ default: aArg.nWordWidth = nOldWidth;
+ aArg.nWordAdd = nOldAdd;
+
+ }
+ aIter.SeekAndChgAttrIter( ++nIdx, pOut );
+ }
+ break;
+ }
+ }
+ if( (long)rMax < aArg.nRowWidth )
+ rMax = aArg.nRowWidth;
+
+ nLROffset += rSpace.GetRight();
+
+ rAbsMin += nLROffset;
+ rAbsMin += nAdd;
+ rMin += nLROffset;
+ rMin += nAdd;
+ if( (long)rMin < aNodeArgs.nMinWidth )
+ rMin = aNodeArgs.nMinWidth;
+ if( (long)rAbsMin < aNodeArgs.nMinWidth )
+ rAbsMin = aNodeArgs.nMinWidth;
+ rMax += aNodeArgs.nMaxWidth;
+ rMax += nLROffset;
+ rMax += nAdd;
+ if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
+ rMax = rMin; // in das Minimum ein
+ pOut->SetMapMode( aOldMap );
+}
+
+/*************************************************************************
+ * SwTxtNode::GetScalingOfSelectedText()
+ *
+ * Calculates the width of the text part specified by nStt and nEnd,
+ * the height of the line containing nStt is devided by this width,
+ * indicating the scaling factor, if the text part is rotated.
+ * Having CH_BREAKs in the text part, this method returns the scaling
+ * factor for the longest of the text parts separated by the CH_BREAKs.
+ *
+ * changing this method very likely requires changing of "GetMinMaxSize"
+ *************************************************************************/
+
+USHORT SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd )
+ const
+{
+ ViewShell* pSh = NULL;
+ OutputDevice* pOut = NULL;
+ GetDoc()->GetEditShell( &pSh );
+
+ if ( pSh )
+ pOut = &pSh->GetRefDev();
+ else
+ {
+ //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
+ if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) )
+ pOut = GetpApp()->GetDefaultDevice();
+ else
+ pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
+ }
+
+ ASSERT( pOut, "GetScalingOfSelectedText without outdev" )
+
+ MapMode aOldMap( pOut->GetMapMode() );
+ pOut->SetMapMode( MapMode( MAP_TWIP ) );
+
+ if ( nStt == nEnd )
+ {
+ if ( !pBreakIt->GetBreakIter().is() )
+ return 100;
+
+ SwScriptInfo aScriptInfo;
+ SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
+ aIter.SeekAndChgAttrIter( nStt, pOut );
+
+ Boundary aBound =
+ pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
+ pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
+ WordType::DICTIONARY_WORD, sal_True );
+
+ if ( nStt == aBound.startPos )
+ {
+ // cursor is at left or right border of word
+ pOut->SetMapMode( aOldMap );
+ return 100;
+ }
+
+ nStt = (xub_StrLen)aBound.startPos;
+ nEnd = (xub_StrLen)aBound.endPos;
+
+ if ( nStt == nEnd )
+ {
+ pOut->SetMapMode( aOldMap );
+ return 100;
+ }
+ }
+
+ SwScriptInfo aScriptInfo;
+ SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
+
+ // We do not want scaling attributes to be considered during this
+ // calculation. For this, we push a temporary scaling attribute with
+ // scaling value 100 and priority flag on top of the scaling stack
+ SwAttrHandler& rAH = aIter.GetAttrHandler();
+ SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
+ SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
+ aAttr.SetPriorityAttr( sal_True );
+ rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
+
+ xub_StrLen nIdx = nStt;
+
+ ULONG nWidth = 0;
+ ULONG nProWidth = 0;
+
+ while( nIdx < nEnd )
+ {
+ aIter.SeekAndChgAttrIter( nIdx, pOut );
+
+ // scan for end of portion
+ xub_StrLen nNextChg = aIter.GetNextAttr();
+ xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
+ if( nNextChg > nStop )
+ nNextChg = nStop;
+
+ nStop = nIdx;
+ xub_Unicode cChar = CH_BLANK;
+ SwTxtAttr* pHint = NULL;
+
+ // stop at special characters in [ nIdx, nNextChg ]
+ while( nStop < nEnd && nStop < nNextChg )
+ {
+ cChar = m_Text.GetChar( nStop );
+ if( CH_TAB == cChar || CH_BREAK == cChar ||
+ CHAR_HARDBLANK == cChar || CHAR_HARDHYPHEN == cChar ||
+ CHAR_SOFTHYPHEN == cChar ||
+ ( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar ) &&
+ ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
+ break;
+ else
+ ++nStop;
+ }
+
+ // calculate text widths up to cChar
+ if ( nStop > nIdx )
+ {
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
+ nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
+ }
+
+ nIdx = nStop;
+ aIter.SeekAndChgAttrIter( nIdx, pOut );
+
+ if ( cChar == CH_BREAK )
+ {
+ nWidth = Max( nWidth, nProWidth );
+ nProWidth = 0;
+ nIdx++;
+ }
+ else if ( cChar == CH_TAB )
+ {
+ // tab receives width of one space
+ XubString sTmp( CH_BLANK );
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
+ nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
+ nIdx++;
+ }
+ else if ( cChar == CHAR_SOFTHYPHEN )
+ ++nIdx;
+ else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
+ {
+ XubString sTmp( cChar );
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
+ nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
+ nIdx++;
+ }
+ else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
+ {
+ switch( pHint->Which() )
+ {
+ case RES_TXTATR_FTN :
+ {
+ const XubString aTxt = pHint->GetFtn().GetNumStr();
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
+
+ nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
+ break;
+ }
+ case RES_TXTATR_FIELD :
+ {
+ SwField *pFld = (SwField*)pHint->GetFld().GetFld();
+ const String aTxt = pFld->GetCntnt( FALSE );
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
+
+ nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
+ break;
+ }
+ default:
+ {
+ // any suggestions for a default action?
+ }
+ } // end of switch
+ nIdx++;
+ } // end of while
+ }
+
+ nWidth = Max( nWidth, nProWidth );
+
+ // search for a text frame this node belongs to
+ SwClientIter aClientIter( *(SwTxtNode*)this );
+ SwClient* pLastFrm = aClientIter.GoStart();
+ SwTxtFrm* pFrm = 0;
+
+ while( pLastFrm )
+ {
+ if ( pLastFrm->ISA( SwTxtFrm ) )
+ {
+ SwTxtFrm* pTmpFrm = ( SwTxtFrm* )pLastFrm;
+ if ( pTmpFrm->GetOfst() <= nStt &&
+ ( !pTmpFrm->GetFollow() ||
+ pTmpFrm->GetFollow()->GetOfst() > nStt ) )
+ {
+ pFrm = pTmpFrm;
+ break;
+ }
+ }
+ pLastFrm = ++aClientIter;
+ }
+
+ // search for the line containing nStt
+ if ( pFrm && pFrm->HasPara() )
+ {
+ SwTxtInfo aInf( pFrm );
+ SwTxtIter aLine( pFrm, &aInf );
+ aLine.CharToLine( nStt );
+ pOut->SetMapMode( aOldMap );
+ return (USHORT)( nWidth ?
+ ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
+ }
+ // no frame or no paragraph, we take the height of the character
+ // at nStt as line height
+
+ aIter.SeekAndChgAttrIter( nStt, pOut );
+ pOut->SetMapMode( aOldMap );
+
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
+ return (USHORT)
+ ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
+}
+
+USHORT SwTxtNode::GetWidthOfLeadingTabs() const
+{
+ USHORT nRet = 0;
+
+ xub_StrLen nIdx = 0;
+ sal_Unicode cCh;
+
+ while ( nIdx < GetTxt().Len() &&
+ ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
+ ' ' == cCh ) )
+ ++nIdx;
+
+ if ( nIdx > 0 )
+ {
+ SwPosition aPos( *this );
+ aPos.nContent += nIdx;
+
+ // Find the non-follow text frame:
+ SwClientIter aClientIter( (SwTxtNode&)*this );
+ SwClient* pLastFrm = aClientIter.GoStart();
+
+ while( pLastFrm )
+ {
+ // Only consider master frames:
+ if ( pLastFrm->ISA(SwTxtFrm) &&
+ !static_cast<SwTxtFrm*>(pLastFrm)->IsFollow() )
+ {
+ const SwTxtFrm* pFrm = static_cast<SwTxtFrm*>(pLastFrm);
+ SWRECTFN( pFrm )
+ SwRect aRect;
+ pFrm->GetCharRect( aRect, aPos );
+ nRet = (USHORT)
+ ( pFrm->IsRightToLeft() ?
+ (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
+ (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
+ break;
+ }
+ pLastFrm = ++aClientIter;
+ }
+ }
+
+ return nRet;
+}
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
new file mode 100644
index 000000000000..5a8854c8c075
--- /dev/null
+++ b/sw/source/core/text/itratr.hxx
@@ -0,0 +1,131 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _ITRATR_HXX
+#define _ITRATR_HXX
+#include <atrhndl.hxx>
+
+#include "txttypes.hxx"
+#include "swfont.hxx"
+#include "porlay.hxx"
+
+#define _SVSTDARR_XUB_STRLEN
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+
+class OutputDevice;
+class SwFont;
+class SwpHints;
+class SwTxtAttr;
+class SwAttrSet;
+class SwTxtNode;
+class SwRedlineItr;
+class ViewShell;
+class SwTxtFrm;
+
+/*************************************************************************
+ * class SwAttrIter
+ *************************************************************************/
+
+class SwAttrIter
+{
+ friend class SwFontSave;
+protected:
+
+ SwAttrHandler aAttrHandler;
+ ViewShell *pShell;
+ SwFont *pFnt;
+ SwpHints *pHints;
+ const SwAttrSet* pAttrSet; // das Char-Attribut-Set
+ SwScriptInfo* pScriptInfo;
+
+private:
+ OutputDevice *pLastOut;
+ MSHORT nChgCnt;
+ SwRedlineItr *pRedln;
+ xub_StrLen nStartIndex, nEndIndex, nPos;
+ BYTE nPropFont;
+ void SeekFwd( const xub_StrLen nPos );
+ inline void SetFnt( SwFont* pNew ) { pFnt = pNew; }
+ const void* aMagicNo[ SW_SCRIPTS ];
+ MSHORT aFntIdx[ SW_SCRIPTS ];
+ const SwTxtNode* m_pTxtNode;
+
+protected:
+ void Chg( SwTxtAttr *pHt );
+ void Rst( SwTxtAttr *pHt );
+ void CtorInitAttrIter( SwTxtNode& rTxtNode, SwScriptInfo& rScrInf, SwTxtFrm* pFrm = 0 );
+ inline SwAttrIter(SwTxtNode* pTxtNode)
+ : pShell(0), pFnt(0), pLastOut(0), nChgCnt(0), pRedln(0), nPropFont(0), m_pTxtNode(pTxtNode) {}
+
+public:
+ // Konstruktor, Destruktor
+ inline SwAttrIter( SwTxtNode& rTxtNode, SwScriptInfo& rScrInf )
+ : pShell(0), pFnt(0), pHints(0), pScriptInfo(0), pLastOut(0), nChgCnt(0), pRedln(0),nPropFont(0), m_pTxtNode(&rTxtNode)
+ { CtorInitAttrIter( rTxtNode, rScrInf ); }
+
+ virtual ~SwAttrIter();
+
+ inline SwRedlineItr *GetRedln() { return pRedln; }
+ // Liefert im Parameter die Position des naechsten Wechsels vor oder an
+ // der uebergebenen Characterposition zurueck. Liefert sal_False, wenn vor
+ // oder an dieser Position kein Wechsel mehr erfolgt, sal_True sonst.
+ xub_StrLen GetNextAttr( ) const;
+ // Macht die an der Characterposition i gueltigen Attribute im
+ // logischen Font wirksam.
+ sal_Bool Seek( const xub_StrLen nPos );
+ // Bastelt den Font an der gew. Position via Seek und fragt ihn,
+ // ob er ein Symbolfont ist.
+ sal_Bool IsSymbol( const xub_StrLen nPos );
+
+ // Fuehrt ChgPhysFnt aus, wenn Seek() sal_True zurueckliefert.
+ sal_Bool SeekAndChgAttrIter( const xub_StrLen nPos, OutputDevice* pOut );
+ sal_Bool SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont = sal_False );
+
+ // Gibt es ueberhaupt Attributwechsel ?
+ inline sal_Bool HasHints() const { return 0 != pHints; }
+
+ // liefert fuer eine Position das Attribut
+ SwTxtAttr *GetAttr( const xub_StrLen nPos ) const;
+
+ inline const SwAttrSet* GetAttrSet() const { return pAttrSet; }
+
+ inline const SwpHints *GetHints() const { return pHints; }
+
+ inline SwFont *GetFnt() { return pFnt; }
+ inline const SwFont *GetFnt() const { return pFnt; }
+
+ inline BYTE GetPropFont() const { return nPropFont; }
+ inline void SetPropFont( const BYTE nNew ) { nPropFont = nNew; }
+
+ inline SwAttrHandler& GetAttrHandler() { return aAttrHandler; }
+
+#if OSL_DEBUG_LEVEL > 1
+ void Dump( SvStream &rOS ) const;
+#endif
+};
+
+#endif
diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx
new file mode 100644
index 000000000000..438f7c246287
--- /dev/null
+++ b/sw/source/core/text/itrcrsr.cxx
@@ -0,0 +1,1856 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+#include "errhdl.hxx"
+#include "ndtxt.hxx"
+#include "frmfmt.hxx"
+#include "paratr.hxx"
+#include "flyfrm.hxx"
+#include "pam.hxx"
+#include "swselectionlist.hxx"
+#include <sortedobjs.hxx>
+#include <editeng/protitem.hxx>
+#include <editeng/adjitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <frmatr.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <pagefrm.hxx>
+
+#include "txtcfg.hxx"
+#include "itrtxt.hxx"
+#include "txtfrm.hxx"
+#include "flyfrms.hxx"
+#include "porglue.hxx" // SwFlyCnt
+#include "porfld.hxx" // SwFldPortion::IsFollow()
+#include "porfly.hxx" // GetFlyCrsrOfst()
+#include "pordrop.hxx"
+#include "crstate.hxx" // SwCrsrMoveState
+#include <pormulti.hxx> // SwMultiPortion
+
+// Nicht reentrant !!!
+// wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet.
+sal_Bool SwTxtCursor::bRightMargin = sal_False;
+
+
+/*************************************************************************
+ * lcl_GetCharRectInsideField
+ *
+ * After calculating the position of a character during GetCharRect
+ * this function allows to find the coordinates of a position (defined
+ * in pCMS->pSpecialPos) inside a special portion (e.g., a field)
+ *************************************************************************/
+void lcl_GetCharRectInsideField( SwTxtSizeInfo& rInf, SwRect& rOrig,
+ const SwCrsrMoveState& rCMS,
+ const SwLinePortion& rPor )
+{
+ ASSERT( rCMS.pSpecialPos, "Information about special pos missing" )
+
+ if ( rPor.InFldGrp() && ((SwFldPortion&)rPor).GetExp().Len() )
+ {
+ const USHORT nCharOfst = rCMS.pSpecialPos->nCharOfst;
+ USHORT nFldIdx = 0;
+ USHORT nFldLen = 0;
+
+ const XubString* pString = 0;
+ const SwLinePortion* pPor = &rPor;
+ do
+ {
+ if ( pPor->InFldGrp() )
+ {
+ pString = &((SwFldPortion*)pPor)->GetExp();
+ nFldLen = pString->Len();
+ }
+ else
+ {
+ pString = 0;
+ nFldLen = 0;
+ }
+
+ if ( ! pPor->GetPortion() || nFldIdx + nFldLen > nCharOfst )
+ break;
+
+ nFldIdx = nFldIdx + nFldLen;
+ rOrig.Pos().X() += pPor->Width();
+ pPor = pPor->GetPortion();
+
+ } while ( TRUE );
+
+ ASSERT( nCharOfst >= nFldIdx, "Request of position inside field failed" )
+ USHORT nLen = nCharOfst - nFldIdx + 1;
+
+ if ( pString )
+ {
+ // get script for field portion
+ rInf.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString, 0 ) );
+
+ xub_StrLen nOldLen = pPor->GetLen();
+ ((SwLinePortion*)pPor)->SetLen( nLen - 1 );
+ const SwTwips nX1 = pPor->GetLen() ?
+ pPor->GetTxtSize( rInf ).Width() :
+ 0;
+
+ SwTwips nX2 = 0;
+ if ( rCMS.bRealWidth )
+ {
+ ((SwLinePortion*)pPor)->SetLen( nLen );
+ nX2 = pPor->GetTxtSize( rInf ).Width();
+ }
+
+ ((SwLinePortion*)pPor)->SetLen( nOldLen );
+
+ rOrig.Pos().X() += nX1;
+ rOrig.Width( ( nX2 > nX1 ) ?
+ ( nX2 - nX1 ) :
+ 1 );
+ }
+ }
+ else
+ {
+ // special cases: no common fields, e.g., graphic number portion,
+ // FlyInCntPortions, Notes
+ rOrig.Width( rCMS.bRealWidth && rPor.Width() ? rPor.Width() : 1 );
+ }
+}
+
+/*************************************************************************
+ * SwTxtMargin::CtorInitTxtMargin()
+ *************************************************************************/
+void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
+{
+ CtorInitTxtIter( pNewFrm, pNewInf );
+
+ pInf = pNewInf;
+ GetInfo().SetFont( GetFnt() );
+ const SwTxtNode *pNode = pFrm->GetTxtNode();
+
+ const SvxLRSpaceItem &rSpace = pFrm->GetTxtNode()->GetSwAttrSet().GetLRSpace();
+ // --> OD 2009-09-08 #i95907#, #b6879723#
+ const bool bListLevelIndentsApplicable = pFrm->GetTxtNode()->AreListLevelIndentsApplicable();
+ // <--
+
+ //
+ // Carefully adjust the text formatting ranges.
+ //
+ // This whole area desperately needs some rework. There are
+ // quite a couple of values that need to be considered:
+ // 1. paragraph indent
+ // 2. paragraph first line indent
+ // 3. numbering indent
+ // 4. numbering spacing to text
+ // 5. paragraph border
+ // Note: These values have already been used during calculation
+ // of the printing area of the paragraph.
+ const int nLMWithNum = pNode->GetLeftMarginWithNum( sal_True );
+ if ( pFrm->IsRightToLeft() )
+ {
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ // this calculation is identical this the calculation for L2R layout - see below
+ nLeft = pFrm->Frm().Left() +
+ pFrm->Prt().Left() +
+ nLMWithNum -
+ pNode->GetLeftMarginWithNum( sal_False ) -
+ // --> OD 2009-09-08 #i95907#, #b6879723#
+// rSpace.GetLeft() +
+// rSpace.GetTxtLeft();
+ ( bListLevelIndentsApplicable
+ ? 0
+ : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
+ // <--
+ }
+ else
+ {
+ // --> OD 2009-09-08 #i95907#, #b6879723#
+// if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
+ if ( bListLevelIndentsApplicable ||
+ !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
+ // <--
+ {
+ // this calculation is identical this the calculation for R2L layout - see above
+ nLeft = pFrm->Frm().Left() +
+ pFrm->Prt().Left() +
+ nLMWithNum -
+ pNode->GetLeftMarginWithNum( sal_False ) -
+ // --> OD 2009-09-08 #i95907#, #b6879723#
+// rSpace.GetLeft() +
+// rSpace.GetTxtLeft();
+ ( bListLevelIndentsApplicable
+ ? 0
+ : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
+ // <--
+ }
+ else
+ {
+ nLeft = pFrm->Frm().Left() +
+ Max( long( rSpace.GetTxtLeft() + nLMWithNum ),
+ pFrm->Prt().Left() );
+ }
+ }
+
+ nRight = pFrm->Frm().Left() + pFrm->Prt().Left() + pFrm->Prt().Width();
+
+ if( nLeft >= nRight &&
+ // --> FME 2005-08-10 #i53066# Omit adjustment of nLeft for numbered
+ // paras inside cells inside new documents:
+ ( pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ||
+ !pFrm->IsInTab() ||
+ !nLMWithNum ) )
+ // <--
+ {
+ nLeft = pFrm->Prt().Left() + pFrm->Frm().Left();
+ if( nLeft >= nRight ) // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten
+ nRight = nLeft + 1; // einen goennen wir uns immer
+ }
+
+ if( pFrm->IsFollow() && pFrm->GetOfst() )
+ nFirst = nLeft;
+ else
+ {
+ short nFLOfst = 0;
+ long nFirstLineOfs = 0;
+ if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) &&
+ rSpace.IsAutoFirst() )
+ {
+ nFirstLineOfs = GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
+ const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
+ if( pSpace )
+ {
+ switch( pSpace->GetLineSpaceRule() )
+ {
+ case SVX_LINE_SPACE_AUTO:
+ break;
+ case SVX_LINE_SPACE_MIN:
+ {
+ if( nFirstLineOfs < KSHORT( pSpace->GetLineHeight() ) )
+ nFirstLineOfs = pSpace->GetLineHeight();
+ break;
+ }
+ case SVX_LINE_SPACE_FIX:
+ nFirstLineOfs = pSpace->GetLineHeight();
+ break;
+ default: ASSERT( sal_False, ": unknown LineSpaceRule" );
+ }
+ switch( pSpace->GetInterLineSpaceRule() )
+ {
+ case SVX_INTER_LINE_SPACE_OFF:
+ break;
+ case SVX_INTER_LINE_SPACE_PROP:
+ {
+ long nTmp = pSpace->GetPropLineSpace();
+ // 50% ist das Minimum, bei 0% schalten wir auf
+ // den Defaultwert 100% um ...
+ if( nTmp < 50 )
+ nTmp = nTmp ? 50 : 100;
+
+ nTmp *= nFirstLineOfs;
+ nTmp /= 100;
+ if( !nTmp )
+ ++nTmp;
+ nFirstLineOfs = (KSHORT)nTmp;
+ break;
+ }
+ case SVX_INTER_LINE_SPACE_FIX:
+ {
+ nFirstLineOfs += pSpace->GetInterLineSpace();
+ break;
+ }
+ default: ASSERT( sal_False, ": unknown InterLineSpaceRule" );
+ }
+ }
+ }
+ else
+ nFirstLineOfs = nFLOfst;
+
+ // --> OD 2009-09-08 #i95907#, #b6879723#
+// if ( pFrm->IsRightToLeft() ||
+// !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
+ if ( pFrm->IsRightToLeft() ||
+ bListLevelIndentsApplicable ||
+ !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
+ // <--
+ {
+ nFirst = nLeft + nFirstLineOfs;
+ }
+ else
+ {
+ nFirst = pFrm->Frm().Left() +
+ Max( rSpace.GetTxtLeft() + nLMWithNum+ nFirstLineOfs,
+ pFrm->Prt().Left() );
+ }
+
+ // --> OD 2008-01-31 #newlistlevelattrs#
+ // Note: <SwTxtFrm::GetAdditionalFirstLineOffset()> returns a negative
+ // value for the new list label postion and space mode LABEL_ALIGNMENT
+ // and label alignment CENTER and RIGHT in L2R layout respectively
+ // label alignment LEFT and CENTER in R2L layout
+ nFirst += pFrm->GetAdditionalFirstLineOffset();
+ // <--
+
+ if( nFirst >= nRight )
+ nFirst = nRight - 1;
+ }
+ const SvxAdjustItem& rAdjust = pFrm->GetTxtNode()->GetSwAttrSet().GetAdjust();
+ nAdjust = static_cast<USHORT>(rAdjust.GetAdjust());
+
+ // left is left and right is right
+ if ( pFrm->IsRightToLeft() )
+ {
+ if ( SVX_ADJUST_LEFT == nAdjust )
+ nAdjust = SVX_ADJUST_RIGHT;
+ else if ( SVX_ADJUST_RIGHT == nAdjust )
+ nAdjust = SVX_ADJUST_LEFT;
+ }
+
+ bOneBlock = rAdjust.GetOneWord() == SVX_ADJUST_BLOCK;
+ bLastBlock = rAdjust.GetLastBlock() == SVX_ADJUST_BLOCK;
+ bLastCenter = rAdjust.GetLastBlock() == SVX_ADJUST_CENTER;
+
+ // --> OD 2008-07-01 #i91133#
+ mnTabLeft = pNode->GetLeftMarginForTabCalculation();
+ // <--
+
+#if OSL_DEBUG_LEVEL > 1
+ static sal_Bool bOne = sal_False;
+ static sal_Bool bLast = sal_False;
+ static sal_Bool bCenter = sal_False;
+ bOneBlock |= bOne;
+ bLastBlock |= bLast;
+ bLastCenter |= bCenter;
+#endif
+ DropInit();
+}
+
+/*************************************************************************
+ * SwTxtMargin::DropInit()
+ *************************************************************************/
+void SwTxtMargin::DropInit()
+{
+ nDropLeft = nDropLines = nDropHeight = nDropDescent = 0;
+ const SwParaPortion *pPara = GetInfo().GetParaPortion();
+ if( pPara )
+ {
+ const SwDropPortion *pPorDrop = pPara->FindDropPortion();
+ if ( pPorDrop )
+ {
+ nDropLeft = pPorDrop->GetDropLeft();
+ nDropLines = pPorDrop->GetLines();
+ nDropHeight = pPorDrop->GetDropHeight();
+ nDropDescent = pPorDrop->GetDropDescent();
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtMargin::GetLineStart()
+ *************************************************************************/
+
+// Unter Beruecksichtigung des Erstzeileneinzuges und der angebenen Breite.
+SwTwips SwTxtMargin::GetLineStart() const
+{
+ SwTwips nRet = GetLeftMargin();
+ if( GetAdjust() != SVX_ADJUST_LEFT &&
+ !pCurr->GetFirstPortion()->IsMarginPortion() )
+ {
+ // Wenn die erste Portion ein Margin ist, dann wird das
+ // Adjustment durch die Portions ausgedrueckt.
+ if( GetAdjust() == SVX_ADJUST_RIGHT )
+ nRet = Right() - CurrWidth();
+ else if( GetAdjust() == SVX_ADJUST_CENTER )
+ nRet += (GetLineWidth() - CurrWidth()) / 2;
+ }
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtCursor::CtorInitTxtCursor()
+ *************************************************************************/
+void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
+{
+ CtorInitTxtMargin( pNewFrm, pNewInf );
+ // 6096: Vorsicht, die Iteratoren sind abgeleitet!
+ // GetInfo().SetOut( GetInfo().GetWin() );
+}
+
+/*************************************************************************
+ * SwTxtCursor::GetEndCharRect()
+ *************************************************************************/
+
+// 1170: Antikbug: Shift-Ende vergisst das letzte Zeichen ...
+
+sal_Bool SwTxtCursor::GetEndCharRect( SwRect* pOrig, const xub_StrLen nOfst,
+ SwCrsrMoveState* pCMS, const long nMax )
+{
+ // 1170: Mehrdeutigkeit von Dokumentpositionen
+ bRightMargin = sal_True;
+ CharCrsrToLine(nOfst);
+
+ // Etwas verdreht: nOfst bezeichnet die Position hinter dem letzten
+ // Zeichen der letzten Zeile == Position vor dem ersten Zeichen der
+ // Zeile in der wir gerade stehen:
+ if( nOfst != GetStart() || !pCurr->GetLen() )
+ {
+ // 8810: Masterzeile RightMargin, danach LeftMargin
+ const sal_Bool bRet = GetCharRect( pOrig, nOfst, pCMS, nMax );
+ bRightMargin = nOfst >= GetEnd() && nOfst < GetInfo().GetTxt().Len();
+ return bRet;
+ }
+
+ if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() )
+ return GetCharRect( pOrig, nOfst, pCMS, nMax );
+
+ // Adjustierung ggf. nachholen
+ GetAdjusted();
+
+ KSHORT nX = 0;
+ KSHORT nLast = 0;
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+
+ KSHORT nTmpHeight, nTmpAscent;
+ CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+ KSHORT nPorHeight = nTmpHeight;
+ KSHORT nPorAscent = nTmpAscent;
+
+ // Die letzte Text/EndPortion der Zeile suchen
+ while( pPor )
+ {
+ nX = nX + pPor->Width();
+ if( pPor->InTxtGrp() || ( pPor->GetLen() && !pPor->IsFlyPortion()
+ && !pPor->IsHolePortion() ) || pPor->IsBreakPortion() )
+ {
+ nLast = nX;
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+ pPor = pPor->GetPortion();
+ }
+
+ const Size aCharSize( 1, nTmpHeight );
+ pOrig->Pos( GetTopLeft() );
+ pOrig->SSize( aCharSize );
+ pOrig->Pos().X() += nLast;
+ const SwTwips nTmpRight = Right() - 1;
+ if( pOrig->Left() > nTmpRight )
+ pOrig->Pos().X() = nTmpRight;
+
+ if ( pCMS && pCMS->bRealHeight )
+ {
+ if ( nTmpAscent > nPorAscent )
+ pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
+ else
+ pCMS->aRealHeight.X() = 0;
+ ASSERT( nPorHeight, "GetCharRect: Missing Portion-Height" );
+ pCMS->aRealHeight.Y() = nPorHeight;
+ }
+
+ return sal_True;
+}
+
+/*************************************************************************
+ * void SwTxtCursor::_GetCharRect(..)
+ * internal function, called by SwTxtCursor::GetCharRect() to calculate
+ * the relative character position in the current line.
+ * pOrig referes to x and y coordinates, width and height of the cursor
+ * pCMS is used for restricting the cursor, if there are different font
+ * heights in one line ( first value = offset to y of pOrig, second
+ * value = real height of (shortened) cursor
+ *************************************************************************/
+
+void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst,
+ SwCrsrMoveState* pCMS )
+{
+ const XubString &rText = GetInfo().GetTxt();
+ SwTxtSizeInfo aInf( GetInfo(), rText, nStart );
+ if( GetPropFont() )
+ aInf.GetFont()->SetProportion( GetPropFont() );
+ KSHORT nTmpAscent, nTmpHeight; // Zeilenhoehe
+ CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+ const Size aCharSize( 1, nTmpHeight );
+ const Point aCharPos;
+ pOrig->Pos( aCharPos );
+ pOrig->SSize( aCharSize );
+
+ // If we are looking for a position inside a field which covers
+ // more than one line we may not skip any "empty portions" at the
+ // beginning of a line
+ const sal_Bool bInsideFirstField = pCMS && pCMS->pSpecialPos &&
+ ( pCMS->pSpecialPos->nLineOfst ||
+ SP_EXTEND_RANGE_BEFORE ==
+ pCMS->pSpecialPos->nExtendRange );
+
+ sal_Bool bWidth = pCMS && pCMS->bRealWidth;
+ if( !pCurr->GetLen() && !pCurr->Width() )
+ {
+ if ( pCMS && pCMS->bRealHeight )
+ {
+ pCMS->aRealHeight.X() = 0;
+ pCMS->aRealHeight.Y() = nTmpHeight;
+ }
+ }
+ else
+ {
+ KSHORT nPorHeight = nTmpHeight;
+ KSHORT nPorAscent = nTmpAscent;
+ SwTwips nX = 0;
+ SwTwips nTmpFirst = 0;
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+ SwBidiPortion* pLastBidiPor = 0;
+ SwTwips nLastBidiPorWidth = 0;
+ SvUShorts* pKanaComp = pCurr->GetpKanaComp();
+ MSHORT nSpaceIdx = 0;
+ MSHORT nKanaIdx = 0;
+ long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
+
+ sal_Bool bNoTxt = sal_True;
+
+ // Zuerst werden alle Portions ohne Len am Zeilenanfang uebersprungen.
+ // Ausnahme bilden die fiesen Spezialportions aus WhichFirstPortion:
+ // Num, ErgoSum, FtnNum, FeldReste
+ // 8477: aber auch die einzige Textportion einer leeren Zeile mit
+ // Right/Center-Adjustment! Also nicht nur pPor->GetExpandPortion() ...
+ while( pPor && !pPor->GetLen() && ! bInsideFirstField )
+ {
+ nX += pPor->Width();
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nX += pPor->CalcSpacing( nSpaceAdd, aInf );
+ if( bNoTxt )
+ nTmpFirst = nX;
+ // 8670: EndPortions zaehlen hier einmal als TxtPortions.
+ // --> OD 2008-01-28 #newlistlevelattrs#
+// if( pPor->InTxtGrp() || pPor->IsBreakPortion() )
+ if( pPor->InTxtGrp() || pPor->IsBreakPortion() || pPor->InTabGrp() )
+ // <--
+ {
+ bNoTxt = sal_False;
+ nTmpFirst = nX;
+ }
+ if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
+ {
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
+ ++nKanaIdx;
+ }
+ if( pPor->InFixMargGrp() )
+ {
+ if( pPor->IsMarginPortion() )
+ bNoTxt = sal_False;
+ else
+ {
+ // fix margin portion => next SpaceAdd, KanaComp value
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
+ ++nKanaIdx;
+ }
+ }
+ pPor = pPor->GetPortion();
+ }
+
+ if( !pPor )
+ {
+ // Es sind nur Spezialportions unterwegs.
+ nX = nTmpFirst;
+ }
+ else
+ {
+ if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
+ (!pPor->InFldGrp() || pPor->GetAscent() ) )
+ {
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+ while( pPor && !pPor->IsBreakPortion() && ( aInf.GetIdx() < nOfst ||
+ ( bWidth && ( pPor->IsKernPortion() || pPor->IsMultiPortion() ) ) ) )
+ {
+ if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
+ (!pPor->InFldGrp() || pPor->GetAscent() ) )
+ {
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+
+ // If we are behind the portion, we add the portion width to
+ // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen().
+ // For common portions (including BidiPortions) we want to add
+ // the portion width to nX. For MultiPortions, nExtra = 0,
+ // therefore we go to the 'else' branch and start a recursion.
+ const BYTE nExtra = pPor->IsMultiPortion() &&
+ ! ((SwMultiPortion*)pPor)->IsBidi() &&
+ ! bWidth ? 0 : 1;
+ if ( aInf.GetIdx() + pPor->GetLen() < nOfst + nExtra )
+ {
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nX += pPor->PrtWidth() +
+ pPor->CalcSpacing( nSpaceAdd, aInf );
+ else
+ {
+ if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
+ {
+ // update to current SpaceAdd, KanaComp values
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if ( pKanaComp &&
+ ( nKanaIdx + 1 ) < pKanaComp->Count()
+ )
+ ++nKanaIdx;
+ }
+ if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
+ !pPor->GetPortion()->IsMarginPortion() ) )
+ nX += pPor->PrtWidth();
+ }
+ if( pPor->IsMultiPortion() )
+ {
+ if ( ((SwMultiPortion*)pPor)->HasTabulator() )
+ {
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
+ ++nKanaIdx;
+ }
+
+ // if we are right behind a BidiPortion, we have to
+ // hold a pointer to the BidiPortion in order to
+ // find the correct cursor position, depending on the
+ // cursor level
+ if ( ((SwMultiPortion*)pPor)->IsBidi() &&
+ aInf.GetIdx() + pPor->GetLen() == nOfst )
+ {
+ pLastBidiPor = (SwBidiPortion*)pPor;
+ nLastBidiPorWidth = pLastBidiPor->Width() +
+ pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );;
+ }
+ }
+
+ aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() );
+ pPor = pPor->GetPortion();
+ }
+ else
+ {
+ if( pPor->IsMultiPortion() )
+ {
+ nTmpAscent = AdjustBaseLine( *pCurr, pPor );
+ GetInfo().SetMulti( sal_True );
+ pOrig->Pos().Y() += nTmpAscent - nPorAscent;
+
+ if( pCMS && pCMS->b2Lines )
+ {
+ sal_Bool bRecursion = sal_True;
+ if ( ! pCMS->p2Lines )
+ {
+ pCMS->p2Lines = new Sw2LinesPos;
+ pCMS->p2Lines->aLine = SwRect(aCharPos, aCharSize);
+ bRecursion = sal_False;
+ }
+
+ if( ((SwMultiPortion*)pPor)->HasRotation() )
+ {
+ if( ((SwMultiPortion*)pPor)->IsRevers() )
+ pCMS->p2Lines->nMultiType = MT_ROT_270;
+ else
+ pCMS->p2Lines->nMultiType = MT_ROT_90;
+ }
+ else if( ((SwMultiPortion*)pPor)->IsDouble() )
+ pCMS->p2Lines->nMultiType = MT_TWOLINE;
+ else if( ((SwMultiPortion*)pPor)->IsBidi() )
+ pCMS->p2Lines->nMultiType = MT_BIDI;
+ else
+ pCMS->p2Lines->nMultiType = MT_RUBY;
+
+ SwTwips nTmpWidth = pPor->Width();
+ if( nSpaceAdd )
+ nTmpWidth += pPor->CalcSpacing(nSpaceAdd, aInf);
+
+ SwRect aRect( Point(aCharPos.X() + nX, pOrig->Top() ),
+ Size( nTmpWidth, pPor->Height() ) );
+
+ if ( ! bRecursion )
+ pCMS->p2Lines->aPortion = aRect;
+ else
+ pCMS->p2Lines->aPortion2 = aRect;
+ }
+
+ // In a multi-portion we use GetCharRect()-function
+ // recursively and must add the x-position
+ // of the multi-portion.
+ xub_StrLen nOldStart = nStart;
+ SwTwips nOldY = nY;
+ BYTE nOldProp = GetPropFont();
+ nStart = aInf.GetIdx();
+ SwLineLayout* pOldCurr = pCurr;
+ pCurr = &((SwMultiPortion*)pPor)->GetRoot();
+ if( ((SwMultiPortion*)pPor)->IsDouble() )
+ SetPropFont( 50 );
+
+ GETGRID( GetTxtFrm()->FindPageFrm() )
+ const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
+ const USHORT nRubyHeight = bHasGrid ?
+ pGrid->GetRubyHeight() : 0;
+
+ if( nStart + pCurr->GetLen() <= nOfst && GetNext() &&
+ ( ! ((SwMultiPortion*)pPor)->IsRuby() ||
+ ((SwMultiPortion*)pPor)->OnTop() ) )
+ {
+ USHORT nOffset;
+ // in grid mode we may only add the height of the
+ // ruby line if ruby line is on top
+ if ( bHasGrid &&
+ ((SwMultiPortion*)pPor)->IsRuby() &&
+ ((SwMultiPortion*)pPor)->OnTop() )
+ nOffset = nRubyHeight;
+ else
+ nOffset = GetLineHeight();
+
+ pOrig->Pos().Y() += nOffset;
+ Next();
+ }
+
+ sal_Bool bSpaceChg = ((SwMultiPortion*)pPor)->
+ ChgSpaceAdd( pCurr, nSpaceAdd );
+ Point aOldPos = pOrig->Pos();
+
+ // Ok, for ruby portions in grid mode we have to
+ // temporarily set the inner line height to the
+ // outer line height because that value is needed
+ // for the adjustment inside the recursion
+ const USHORT nOldRubyHeight = pCurr->Height();
+ const USHORT nOldRubyRealHeight = pCurr->GetRealHeight();
+ const sal_Bool bChgHeight =
+ ((SwMultiPortion*)pPor)->IsRuby() && bHasGrid;
+
+ if ( bChgHeight )
+ {
+ pCurr->Height( pOldCurr->Height() - nRubyHeight );
+ pCurr->SetRealHeight( pOldCurr->GetRealHeight() -
+ nRubyHeight );
+ }
+
+ SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
+ if ( ((SwMultiPortion*)pPor)->IsBidi() )
+ {
+ aLayoutModeModifier.Modify(
+ ((SwBidiPortion*)pPor)->GetLevel() % 2 );
+ }
+
+ _GetCharRect( pOrig, nOfst, pCMS );
+
+ if ( bChgHeight )
+ {
+ pCurr->Height( nOldRubyHeight );
+ pCurr->SetRealHeight( nOldRubyRealHeight );
+ }
+
+ // if we are still in the first row of
+ // our 2 line multiportion, we use the FirstMulti flag
+ // to indicate this
+ if ( ((SwMultiPortion*)pPor)->IsDouble() )
+ {
+ // the recursion may have damaged our font size
+ SetPropFont( nOldProp );
+ if ( !nOldProp )
+ nOldProp = 100;
+ GetInfo().GetFont()->SetProportion( 100 );
+
+ if ( pCurr == &((SwMultiPortion*)pPor)->GetRoot() )
+ {
+ GetInfo().SetFirstMulti( sal_True );
+
+ // we want to treat a double line portion like a
+ // single line portion, if there is no text in
+ // the second line
+ if ( !pCurr->GetNext() ||
+ !pCurr->GetNext()->GetLen() )
+ GetInfo().SetMulti( sal_False );
+ }
+ }
+ // ruby portions are treated like single line portions
+ else if( ((SwMultiPortion*)pPor)->IsRuby() ||
+ ((SwMultiPortion*)pPor)->IsBidi() )
+ GetInfo().SetMulti( sal_False );
+
+ // calculate cursor values
+ if( ((SwMultiPortion*)pPor)->HasRotation() )
+ {
+ GetInfo().SetMulti( sal_False );
+ long nTmp = pOrig->Width();
+ pOrig->Width( pOrig->Height() );
+ pOrig->Height( nTmp );
+ nTmp = pOrig->Left() - aOldPos.X();
+
+ // if we travel into our rotated portion from
+ // a line below, we have to take care, that the
+ // y coord in pOrig is less than line height:
+ if ( nTmp )
+ nTmp--;
+
+ pOrig->Pos().X() = nX + aOldPos.X();
+ if( ((SwMultiPortion*)pPor)->IsRevers() )
+ pOrig->Pos().Y() = aOldPos.Y() + nTmp;
+ else
+ pOrig->Pos().Y() = aOldPos.Y()
+ + pPor->Height() - nTmp - pOrig->Height();
+ if ( pCMS && pCMS->bRealHeight )
+ {
+ pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
+ // result for rotated multi portion is not
+ // correct for reverse (270 degree) portions
+ if( ((SwMultiPortion*)pPor)->IsRevers() )
+ {
+ if ( SvxParaVertAlignItem::AUTOMATIC ==
+ GetLineInfo().GetVertAlign() )
+ // if vertical alignment is set to auto,
+ // we switch from base line alignment
+ // to centered alignment
+ pCMS->aRealHeight.X() =
+ ( pOrig->Width() +
+ pCMS->aRealHeight.Y() ) / 2;
+ else
+ pCMS->aRealHeight.X() =
+ ( pOrig->Width() -
+ pCMS->aRealHeight.X() +
+ pCMS->aRealHeight.Y() );
+ }
+ }
+ }
+ else
+ {
+ pOrig->Pos().Y() += aOldPos.Y();
+ if ( ((SwMultiPortion*)pPor)->IsBidi() )
+ {
+ const SwTwips nPorWidth = pPor->Width() +
+ pPor->CalcSpacing( nSpaceAdd, aInf );
+ const SwTwips nInsideOfst = pOrig->Pos().X();
+ pOrig->Pos().X() = nX + nPorWidth -
+ nInsideOfst - pOrig->Width();
+ }
+ else
+ pOrig->Pos().X() += nX;
+
+ if( ((SwMultiPortion*)pPor)->HasBrackets() )
+ pOrig->Pos().X() +=
+ ((SwDoubleLinePortion*)pPor)->PreWidth();
+ }
+
+ if( bSpaceChg )
+ SwDoubleLinePortion::ResetSpaceAdd( pCurr );
+
+ pCurr = pOldCurr;
+ nStart = nOldStart;
+ nY = nOldY;
+ bPrev = sal_False;
+
+ return;
+ }
+ if ( pPor->PrtWidth() )
+ {
+ xub_StrLen nOldLen = pPor->GetLen();
+ pPor->SetLen( nOfst - aInf.GetIdx() );
+ aInf.SetLen( pPor->GetLen() );
+ if( nX || !pPor->InNumberGrp() )
+ {
+ SeekAndChg( aInf );
+ const sal_Bool bOldOnWin = aInf.OnWin();
+ aInf.SetOnWin( sal_False ); // keine BULLETs!
+ SwTwips nTmp = nX;
+ aInf.SetKanaComp( pKanaComp );
+ aInf.SetKanaIdx( nKanaIdx );
+ nX += pPor->GetTxtSize( aInf ).Width();
+ aInf.SetOnWin( bOldOnWin );
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nX += pPor->CalcSpacing( nSpaceAdd, aInf );
+ if( bWidth )
+ {
+ pPor->SetLen( pPor->GetLen() + 1 );
+ aInf.SetLen( pPor->GetLen() );
+ aInf.SetOnWin( sal_False ); // keine BULLETs!
+ nTmp += pPor->GetTxtSize( aInf ).Width();
+ aInf.SetOnWin( bOldOnWin );
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nTmp += pPor->CalcSpacing(nSpaceAdd, aInf);
+ pOrig->Width( nTmp - nX );
+ }
+ }
+ pPor->SetLen( nOldLen );
+ }
+ bWidth = sal_False;
+ break;
+ }
+ }
+ }
+
+ if( pPor )
+ {
+ ASSERT( !pPor->InNumberGrp() || bInsideFirstField, "Number surprise" );
+ sal_Bool bEmptyFld = sal_False;
+ if( pPor->InFldGrp() && pPor->GetLen() )
+ {
+ SwFldPortion *pTmp = (SwFldPortion*)pPor;
+ while( pTmp->HasFollow() && !pTmp->GetExp().Len() )
+ {
+ KSHORT nAddX = pTmp->Width();
+ SwLinePortion *pNext = pTmp->GetPortion();
+ while( pNext && !pNext->InFldGrp() )
+ {
+ ASSERT( !pNext->GetLen(), "Where's my field follow?" );
+ nAddX = nAddX + pNext->Width();
+ pNext = pNext->GetPortion();
+ }
+ if( !pNext )
+ break;
+ pTmp = (SwFldPortion*)pNext;
+ nPorHeight = pTmp->Height();
+ nPorAscent = pTmp->GetAscent();
+ nX += nAddX;
+ bEmptyFld = sal_True;
+ }
+ }
+ // 8513: Felder im Blocksatz, ueberspringen
+ while( pPor && !pPor->GetLen() && ! bInsideFirstField &&
+ ( pPor->IsFlyPortion() || pPor->IsKernPortion() ||
+ pPor->IsBlankPortion() || pPor->InTabGrp() ||
+ ( !bEmptyFld && pPor->InFldGrp() ) ) )
+ {
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nX += pPor->PrtWidth() +
+ pPor->CalcSpacing( nSpaceAdd, aInf );
+ else
+ {
+ if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
+ {
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
+ ++nKanaIdx;
+ }
+ if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
+ !pPor->GetPortion()->IsMarginPortion() ) )
+ nX += pPor->PrtWidth();
+ }
+ if( pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->HasTabulator() )
+ {
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
+ ++nKanaIdx;
+ }
+ if( !pPor->IsFlyPortion() )
+ {
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+ pPor = pPor->GetPortion();
+ }
+
+ if( aInf.GetIdx() == nOfst && pPor && pPor->InHyphGrp() &&
+ pPor->GetPortion() && pPor->GetPortion()->InFixGrp() )
+ {
+ // Alle Sonderportions muessen uebersprungen werden
+ // Beispiel: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right()
+ // Ohne den Ausgleich landen wir vor '-' mit dem
+ // Ausgleich vor 's'.
+ while( pPor && !pPor->GetLen() )
+ {
+ DBG_LOOP;
+ nX += pPor->Width();
+ if( !pPor->IsMarginPortion() )
+ {
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+ pPor = pPor->GetPortion();
+ }
+ }
+ if( pPor && pCMS )
+ {
+ if( pCMS->bFieldInfo && pPor->InFldGrp() && pPor->Width() )
+ pOrig->Width( pPor->Width() );
+ if( pPor->IsDropPortion() )
+ {
+ nPorAscent = ((SwDropPortion*)pPor)->GetDropHeight();
+ // The drop height is only calculated, if we have more than
+ // one line. Otherwise it is 0.
+ if ( ! nPorAscent)
+ nPorAscent = pPor->Height();
+ nPorHeight = nPorAscent;
+ pOrig->Height( nPorHeight +
+ ((SwDropPortion*)pPor)->GetDropDescent() );
+ if( nTmpHeight < pOrig->Height() )
+ {
+ nTmpAscent = nPorAscent;
+ nTmpHeight = USHORT( pOrig->Height() );
+ }
+ }
+ if( bWidth && pPor->PrtWidth() && pPor->GetLen() &&
+ aInf.GetIdx() == nOfst )
+ {
+ if( !pPor->IsFlyPortion() && pPor->Height() &&
+ pPor->GetAscent() )
+ {
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+ SwTwips nTmp;
+ if( 2 > pPor->GetLen() )
+ {
+ nTmp = pPor->Width();
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nTmp += pPor->CalcSpacing( nSpaceAdd, aInf );
+ }
+ else
+ {
+ const sal_Bool bOldOnWin = aInf.OnWin();
+ xub_StrLen nOldLen = pPor->GetLen();
+ pPor->SetLen( 1 );
+ aInf.SetLen( pPor->GetLen() );
+ SeekAndChg( aInf );
+ aInf.SetOnWin( sal_False ); // keine BULLETs!
+ aInf.SetKanaComp( pKanaComp );
+ aInf.SetKanaIdx( nKanaIdx );
+ nTmp = pPor->GetTxtSize( aInf ).Width();
+ aInf.SetOnWin( bOldOnWin );
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ nTmp += pPor->CalcSpacing( nSpaceAdd, aInf );
+ pPor->SetLen( nOldLen );
+ }
+ pOrig->Width( nTmp );
+ }
+
+ // travel inside field portion?
+ if ( pCMS->pSpecialPos )
+ {
+ // apply attributes to font
+ Seek( nOfst );
+ lcl_GetCharRectInsideField( aInf, *pOrig, *pCMS, *pPor );
+ }
+ }
+ }
+
+ // special case: We are at the beginning of a BidiPortion or
+ // directly behind a BidiPortion
+ if ( pCMS &&
+ ( pLastBidiPor ||
+ ( pPor &&
+ pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->IsBidi() ) ) )
+ {
+ // we determine if the cursor has to blink before or behind
+ // the bidi portion
+ if ( pLastBidiPor )
+ {
+ const BYTE nPortionLevel = pLastBidiPor->GetLevel();
+
+ if ( pCMS->nCursorBidiLevel >= nPortionLevel )
+ {
+ // we came from inside the bidi portion, we want to blink
+ // behind the portion
+ pOrig->Pos().X() -= nLastBidiPorWidth;
+
+ // Again, there is a special case: logically behind
+ // the portion can actually mean that the cursor is inside
+ // the portion. This can happen is the last portion
+ // inside the bidi portion is a nested bidi portion
+ SwLineLayout& rLineLayout =
+ ((SwMultiPortion*)pLastBidiPor)->GetRoot();
+
+ const SwLinePortion *pLast = rLineLayout.FindLastPortion();
+ if ( pLast->IsMultiPortion() )
+ {
+ ASSERT( ((SwMultiPortion*)pLast)->IsBidi(),
+ "Non-BidiPortion inside BidiPortion" )
+ pOrig->Pos().X() += pLast->Width() +
+ pLast->CalcSpacing( nSpaceAdd, aInf );
+ }
+ }
+ }
+ else
+ {
+ const BYTE nPortionLevel = ((SwBidiPortion*)pPor)->GetLevel();
+
+ if ( pCMS->nCursorBidiLevel >= nPortionLevel )
+ {
+ // we came from inside the bidi portion, we want to blink
+ // behind the portion
+ pOrig->Pos().X() += pPor->Width() +
+ pPor->CalcSpacing( nSpaceAdd, aInf );
+ }
+ }
+ }
+
+ pOrig->Pos().X() += nX;
+
+ if ( pCMS && pCMS->bRealHeight )
+ {
+ nTmpAscent = AdjustBaseLine( *pCurr, 0, nPorHeight, nPorAscent );
+ if ( nTmpAscent > nPorAscent )
+ pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
+ else
+ pCMS->aRealHeight.X() = 0;
+ ASSERT( nPorHeight, "GetCharRect: Missing Portion-Height" );
+ if ( nTmpHeight > nPorHeight )
+ pCMS->aRealHeight.Y() = nPorHeight;
+ else
+ pCMS->aRealHeight.Y() = nTmpHeight;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtCursor::GetCharRect()
+ *************************************************************************/
+
+sal_Bool SwTxtCursor::GetCharRect( SwRect* pOrig, const xub_StrLen nOfst,
+ SwCrsrMoveState* pCMS, const long nMax )
+{
+ CharCrsrToLine(nOfst);
+
+ // Indicates that a position inside a special portion (field, number portion)
+ // is requested.
+ const sal_Bool bSpecialPos = pCMS && pCMS->pSpecialPos;
+ xub_StrLen nFindOfst = nOfst;
+
+ if ( bSpecialPos )
+ {
+ const BYTE nExtendRange = pCMS->pSpecialPos->nExtendRange;
+
+ ASSERT( ! pCMS->pSpecialPos->nLineOfst || SP_EXTEND_RANGE_BEFORE != nExtendRange,
+ "LineOffset AND Number Portion?" )
+
+ // portions which are behind the string
+ if ( SP_EXTEND_RANGE_BEHIND == nExtendRange )
+ ++nFindOfst;
+
+ // skip lines for fields which cover more than one line
+ for ( USHORT i = 0; i < pCMS->pSpecialPos->nLineOfst; i++ )
+ Next();
+ }
+
+ // Adjustierung ggf. nachholen
+ GetAdjusted();
+
+ const Point aCharPos( GetTopLeft() );
+ sal_Bool bRet = sal_True;
+
+ _GetCharRect( pOrig, nFindOfst, pCMS );
+
+ const SwTwips nTmpRight = Right() - 12;
+
+ pOrig->Pos().X() += aCharPos.X();
+ pOrig->Pos().Y() += aCharPos.Y();
+
+ if( pCMS && pCMS->b2Lines && pCMS->p2Lines )
+ {
+ pCMS->p2Lines->aLine.Pos().X() += aCharPos.X();
+ pCMS->p2Lines->aLine.Pos().Y() += aCharPos.Y();
+ pCMS->p2Lines->aPortion.Pos().X() += aCharPos.X();
+ pCMS->p2Lines->aPortion.Pos().Y() += aCharPos.Y();
+ }
+
+ if( pOrig->Left() > nTmpRight )
+ pOrig->Pos().X() = nTmpRight;
+
+ if( nMax )
+ {
+ if( pOrig->Top() + pOrig->Height() > nMax )
+ {
+ if( pOrig->Top() > nMax )
+ pOrig->Top( nMax );
+ pOrig->Height( nMax - pOrig->Top() );
+ }
+ if ( pCMS && pCMS->bRealHeight && pCMS->aRealHeight.Y() >= 0 )
+ {
+ long nTmp = pCMS->aRealHeight.X() + pOrig->Top();
+ if( nTmp >= nMax )
+ {
+ pCMS->aRealHeight.X() = nMax - pOrig->Top();
+ pCMS->aRealHeight.Y() = 0;
+ }
+ else if( nTmp + pCMS->aRealHeight.Y() > nMax )
+ pCMS->aRealHeight.Y() = nMax - nTmp;
+ }
+ }
+ long nOut = pOrig->Right() - GetTxtFrm()->Frm().Right();
+ if( nOut > 0 )
+ {
+ if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left()
+ + GetTxtFrm()->Prt().Width() )
+ nOut += GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left()
+ - GetTxtFrm()->Prt().Width();
+ if( nOut > 0 )
+ pOrig->Pos().X() -= nOut + 10;
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtCursor::GetCrsrOfst()
+ *
+ * Return: Offset im String
+ *************************************************************************/
+xub_StrLen SwTxtCursor::GetCrsrOfst( SwPosition *pPos, const Point &rPoint,
+ const MSHORT nChgNode, SwCrsrMoveState* pCMS ) const
+{
+ // Adjustierung ggf. nachholen
+ GetAdjusted();
+
+ const XubString &rText = GetInfo().GetTxt();
+ xub_StrLen nOffset = 0;
+
+ // x ist der horizontale Offset innerhalb der Zeile.
+ SwTwips x = rPoint.X();
+ CONST SwTwips nLeftMargin = GetLineStart();
+ SwTwips nRightMargin = GetLineEnd();
+ if( nRightMargin == nLeftMargin )
+ nRightMargin += 30;
+
+ const sal_Bool bLeftOver = x < nLeftMargin;
+ if( bLeftOver )
+ x = nLeftMargin;
+ const sal_Bool bRightOver = x > nRightMargin;
+ if( bRightOver )
+ x = nRightMargin;
+
+ sal_Bool bRightAllowed = pCMS && ( pCMS->eState == MV_NONE );
+
+ // Bis hierher in Dokumentkoordinaten.
+ x -= nLeftMargin;
+
+ KSHORT nX = KSHORT( x );
+
+ // Wenn es in der Zeile Attributwechsel gibt, den Abschnitt
+ // suchen, in dem nX liegt.
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+ xub_StrLen nCurrStart = nStart;
+ sal_Bool bHolePortion = sal_False;
+ sal_Bool bLastHyph = sal_False;
+
+ SvUShorts *pKanaComp = pCurr->GetpKanaComp();
+ xub_StrLen nOldIdx = GetInfo().GetIdx();
+ MSHORT nSpaceIdx = 0;
+ MSHORT nKanaIdx = 0;
+ long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
+ short nKanaComp = pKanaComp ? (*pKanaComp)[0] : 0;
+
+ // nWidth ist die Breite der Zeile, oder die Breite des
+ // Abschnitts mit dem Fontwechsel, in dem nX liegt.
+
+ KSHORT nWidth = pPor->Width();
+ if ( pCurr->IsSpaceAdd() || pKanaComp )
+ {
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ {
+ ((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart );
+ nWidth = nWidth + USHORT( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) );
+ }
+ if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) ||
+ ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
+ )
+ {
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if( pKanaComp )
+ {
+ if ( nKanaIdx + 1 < pKanaComp->Count() )
+ nKanaComp = (*pKanaComp)[++nKanaIdx];
+ else
+ nKanaComp = 0;
+ }
+ }
+ }
+
+ KSHORT nWidth30;
+ if ( pPor->IsPostItsPortion() )
+ nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
+ else
+ nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
+ 30 :
+ nWidth;
+
+ while( pPor->GetPortion() && nWidth30 < nX && !pPor->IsBreakPortion() )
+ {
+ nX = nX - nWidth;
+ nCurrStart = nCurrStart + pPor->GetLen();
+ bHolePortion = pPor->IsHolePortion();
+ pPor = pPor->GetPortion();
+ nWidth = pPor->Width();
+ if ( pCurr->IsSpaceAdd() || pKanaComp )
+ {
+ if ( pPor->InSpaceGrp() && nSpaceAdd )
+ {
+ ((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart );
+ nWidth = nWidth + USHORT( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) );
+ }
+
+ if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) ||
+ ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
+ )
+ {
+ if ( pCurr->IsSpaceAdd() )
+ {
+ if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
+ nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
+ else
+ nSpaceAdd = 0;
+ }
+
+ if ( pKanaComp )
+ {
+ if( nKanaIdx + 1 < pKanaComp->Count() )
+ nKanaComp = (*pKanaComp)[++nKanaIdx];
+ else
+ nKanaComp = 0;
+ }
+ }
+ }
+
+ if ( pPor->IsPostItsPortion() )
+ nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
+ else
+ nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
+ 30 :
+ nWidth;
+ if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
+ bLastHyph = pPor->InHyphGrp();
+ }
+
+ const sal_Bool bLastPortion = (0 == pPor->GetPortion());
+
+ if( nX==nWidth )
+ {
+ SwLinePortion *pNextPor = pPor->GetPortion();
+ while( pNextPor && pNextPor->InFldGrp() && !pNextPor->Width() )
+ {
+ nCurrStart = nCurrStart + pPor->GetLen();
+ pPor = pNextPor;
+ if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
+ bLastHyph = pPor->InHyphGrp();
+ pNextPor = pPor->GetPortion();
+ }
+ }
+
+ ((SwTxtSizeInfo&)GetInfo()).SetIdx( nOldIdx );
+
+ xub_StrLen nLength = pPor->GetLen();
+
+ sal_Bool bFieldInfo = pCMS && pCMS->bFieldInfo;
+
+ if( bFieldInfo && ( nWidth30 < nX || bRightOver || bLeftOver ||
+ ( pPor->InNumberGrp() && !pPor->IsFtnNumPortion() ) ||
+ ( pPor->IsMarginPortion() && nWidth > nX + 30 ) ) )
+ ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
+
+
+ // #i27615#
+ if (pCMS)
+ {
+ if( pCMS->bInFrontOfLabel)
+ {
+ if (! (2 * nX < nWidth && pPor->InNumberGrp() &&
+ !pPor->IsFtnNumPortion()))
+ pCMS->bInFrontOfLabel = sal_False;
+ }
+ }
+
+ // 7684: Wir sind genau auf der HyphPortion angelangt und muessen dafuer
+ // sorgen, dass wir in dem String landen.
+ // 7993: Wenn die Laenge 0 ist muessen wir raus...
+ if( !nLength )
+ {
+ if( pCMS )
+ {
+ if( pPor->IsFlyPortion() && bFieldInfo )
+ ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
+
+ if (!bRightOver && nX)
+ {
+ if( pPor->IsFtnNumPortion())
+ ((SwCrsrMoveState*)pCMS)->bFtnNoInfo = sal_True;
+ else if (pPor->InNumberGrp() ) // #i23726#
+ {
+ ((SwCrsrMoveState*)pCMS)->nInNumPostionOffset = nX;
+ ((SwCrsrMoveState*)pCMS)->bInNumPortion = sal_True;
+ }
+ }
+ }
+ if( !nCurrStart )
+ return 0;
+
+ // 7849, 7816: auf pPor->GetHyphPortion kann nicht verzichtet werden!
+ if( bHolePortion || ( !bRightAllowed && bLastHyph ) ||
+ ( pPor->IsMarginPortion() && !pPor->GetPortion() &&
+ // 46598: In der letzten Zeile eines zentrierten Absatzes wollen
+ // wir auch mal hinter dem letzten Zeichen landen.
+ nCurrStart < rText.Len() ) )
+ --nCurrStart;
+ else if( pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()
+ && nWidth > nX )
+ {
+ if( bFieldInfo )
+ --nCurrStart;
+ else
+ {
+ KSHORT nHeight = pPor->Height();
+ if ( !nHeight || nHeight > nWidth )
+ nHeight = nWidth;
+ if( nChgNode && nWidth - nHeight/2 > nX )
+ --nCurrStart;
+ }
+ }
+ return nCurrStart;
+ }
+ if ( 1 == nLength )
+ {
+ if ( nWidth )
+ {
+ // Sonst kommen wir nicht mehr in zeichengeb. Rahmen hinein...
+ if( !( nChgNode && pPos && pPor->IsFlyCntPortion() ) )
+ {
+ if ( pPor->InFldGrp() ||
+ ( pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->IsBidi() ) )
+ {
+ KSHORT nHeight = 0;
+ if( !bFieldInfo )
+ {
+ nHeight = pPor->Height();
+ if ( !nHeight || nHeight > nWidth )
+ nHeight = nWidth;
+ }
+
+ if( nWidth - nHeight/2 <= nX &&
+ ( ! pPor->InFldGrp() ||
+ !((SwFldPortion*)pPor)->HasFollow() ) )
+ ++nCurrStart;
+ }
+ else if ( ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
+ !pPor->GetPortion()->IsMarginPortion() &&
+ !pPor->GetPortion()->IsHolePortion() ) )
+ && ( nWidth/2 < nX ) &&
+ ( !bFieldInfo ||
+ ( pPor->GetPortion() &&
+ pPor->GetPortion()->IsPostItsPortion() ) )
+ && ( bRightAllowed || !bLastHyph ))
+ ++nCurrStart;
+
+ // if we want to get the position inside the field, we should not return
+ if ( !pCMS || !pCMS->pSpecialPos )
+ return nCurrStart;
+ }
+ }
+ else
+ {
+ if ( pPor->IsPostItsPortion() || pPor->IsBreakPortion() ||
+ pPor->InToxRefGrp() )
+ return nCurrStart;
+ if ( pPor->InFldGrp() )
+ {
+ if( bRightOver && !((SwFldPortion*)pPor)->HasFollow() )
+ ++nCurrStart;
+ return nCurrStart;
+ }
+ }
+ }
+
+ if( bLastPortion && (pCurr->GetNext() || pFrm->GetFollow() ) )
+ --nLength;
+
+ if( nWidth > nX ||
+ ( nWidth == nX && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsDouble() ) )
+ {
+ if( pPor->IsMultiPortion() )
+ {
+ // In a multi-portion we use GetCrsrOfst()-function recursively
+ SwTwips nTmpY = rPoint.Y() - pCurr->GetAscent() + pPor->GetAscent();
+ // if we are in the first line of a double line portion, we have
+ // to add a value to nTmpY for not staying in this line
+ // we also want to skip the first line, if we are inside ruby
+ if ( ( ((SwTxtSizeInfo*)pInf)->IsMulti() &&
+ ((SwTxtSizeInfo*)pInf)->IsFirstMulti() ) ||
+ ( ((SwMultiPortion*)pPor)->IsRuby() &&
+ ((SwMultiPortion*)pPor)->OnTop() ) )
+ nTmpY += ((SwMultiPortion*)pPor)->Height();
+
+ // Important for cursor traveling in ruby portions:
+ // We have to set nTmpY to 0 in order to stay in the first row
+ // if the phonetic line is the second row
+ if ( ((SwMultiPortion*)pPor)->IsRuby() &&
+ ! ((SwMultiPortion*)pPor)->OnTop() )
+ nTmpY = 0;
+
+ SwTxtCursorSave aSave( (SwTxtCursor*)this, (SwMultiPortion*)pPor,
+ nTmpY, nX, nCurrStart, nSpaceAdd );
+
+ SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
+ if ( ((SwMultiPortion*)pPor)->IsBidi() )
+ {
+ const BYTE nBidiLevel = ((SwBidiPortion*)pPor)->GetLevel();
+ aLayoutModeModifier.Modify( nBidiLevel % 2 );
+ }
+
+ if( ((SwMultiPortion*)pPor)->HasRotation() )
+ {
+ nTmpY -= nY;
+ if( !((SwMultiPortion*)pPor)->IsRevers() )
+ nTmpY = pPor->Height() - nTmpY;
+ if( nTmpY < 0 )
+ nTmpY = 0;
+ nX = (KSHORT)nTmpY;
+ }
+
+ if( ((SwMultiPortion*)pPor)->HasBrackets() )
+ {
+ USHORT nPreWidth = ((SwDoubleLinePortion*)pPor)->PreWidth();
+ if ( nX > nPreWidth )
+ nX = nX - nPreWidth;
+ else
+ nX = 0;
+ }
+
+ return GetCrsrOfst( pPos, Point( GetLineStart() + nX, rPoint.Y() ),
+ nChgNode, pCMS );
+ }
+ if( pPor->InTxtGrp() )
+ {
+ BYTE nOldProp;
+ if( GetPropFont() )
+ {
+ ((SwFont*)GetFnt())->SetProportion( GetPropFont() );
+ nOldProp = GetFnt()->GetPropr();
+ }
+ else
+ nOldProp = 0;
+ {
+ SwTxtSizeInfo aSizeInf( GetInfo(), rText, nCurrStart );
+ ((SwTxtCursor*)this)->SeekAndChg( aSizeInf );
+ SwTxtSlot aDiffTxt( &aSizeInf, ((SwTxtPortion*)pPor), false, false );
+ SwFontSave aSave( aSizeInf, pPor->IsDropPortion() ?
+ ((SwDropPortion*)pPor)->GetFnt() : NULL );
+
+ SwParaPortion* pPara = (SwParaPortion*)GetInfo().GetParaPortion();
+ ASSERT( pPara, "No paragraph!" );
+
+ SwDrawTextInfo aDrawInf( aSizeInf.GetVsh(),
+ *aSizeInf.GetOut(),
+ &pPara->GetScriptInfo(),
+ aSizeInf.GetTxt(),
+ aSizeInf.GetIdx(),
+ pPor->GetLen() );
+ aDrawInf.SetOfst( nX );
+
+ if ( nSpaceAdd )
+ {
+ xub_StrLen nCharCnt;
+ // --> FME 2005-04-04 #i41860# Thai justified alignemt needs some
+ // additional information:
+ aDrawInf.SetNumberOfBlanks( pPor->InTxtGrp() ?
+ static_cast<const SwTxtPortion*>(pPor)->GetSpaceCnt( aSizeInf, nCharCnt ) :
+ 0 );
+ // <--
+ }
+
+ if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
+ aDrawInf.SetLen( STRING_LEN ); // SMARTTAGS
+
+ aDrawInf.SetSpace( nSpaceAdd );
+ aDrawInf.SetFont( aSizeInf.GetFont() );
+ aDrawInf.SetFrm( pFrm );
+ aDrawInf.SetSnapToGrid( aSizeInf.SnapToGrid() );
+ aDrawInf.SetPosMatchesBounds( pCMS && pCMS->bPosMatchesBounds );
+
+ if ( SW_CJK == aSizeInf.GetFont()->GetActual() &&
+ pPara->GetScriptInfo().CountCompChg() &&
+ ! pPor->InFldGrp() )
+ aDrawInf.SetKanaComp( nKanaComp );
+
+ nLength = aSizeInf.GetFont()->_GetCrsrOfst( aDrawInf );
+
+ // get position inside field portion?
+ if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
+ {
+ pCMS->pSpecialPos->nCharOfst = nLength;
+ nLength = 0; // SMARTTAGS
+ }
+
+ // set cursor bidi level
+ if ( pCMS )
+ ((SwCrsrMoveState*)pCMS)->nCursorBidiLevel =
+ aDrawInf.GetCursorBidiLevel();
+
+ if( bFieldInfo && nLength == pPor->GetLen() &&
+ ( ! pPor->GetPortion() ||
+ ! pPor->GetPortion()->IsPostItsPortion() ) )
+ --nLength;
+ }
+ if( nOldProp )
+ ((SwFont*)GetFnt())->SetProportion( nOldProp );
+ }
+ else
+ {
+ if( nChgNode && pPos && pPor->IsFlyCntPortion()
+ && !( (SwFlyCntPortion*)pPor )->IsDraw() )
+ {
+ // JP 24.11.94: liegt die Pos nicht im Fly, dann
+ // darf nicht mit STRING_LEN returnt werden!
+ // (BugId: 9692 + Aenderung in feshview)
+ SwFlyInCntFrm *pTmp = ( (SwFlyCntPortion*)pPor )->GetFlyFrm();
+ sal_Bool bChgNode = 1 < nChgNode;
+ if( !bChgNode )
+ {
+ SwFrm* pLower = pTmp->GetLower();
+ if( pLower && (pLower->IsTxtFrm() || pLower->IsLayoutFrm()) )
+ bChgNode = sal_True;
+ }
+ Point aTmpPoint( rPoint );
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( aTmpPoint );
+
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchHorizontalToVertical( aTmpPoint );
+
+ if( bChgNode && pTmp->Frm().IsInside( aTmpPoint ) &&
+ !( pTmp->IsProtected() ) )
+ {
+ nLength = ((SwFlyCntPortion*)pPor)->
+ GetFlyCrsrOfst( nX, aTmpPoint, pPos, pCMS );
+ // Sobald der Frame gewechselt wird, muessen wir aufpassen, dass
+ // unser Font wieder im OutputDevice steht.
+ // vgl. Paint und new SwFlyCntPortion !
+ ((SwTxtSizeInfo*)pInf)->SelectFont();
+
+ // 6776: Das pIter->GetCrsrOfst returnt
+ // aus einer Verschachtelung mit STRING_LEN.
+ return STRING_LEN;
+ }
+ }
+ else
+ nLength = pPor->GetCrsrOfst( nX );
+ }
+ }
+ nOffset = nCurrStart + nLength;
+
+ // 7684: Wir sind vor der HyphPortion angelangt und muessen dafuer
+ // sorgen, dass wir in dem String landen.
+ // Bei Zeilenenden vor FlyFrms muessen ebenso behandelt werden.
+
+ if( nOffset && pPor->GetLen() == nLength && pPor->GetPortion() &&
+ !pPor->GetPortion()->GetLen() && pPor->GetPortion()->InHyphGrp() )
+ --nOffset;
+
+ return nOffset;
+}
+
+/** Looks for text portions which are inside the given rectangle
+
+ For a rectangular text selection every text portions which is inside the given
+ rectangle has to be put into the SwSelectionList as SwPaM
+ From these SwPaM the SwCursors will be created.
+
+ @param rSelList
+ The container for the overlapped text portions
+
+ @param rRect
+ A rectangle in document coordinates, text inside this rectangle has to be
+ selected.
+
+ @return [ true, false ]
+ true if any overlapping text portion has been found and put into list
+ false if no portion overlaps, the list has been unchanged
+*/
+bool SwTxtFrm::FillSelection( SwSelectionList& rSelList, const SwRect& rRect ) const
+{
+ bool bRet = false;
+ // PaintArea() instead Frm() for negative indents
+ SwRect aTmpFrm( PaintArea() );
+ if( !rRect.IsOver( aTmpFrm ) )
+ return false;
+ if( rSelList.checkContext( this ) )
+ {
+ SwRect aRect( aTmpFrm );
+ aRect.Intersection( rRect );
+ // rNode without const to create SwPaMs
+ SwCntntNode &rNode = const_cast<SwCntntNode&>( *GetNode() );
+ SwNodeIndex aIdx( rNode );
+ SwPosition aPosL( aIdx, SwIndex( &rNode, 0 ) );
+ if( IsEmpty() )
+ {
+ SwPaM *pPam = new SwPaM( aPosL, aPosL );
+ rSelList.insertPaM( pPam );
+ }
+ else if( aRect.HasArea() )
+ {
+ xub_StrLen nOld = STRING_LEN;
+ SwPosition aPosR( aPosL );
+ Point aPoint;
+ SwTxtInfo aInf( const_cast<SwTxtFrm*>(this) );
+ SwTxtIter aLine( const_cast<SwTxtFrm*>(this), &aInf );
+ // We have to care for top-to-bottom layout, where right becomes top etc.
+ SWRECTFN( this )
+ SwTwips nTop = (aRect.*fnRect->fnGetTop)();
+ SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
+ SwTwips nLeft = (aRect.*fnRect->fnGetLeft)();
+ SwTwips nRight = (aRect.*fnRect->fnGetRight)();
+ SwTwips nY = aLine.Y(); // Top position of the first line
+ SwTwips nLastY = nY;
+ while( nY < nTop && aLine.Next() ) // line above rectangle
+ {
+ nLastY = nY;
+ nY = aLine.Y();
+ }
+ bool bLastLine = false;
+ if( nY < nTop && !aLine.GetNext() )
+ {
+ bLastLine = true;
+ nY += aLine.GetLineHeight();
+ }
+ do // check the lines for overlapping
+ {
+ if( nLastY < nTop ) // if the last line was above rectangle
+ nLastY = nTop;
+ if( nY > nBottom ) // if the current line leaves the rectangle
+ nY = nBottom;
+ if( nY >= nLastY ) // gotcha: overlapping
+ {
+ nLastY += nY;
+ nLastY /= 2;
+ if( bVert )
+ {
+ aPoint.X() = nLastY;
+ aPoint.Y() = nLeft;
+ }
+ else
+ {
+ aPoint.X() = nLeft;
+ aPoint.Y() = nLastY;
+ }
+ // Looking for the position of the left border of the rectangle
+ // in this text line
+ SwCrsrMoveState aState( MV_UPDOWN );
+ if( GetCrsrOfst( &aPosL, aPoint, &aState ) )
+ {
+ if( bVert )
+ {
+ aPoint.X() = nLastY;
+ aPoint.Y() = nRight;
+ }
+ else
+ {
+ aPoint.X() = nRight;
+ aPoint.Y() = nLastY;
+ }
+ // If we get a right position and if the left position
+ // is not the same like the left position of the line before
+ // which cound happen e.g. for field portions or fly frames
+ // a SwPaM will be inserted with these positions
+ if( GetCrsrOfst( &aPosR, aPoint, &aState ) &&
+ nOld != aPosL.nContent.GetIndex() )
+ {
+ SwPaM *pPam = new SwPaM( aPosL, aPosR );
+ rSelList.insertPaM( pPam );
+ nOld = aPosL.nContent.GetIndex();
+ }
+ }
+ }
+ if( aLine.Next() )
+ {
+ nLastY = nY;
+ nY = aLine.Y();
+ }
+ else if( !bLastLine )
+ {
+ bLastLine = true;
+ nLastY = nY;
+ nY += aLine.GetLineHeight();
+ }
+ else
+ break;
+ }while( nLastY < nBottom );
+ }
+ }
+ if( GetDrawObjs() )
+ {
+ const SwSortedObjs &rObjs = *GetDrawObjs();
+ for ( USHORT i = 0; i < rObjs.Count(); ++i )
+ {
+ const SwAnchoredObject* pAnchoredObj = rObjs[i];
+ if( !pAnchoredObj->ISA(SwFlyFrm) )
+ continue;
+ const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
+ if( pFly->IsFlyInCntFrm() && pFly->FillSelection( rSelList, rRect ) )
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
new file mode 100644
index 000000000000..c7527b372554
--- /dev/null
+++ b/sw/source/core/text/itrform2.cxx
@@ -0,0 +1,2127 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <editeng/lspcitem.hxx>
+#include <txtftn.hxx>
+#include <fmtftn.hxx>
+#include <ftninfo.hxx>
+#include <charfmt.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <layfrm.hxx> // GetFrmRstHeight, etc
+#include <viewsh.hxx>
+#include <viewopt.hxx> // SwViewOptions
+#include <paratr.hxx> // SwFmtDrop
+#include <txtcfg.hxx>
+#include <itrform2.hxx>
+#include <porrst.hxx>
+#include <portab.hxx> // pLastTab->
+#include <porfly.hxx> // CalcFlyWidth
+#include <portox.hxx> // WhichTxtPortion
+#include <porref.hxx> // WhichTxtPortion
+#include <porfld.hxx> // SwNumberPortion fuer CalcAscent()
+#include <porftn.hxx> // SwFtnPortion
+#include <porhyph.hxx>
+#include <guess.hxx>
+#include <blink.hxx> // pBlink
+#include <ftnfrm.hxx> // WhichFirstPortion() -> mal Verlagern.
+#include <redlnitr.hxx> // SwRedlineItr
+#include <pagefrm.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <doc.hxx> // SwDoc
+#include <pormulti.hxx> // SwMultiPortion
+#define _SVSTDARR_LONGS
+#include <svl/svstdarr.hxx>
+#include <unotools/charclass.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <ndtxt.hxx> // pSwpHints, Ausgabeoperator
+#endif
+
+using namespace ::com::sun::star;
+
+extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
+bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos );
+
+#define MAX_TXTPORLEN 300
+
+inline void ClearFly( SwTxtFormatInfo &rInf )
+{
+ if( rInf.GetFly() )
+ {
+ delete rInf.GetFly();
+ rInf.SetFly(0);
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CtorInitTxtFormatter()
+ *************************************************************************/
+
+void SwTxtFormatter::CtorInitTxtFormatter( SwTxtFrm *pNewFrm, SwTxtFormatInfo *pNewInf )
+{
+ CtorInitTxtPainter( pNewFrm, pNewInf );
+ pInf = pNewInf;
+ pDropFmt = GetInfo().GetDropFmt();
+ pMulti = NULL;
+
+ bOnceMore = sal_False;
+ bFlyInCntBase = sal_False;
+ bChanges = sal_False;
+ bTruncLines = sal_False;
+ nCntEndHyph = 0;
+ nCntMidHyph = 0;
+ nLeftScanIdx = STRING_LEN;
+ nRightScanIdx = 0;
+ m_nHintEndIndex = 0;
+
+ if( nStart > GetInfo().GetTxt().Len() )
+ {
+ ASSERT( !this, "+SwTxtFormatter::CTOR: bad offset" );
+ nStart = GetInfo().GetTxt().Len();
+ }
+
+}
+
+/*************************************************************************
+ * SwTxtFormatter::DTOR
+ *************************************************************************/
+
+SwTxtFormatter::~SwTxtFormatter()
+{
+ // Auesserst unwahrscheinlich aber denkbar.
+ // z.B.: Feld spaltet sich auf, Widows schlagen zu
+ if( GetInfo().GetRest() )
+ {
+ delete GetInfo().GetRest();
+ GetInfo().SetRest(0);
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::Insert()
+ *************************************************************************/
+
+void SwTxtFormatter::Insert( SwLineLayout *pLay )
+{
+ // Einfuegen heute mal ausnahmsweise hinter dem aktuellen Element.
+ if ( pCurr )
+ {
+ pLay->SetNext( pCurr->GetNext() );
+ pCurr->SetNext( pLay );
+ }
+ else
+ pCurr = pLay;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::GetFrmRstHeight()
+ *************************************************************************/
+
+KSHORT SwTxtFormatter::GetFrmRstHeight() const
+{
+ // 8725: Uns interessiert die Resthoehe bezogen auf die Seite.
+ // Wenn wir in einer Tabelle stehen, dann ist pFrm->GetUpper() nicht
+ // die Seite. GetFrmRstHeight() wird im Zusammenhang mit den Ftn
+ // gerufen.
+ // Falsch: const SwFrm *pUpper = pFrm->GetUpper();
+ const SwFrm *pPage = (const SwFrm*)pFrm->FindPageFrm();
+ const SwTwips nHeight = pPage->Frm().Top()
+ + pPage->Prt().Top()
+ + pPage->Prt().Height() - Y();
+ if( 0 > nHeight )
+ return pCurr->Height();
+ else
+ return KSHORT( nHeight );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::UnderFlow()
+ *************************************************************************/
+
+SwLinePortion *SwTxtFormatter::UnderFlow( SwTxtFormatInfo &rInf )
+{
+ // Werte sichern und rInf initialisieren.
+ SwLinePortion *pUnderFlow = rInf.GetUnderFlow();
+ if( !pUnderFlow )
+ return 0;
+
+ // Wir formatieren rueckwaerts, d.h. dass Attributwechsel in der
+ // naechsten Zeile durchaus noch einmal drankommen koennen.
+ // Zu beobachten in 8081.sdw, wenn man in der ersten Zeile Text eingibt.
+
+ const xub_StrLen nSoftHyphPos = rInf.GetSoftHyphPos();
+ const xub_StrLen nUnderScorePos = rInf.GetUnderScorePos();
+
+ // 8358, 8359: Flys sichern und auf 0 setzen, sonst GPF
+ // 3983: Nicht ClearFly(rInf) !
+ SwFlyPortion *pFly = rInf.GetFly();
+ rInf.SetFly( 0 );
+
+ FeedInf( rInf );
+ rInf.SetLast( pCurr );
+ // pUnderFlow braucht nicht deletet werden, weil es im folgenden
+ // Truncate() untergehen wird.
+ rInf.SetUnderFlow(0);
+ rInf.SetSoftHyphPos( nSoftHyphPos );
+ rInf.SetUnderScorePos( nUnderScorePos );
+ rInf.SetPaintOfst( GetLeftMargin() );
+
+ // Wir suchen die Portion mit der Unterlaufposition
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+ if( pPor != pUnderFlow )
+ {
+ // pPrev wird die letzte Portion vor pUnderFlow,
+ // die noch eine echte Breite hat.
+ // Ausnahme: SoftHyphPortions duerfen dabei natuerlich
+ // nicht vergessen werden, obwohl sie keine Breite haben.
+ SwLinePortion *pTmpPrev = pPor;
+ while( pPor && pPor != pUnderFlow )
+ {
+ DBG_LOOP;
+ if( !pPor->IsKernPortion() &&
+ ( pPor->Width() || pPor->IsSoftHyphPortion() ) )
+ {
+ while( pTmpPrev != pPor )
+ {
+ pTmpPrev->Move( rInf );
+ rInf.SetLast( pTmpPrev );
+ pTmpPrev = pTmpPrev->GetPortion();
+ ASSERT( pTmpPrev, "UnderFlow: Loosing control!" );
+ };
+ }
+ pPor = pPor->GetPortion();
+ }
+ pPor = pTmpPrev;
+ if( pPor && // Flies + Initialen werden nicht beim UnderFlow mitgenommen
+ ( pPor->IsFlyPortion() || pPor->IsDropPortion() ||
+ pPor->IsFlyCntPortion() ) )
+ {
+ pPor->Move( rInf );
+ rInf.SetLast( pPor );
+ rInf.SetStopUnderFlow( sal_True );
+ pPor = pUnderFlow;
+ }
+ }
+
+ // Was? Die Unterlaufsituation ist nicht in der Portion-Kette ?
+ ASSERT( pPor, "SwTxtFormatter::UnderFlow: overflow but underflow" );
+
+ // OD 2004-05-26 #i29529# - correction: no delete of footnotes
+// if( rInf.IsFtnInside() && pPor && !rInf.IsQuick() )
+// {
+// SwLinePortion *pTmp = pPor->GetPortion();
+// while( pTmp )
+// {
+// if( pTmp->IsFtnPortion() )
+// ((SwFtnPortion*)pTmp)->ClearFtn();
+// pTmp = pTmp->GetPortion();
+// }
+// }
+
+ /*-----------------14.12.94 09:45-------------------
+ * 9849: Schnellschuss
+ * --------------------------------------------------*/
+ if ( pPor==rInf.GetLast() )
+ {
+ // Hier landen wir, wenn die UnderFlow-ausloesende Portion sich
+ // ueber die ganze Zeile erstreckt, z. B. wenn ein Wort ueber
+ // mehrere Zeilen geht und in der zweiten Zeile in einen Fly
+ // hineinlaeuft!
+ rInf.SetFly( pFly ); // wg. 28300
+ pPor->Truncate();
+ return pPor; // Reicht das?
+ }
+ /*---------------------------------------------------
+ * Ende des Schnellschusses wg. 9849
+ * --------------------------------------------------*/
+
+ // 4656: X + Width == 0 bei SoftHyph > Zeile ?!
+ if( !pPor || !(rInf.X() + pPor->Width()) )
+ {
+ delete pFly;
+ return 0;
+ }
+
+ // Vorbereitungen auf's Format()
+ // Wir muessen die Kette hinter pLast abknipsen, weil
+ // nach dem Format() ein Insert erfolgt.
+ SeekAndChg( rInf );
+
+ // line width is adjusted, so that pPor does not fit to current
+ // line anymore
+ rInf.Width( (USHORT)(rInf.X() + (pPor->Width() ? pPor->Width() - 1 : 0)) );
+ rInf.SetLen( pPor->GetLen() );
+ rInf.SetFull( sal_False );
+ if( pFly )
+ {
+ // Aus folgendem Grund muss die FlyPortion neu berechnet werden:
+ // Wenn durch einen grossen Font in der Mitte der Zeile die Grundlinie
+ // abgesenkt wird und dadurch eine Ueberlappung mit eine Fly entsteht,
+ // so hat die FlyPortion eine falsche Groesse/Fixsize.
+ rInf.SetFly( pFly );
+ CalcFlyWidth( rInf );
+ }
+ rInf.GetLast()->SetPortion(0);
+
+ // Eine Ausnahme bildet das SwLineLayout, dass sich beim
+ // ersten Portionwechsel aufspaltet. Hier nun der umgekehrte Weg:
+ if( rInf.GetLast() == pCurr )
+ {
+ if( pPor->InTxtGrp() && !pPor->InExpGrp() )
+ {
+ MSHORT nOldWhich = pCurr->GetWhichPor();
+ *(SwLinePortion*)pCurr = *pPor;
+ pCurr->SetPortion( pPor->GetPortion() );
+ pCurr->SetWhichPor( nOldWhich );
+ pPor->SetPortion( 0 );
+ delete pPor;
+ pPor = pCurr;
+ }
+ }
+ pPor->Truncate();
+ SwLinePortion *const pRest( rInf.GetRest() );
+ if (pRest && pRest->InFldGrp() &&
+ static_cast<SwFldPortion*>(pRest)->IsNoLength())
+ {
+ // HACK: decrement again, so we pick up the suffix in next line!
+ --m_nHintEndIndex;
+ }
+ delete pRest;
+ rInf.SetRest(0);
+ return pPor;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::InsertPortion()
+ *************************************************************************/
+
+void SwTxtFormatter::InsertPortion( SwTxtFormatInfo &rInf,
+ SwLinePortion *pPor ) const
+{
+ // Die neue Portion wird eingefuegt,
+ // bei dem LineLayout ist allerdings alles anders...
+ if( pPor == pCurr )
+ {
+ if( pCurr->GetPortion() )
+ pPor = pCurr->GetPortion();
+ }
+ else
+ {
+ SwLinePortion *pLast = rInf.GetLast();
+ if( pLast->GetPortion() )
+ {
+ while( pLast->GetPortion() )
+ pLast = pLast->GetPortion();
+ rInf.SetLast( pLast );
+ }
+ pLast->Insert( pPor );
+
+ rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
+
+ // Maxima anpassen:
+ if( pCurr->Height() < pPor->Height() )
+ pCurr->Height( pPor->Height() );
+ if( pCurr->GetAscent() < pPor->GetAscent() )
+ pCurr->SetAscent( pPor->GetAscent() );
+ }
+
+ // manchmal werden ganze Ketten erzeugt (z.B. durch Hyphenate)
+ rInf.SetLast( pPor );
+ while( pPor )
+ {
+ DBG_LOOP;
+ pPor->Move( rInf );
+ rInf.SetLast( pPor );
+ pPor = pPor->GetPortion();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::BuildPortion()
+ *************************************************************************/
+
+void SwTxtFormatter::BuildPortions( SwTxtFormatInfo &rInf )
+{
+ ASSERT( rInf.GetTxt().Len() < STRING_LEN,
+ "SwTxtFormatter::BuildPortions: bad text length in info" );
+
+ rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
+
+ // Erst NewTxtPortion() entscheidet, ob pCurr in pPor landet.
+ // Wir muessen in jedem Fall dafuer sorgen, dass der Font eingestellt
+ // wird. In CalcAscent geschieht dies automatisch.
+ rInf.SetLast( pCurr );
+ rInf.ForcedLeftMargin( 0 );
+
+ ASSERT( pCurr->FindLastPortion() == pCurr, "pLast supposed to equal pCurr" );
+
+ if( !pCurr->GetAscent() && !pCurr->Height() )
+ CalcAscent( rInf, pCurr );
+
+ SeekAndChg( rInf );
+
+ // In CalcFlyWidth wird Width() verkuerzt, wenn eine FlyPortion vorliegt.
+ ASSERT( !rInf.X() || pMulti, "SwTxtFormatter::BuildPortion X=0?" );
+ CalcFlyWidth( rInf );
+ SwFlyPortion *pFly = rInf.GetFly();
+ if( pFly )
+ {
+ if ( 0 < pFly->Fix() )
+ ClearFly( rInf );
+ else
+ rInf.SetFull(sal_True);
+ }
+
+ SwLinePortion *pPor = NewPortion( rInf );
+
+ // Asian grid stuff
+ GETGRID( pFrm->FindPageFrm() )
+ const sal_Bool bHasGrid = pGrid && rInf.SnapToGrid() &&
+ GRID_LINES_CHARS == pGrid->GetGridType();
+
+ const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
+ const USHORT nGridWidth = bHasGrid ?
+ GETGRIDWIDTH(pGrid,pDoc) : 0; //for textgrid refactor
+
+ // used for grid mode only:
+ // the pointer is stored, because after formatting of non-asian text,
+ // the width of the kerning portion has to be adjusted
+ SwKernPortion* pGridKernPortion = 0;
+
+ sal_Bool bFull;
+ SwTwips nUnderLineStart = 0;
+ rInf.Y( Y() );
+
+ while( pPor && !rInf.IsStop() )
+ {
+ ASSERT( rInf.GetLen() < STRING_LEN &&
+ rInf.GetIdx() <= rInf.GetTxt().Len(),
+ "SwTxtFormatter::BuildPortions: bad length in info" );
+ DBG_LOOP;
+
+ // We have to check the script for fields in order to set the
+ // correct nActual value for the font.
+ if( pPor->InFldGrp() )
+ ((SwFldPortion*)pPor)->CheckScript( rInf );
+
+ if( ! bHasGrid && rInf.HasScriptSpace() &&
+ rInf.GetLast() && rInf.GetLast()->InTxtGrp() &&
+ rInf.GetLast()->Width() && !rInf.GetLast()->InNumberGrp() )
+ {
+ BYTE nNxtActual = rInf.GetFont()->GetActual();
+ BYTE nLstActual = nNxtActual;
+ USHORT nLstHeight = (USHORT)rInf.GetFont()->GetHeight();
+ sal_Bool bAllowBefore = sal_False;
+ sal_Bool bAllowBehind = sal_False;
+ const CharClass& rCC = GetAppCharClass();
+
+ // are there any punctuation characters on both sides
+ // of the kerning portion?
+ if ( pPor->InFldGrp() )
+ {
+ XubString aAltTxt;
+ if ( ((SwFldPortion*)pPor)->GetExpTxt( rInf, aAltTxt ) &&
+ aAltTxt.Len() )
+ {
+ bAllowBehind = rCC.isLetterNumeric( aAltTxt, 0 );
+
+ const SwFont* pTmpFnt = ((SwFldPortion*)pPor)->GetFont();
+ if ( pTmpFnt )
+ nNxtActual = pTmpFnt->GetActual();
+ }
+ }
+ else
+ bAllowBehind = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() );
+
+ const SwLinePortion* pLast = rInf.GetLast();
+ if ( bAllowBehind && pLast )
+ {
+ if ( pLast->InFldGrp() )
+ {
+ XubString aAltTxt;
+ if ( ((SwFldPortion*)pLast)->GetExpTxt( rInf, aAltTxt ) &&
+ aAltTxt.Len() )
+ {
+ bAllowBefore = rCC.isLetterNumeric( aAltTxt, aAltTxt.Len() - 1 );
+
+ const SwFont* pTmpFnt = ((SwFldPortion*)pLast)->GetFont();
+ if ( pTmpFnt )
+ {
+ nLstActual = pTmpFnt->GetActual();
+ nLstHeight = (USHORT)pTmpFnt->GetHeight();
+ }
+ }
+ }
+ else if ( rInf.GetIdx() )
+ {
+ bAllowBefore = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() - 1 );
+ // Note: ScriptType returns values in [1,4]
+ if ( bAllowBefore )
+ nLstActual = pScriptInfo->ScriptType( rInf.GetIdx() - 1 ) - 1;
+ }
+
+ nLstHeight /= 5;
+ // does the kerning portion still fit into the line?
+ if( bAllowBefore && ( nLstActual != nNxtActual ) &&
+ nLstHeight && rInf.X() + nLstHeight <= rInf.Width() )
+ {
+ SwKernPortion* pKrn =
+ new SwKernPortion( *rInf.GetLast(), nLstHeight,
+ pLast->InFldGrp() && pPor->InFldGrp() );
+ rInf.GetLast()->SetPortion( NULL );
+ InsertPortion( rInf, pKrn );
+ }
+ }
+ }
+ else if ( bHasGrid && ! pGridKernPortion && ! pMulti )
+ {
+ // insert a grid kerning portion
+ if ( ! pGridKernPortion )
+ pGridKernPortion = pPor->IsKernPortion() ?
+ (SwKernPortion*)pPor :
+ new SwKernPortion( *pCurr );
+
+ // if we have a new GridKernPortion, we initially calculate
+ // its size so that its ends on the grid
+ const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
+ const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
+ SWRECTFN( pPageFrm )
+
+ const long nGridOrigin = pBody ?
+ (pBody->*fnRect->fnGetPrtLeft)() :
+ (pPageFrm->*fnRect->fnGetPrtLeft)();
+
+ SwTwips nStartX = rInf.X() + GetLeftMargin();
+ if ( bVert )
+ {
+ Point aPoint( nStartX, 0 );
+ pFrm->SwitchHorizontalToVertical( aPoint );
+ nStartX = aPoint.Y();
+ }
+
+ const SwTwips nOfst = nStartX - nGridOrigin;
+ if ( nOfst )
+ {
+ const ULONG i = ( nOfst > 0 ) ?
+ ( ( nOfst - 1 ) / nGridWidth + 1 ) :
+ 0;
+ const SwTwips nKernWidth = i * nGridWidth - nOfst;
+ const SwTwips nRestWidth = rInf.Width() - rInf.X();
+
+ if ( nKernWidth <= nRestWidth )
+ pGridKernPortion->Width( (USHORT)nKernWidth );
+ }
+
+ if ( pGridKernPortion != pPor )
+ InsertPortion( rInf, pGridKernPortion );
+ }
+
+ // the multi-portion has it's own format function
+ if( pPor->IsMultiPortion() && ( !pMulti || pMulti->IsBidi() ) )
+ bFull = BuildMultiPortion( rInf, *((SwMultiPortion*)pPor) );
+ else
+ bFull = pPor->Format( rInf );
+
+ if( rInf.IsRuby() && !rInf.GetRest() )
+ bFull = sal_True;
+
+ // if we are underlined, we store the beginning of this underlined
+ // segment for repaint optimization
+ if ( UNDERLINE_NONE != pFnt->GetUnderline() && ! nUnderLineStart )
+ nUnderLineStart = GetLeftMargin() + rInf.X();
+
+ if ( pPor->IsFlyPortion() )
+ pCurr->SetFly( sal_True );
+ // some special cases, where we have to take care for the repaint
+ // offset:
+ // 1. Underlined portions due to special underline feature
+ // 2. Right Tab
+ // 3. BidiPortions
+ // 4. other Multiportions
+ // 5. DropCaps
+ // 6. Grid Mode
+ else if ( ( ! rInf.GetPaintOfst() || nUnderLineStart < rInf.GetPaintOfst() ) &&
+ // 1. Underlined portions
+ nUnderLineStart &&
+ // reformat is at end of an underlined portion and next portion
+ // is not underlined
+ ( ( rInf.GetReformatStart() == rInf.GetIdx() &&
+ UNDERLINE_NONE == pFnt->GetUnderline()
+ ) ||
+ // reformat is inside portion and portion is underlined
+ ( rInf.GetReformatStart() >= rInf.GetIdx() &&
+ rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() &&
+ UNDERLINE_NONE != pFnt->GetUnderline() ) ) )
+ rInf.SetPaintOfst( nUnderLineStart );
+ else if ( ! rInf.GetPaintOfst() &&
+ // 2. Right Tab
+ ( ( pPor->InTabGrp() && !pPor->IsTabLeftPortion() ) ||
+ // 3. BidiPortions
+ ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() ) ||
+ // 4. Multi Portion and 5. Drop Caps
+ ( ( pPor->IsDropPortion() || pPor->IsMultiPortion() ) &&
+ rInf.GetReformatStart() >= rInf.GetIdx() &&
+ rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() )
+ // 6. Grid Mode
+ || ( bHasGrid && SW_CJK != pFnt->GetActual() )
+ )
+ )
+ // we store the beginning of the critical portion as our
+ // paint offset
+ rInf.SetPaintOfst( GetLeftMargin() + rInf.X() );
+
+ // under one of these conditions we are allowed to delete the
+ // start of the underline portion
+ if ( IsUnderlineBreak( *pPor, *pFnt ) )
+ nUnderLineStart = 0;
+
+ if( pPor->IsFlyCntPortion() || ( pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->HasFlyInCntnt() ) )
+ SetFlyInCntBase();
+ // 5964: bUnderFlow muss zurueckgesetzt werden, sonst wird beim
+ // naechsten Softhyphen wieder umgebrochen!
+ if ( !bFull )
+ {
+ rInf.ClrUnderFlow();
+ if( ! bHasGrid && rInf.HasScriptSpace() && pPor->InTxtGrp() &&
+ pPor->GetLen() && !pPor->InFldGrp() )
+ {
+ // The distance between two different scripts is set
+ // to 20% of the fontheight.
+ xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
+ if( nTmp == pScriptInfo->NextScriptChg( nTmp - 1 ) &&
+ nTmp != rInf.GetTxt().Len() )
+ {
+ USHORT nDist = (USHORT)(rInf.GetFont()->GetHeight()/5);
+
+ if( nDist )
+ {
+ // we do not want a kerning portion if any end
+ // would be a punctuation character
+ const CharClass& rCC = GetAppCharClass();
+ if ( rCC.isLetterNumeric( rInf.GetTxt(), nTmp - 1 ) &&
+ rCC.isLetterNumeric( rInf.GetTxt(), nTmp ) )
+ {
+ // does the kerning portion still fit into the line?
+ if ( rInf.X() + pPor->Width() + nDist <= rInf.Width() )
+ new SwKernPortion( *pPor, nDist );
+ else
+ bFull = sal_True;
+ }
+ }
+ }
+ }
+ }
+
+ if ( bHasGrid && pPor != pGridKernPortion && ! pMulti )
+ {
+ xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
+ const SwTwips nRestWidth = rInf.Width() - rInf.X() - pPor->Width();
+
+ const BYTE nCurrScript = pFnt->GetActual(); // pScriptInfo->ScriptType( rInf.GetIdx() );
+ const BYTE nNextScript = nTmp >= rInf.GetTxt().Len() ?
+ SW_CJK :
+ SwScriptInfo::WhichFont( nTmp, 0, pScriptInfo );
+
+ // snap non-asian text to grid if next portion is ASIAN or
+ // there are no more portions in this line
+ // be careful when handling an underflow event: the gridkernportion
+ // could have been deleted
+ if ( nRestWidth > 0 && SW_CJK != nCurrScript &&
+ ! rInf.IsUnderFlow() && ( bFull || SW_CJK == nNextScript ) )
+ {
+ ASSERT( pGridKernPortion, "No GridKernPortion available" )
+
+ // calculate size
+ SwLinePortion* pTmpPor = pGridKernPortion->GetPortion();
+ USHORT nSumWidth = pPor->Width();
+ while ( pTmpPor )
+ {
+ nSumWidth = nSumWidth + pTmpPor->Width();
+ pTmpPor = pTmpPor->GetPortion();
+ }
+
+ const USHORT i = nSumWidth ?
+ ( nSumWidth - 1 ) / nGridWidth + 1 :
+ 0;
+ const SwTwips nTmpWidth = i * nGridWidth;
+ const SwTwips nKernWidth = Min( (SwTwips)(nTmpWidth - nSumWidth),
+ nRestWidth );
+ const USHORT nKernWidth_1 = (USHORT)(nKernWidth / 2);
+
+ ASSERT( nKernWidth <= nRestWidth,
+ "Not enough space left for adjusting non-asian text in grid mode" )
+
+ pGridKernPortion->Width( pGridKernPortion->Width() + nKernWidth_1 );
+ rInf.X( rInf.X() + nKernWidth_1 );
+
+ if ( ! bFull )
+ new SwKernPortion( *pPor, (short)(nKernWidth - nKernWidth_1),
+ sal_False, sal_True );
+
+ pGridKernPortion = 0;
+ }
+ else if ( pPor->IsMultiPortion() || pPor->InFixMargGrp() ||
+ pPor->IsFlyCntPortion() || pPor->InNumberGrp() ||
+ pPor->InFldGrp() || nCurrScript != nNextScript )
+ // next portion should snap to grid
+ pGridKernPortion = 0;
+ }
+
+ rInf.SetFull( bFull );
+
+ // Restportions von mehrzeiligen Feldern haben bisher noch
+ // nicht den richtigen Ascent.
+ if ( !pPor->GetLen() && !pPor->IsFlyPortion()
+ && !pPor->IsGrfNumPortion() && ! pPor->InNumberGrp()
+ && !pPor->IsMultiPortion() )
+ CalcAscent( rInf, pPor );
+
+ InsertPortion( rInf, pPor );
+ pPor = NewPortion( rInf );
+ }
+
+ if( !rInf.IsStop() )
+ {
+ // der letzte rechte, zentrierte, dezimale Tab
+ SwTabPortion *pLastTab = rInf.GetLastTab();
+ if( pLastTab )
+ pLastTab->FormatEOL( rInf );
+ else if( rInf.GetLast() && rInf.LastKernPortion() )
+ rInf.GetLast()->FormatEOL( rInf );
+ }
+ if( pCurr->GetPortion() && pCurr->GetPortion()->InNumberGrp()
+ && ((SwNumberPortion*)pCurr->GetPortion())->IsHide() )
+ rInf.SetNumDone( sal_False );
+
+ // 3260, 3860: Fly auf jeden Fall loeschen!
+ ClearFly( rInf );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcAdjustLine()
+ *************************************************************************/
+
+void SwTxtFormatter::CalcAdjustLine( SwLineLayout *pCurrent )
+{
+ if( SVX_ADJUST_LEFT != GetAdjust() && !pMulti)
+ {
+ pCurrent->SetFormatAdj(sal_True);
+ if( IsFlyInCntBase() )
+ {
+ CalcAdjLine( pCurrent );
+ // 23348: z.B. bei zentrierten Flys muessen wir den RefPoint
+ // auf jeden Fall umsetzen, deshalb bAllWays = sal_True
+ UpdatePos( pCurrent, GetTopLeft(), GetStart(), sal_True );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcAscent()
+ *************************************************************************/
+
+void SwTxtFormatter::CalcAscent( SwTxtFormatInfo &rInf, SwLinePortion *pPor )
+{
+ if ( pPor->InFldGrp() && ((SwFldPortion*)pPor)->GetFont() )
+ {
+ // Numerierungen + InterNetFlds koennen einen eigenen Font beinhalten,
+ // dann ist ihre Groesse unabhaengig von harten Attributierungen.
+ SwFont* pFldFnt = ((SwFldPortion*)pPor)->pFnt;
+ SwFontSave aSave( rInf, pFldFnt );
+ ((SwFldPortion*)pPor)->Height( pFldFnt->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
+ ((SwFldPortion*)pPor)->SetAscent( pFldFnt->GetAscent( rInf.GetVsh(), *rInf.GetOut() ) );
+ }
+ // --> OD 2008-06-05 #i89179#
+ // tab portion representing the list tab of a list label gets the
+ // same height and ascent as the corresponding number portion
+ else if ( pPor->InTabGrp() && pPor->GetLen() == 0 &&
+ rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
+ static_cast<const SwNumberPortion*>(rInf.GetLast())->HasFont() )
+ {
+ const SwLinePortion* pLast = rInf.GetLast();
+ pPor->Height( pLast->Height() );
+ pPor->SetAscent( pLast->GetAscent() );
+ }
+ // <--
+ else
+ {
+ const SwLinePortion *pLast = rInf.GetLast();
+ sal_Bool bChg;
+
+ // Fallunterscheidung: in leeren Zeilen werden die Attribute
+ // per SeekStart angeschaltet.
+ const sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
+ if ( pPor->IsQuoVadisPortion() )
+ bChg = SeekStartAndChg( rInf, sal_True );
+ else
+ {
+ if( bFirstPor )
+ {
+ if( rInf.GetTxt().Len() )
+ {
+ if ( pPor->GetLen() || !rInf.GetIdx()
+ || ( pCurr != pLast && !pLast->IsFlyPortion() )
+ || !pCurr->IsRest() ) // statt !rInf.GetRest()
+ bChg = SeekAndChg( rInf );
+ else
+ bChg = SeekAndChgBefore( rInf );
+ }
+ else if ( pMulti )
+ // do not open attributes starting at 0 in empty multi
+ // portions (rotated numbering followed by a footnote
+ // can cause trouble, because the footnote attribute
+ // starts at 0, but if we open it, the attribute handler
+ // cannot handle it.
+ bChg = sal_False;
+ else
+ bChg = SeekStartAndChg( rInf );
+ }
+ else
+ bChg = SeekAndChg( rInf );
+ }
+ if( bChg || bFirstPor || !pPor->GetAscent()
+ || !rInf.GetLast()->InTxtGrp() )
+ {
+ pPor->SetAscent( rInf.GetAscent() );
+ pPor->Height( rInf.GetTxtHeight() );
+ }
+ else
+ {
+ pPor->Height( pLast->Height() );
+ pPor->SetAscent( pLast->GetAscent() );
+ }
+ }
+}
+
+/*************************************************************************
+ * class SwMetaPortion
+ *************************************************************************/
+
+class SwMetaPortion : public SwTxtPortion
+{
+public:
+ inline SwMetaPortion() { SetWhichPor( POR_META ); }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+// OUTPUT_OPERATOR
+};
+
+//CLASSIO( SwMetaPortion )
+
+/*************************************************************************
+ * virtual SwMetaPortion::Paint()
+ *************************************************************************/
+
+void SwMetaPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if ( Width() )
+ {
+ rInf.DrawViewOpt( *this, POR_META );
+ SwTxtPortion::Paint( rInf );
+ }
+}
+
+
+/*************************************************************************
+ * SwTxtFormatter::WhichTxtPor()
+ *************************************************************************/
+
+SwTxtPortion *SwTxtFormatter::WhichTxtPor( SwTxtFormatInfo &rInf ) const
+{
+ SwTxtPortion *pPor = 0;
+ if( GetFnt()->IsTox() )
+ pPor = new SwToxPortion;
+ else
+ {
+ if( GetFnt()->IsRef() )
+ pPor = new SwRefPortion;
+ else if (GetFnt()->IsMeta())
+ {
+ pPor = new SwMetaPortion;
+ }
+ else
+ {
+ // Erst zum Schluss !
+ // Wenn pCurr keine Breite hat, kann sie trotzdem schon Inhalt haben,
+ // z.B. bei nicht darstellbaren Zeichen.
+ if( rInf.GetLen() > 0 )
+ {
+ if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDSTART )
+ pPor = new SwFieldMarkPortion();
+ else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDEND )
+ pPor = new SwFieldMarkPortion();
+ else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FORMELEMENT )
+ pPor = new SwFieldFormPortion();
+ }
+ if( !pPor )
+ {
+ if( !rInf.X() && !pCurr->GetPortion() && !pCurr->GetLen() && !GetFnt()->IsURL() )
+ pPor = pCurr;
+ else
+ {
+ pPor = new SwTxtPortion;
+ if( GetFnt()->IsURL() )
+ pPor->SetWhichPor( POR_URL );
+ }
+ }
+ }
+ }
+ return pPor;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewTxtPortion()
+ *************************************************************************/
+// Die Laenge wird ermittelt, folgende Portion-Grenzen sind definiert:
+// 1) Tabs
+// 2) Linebreaks
+// 3) CH_TXTATR_BREAKWORD / CH_TXTATR_INWORD
+// 4) naechster Attributwechsel
+
+SwTxtPortion *SwTxtFormatter::NewTxtPortion( SwTxtFormatInfo &rInf )
+{
+ // Wenn wir am Zeilenbeginn stehen, nehmen wir pCurr
+ // Wenn pCurr nicht von SwTxtPortion abgeleitet ist,
+ // muessen wir duplizieren ...
+ Seek( rInf.GetIdx() );
+ SwTxtPortion *pPor = WhichTxtPor( rInf );
+
+ // until next attribute change:
+ const xub_StrLen nNextAttr = GetNextAttr();
+ xub_StrLen nNextChg = Min( nNextAttr, rInf.GetTxt().Len() );
+
+ // end of script type:
+ const xub_StrLen nNextScript = pScriptInfo->NextScriptChg( rInf.GetIdx() );
+ nNextChg = Min( nNextChg, nNextScript );
+
+ // end of direction:
+ const xub_StrLen nNextDir = pScriptInfo->NextDirChg( rInf.GetIdx() );
+ nNextChg = Min( nNextChg, nNextDir );
+
+ // 7515, 7516, 3470, 6441 : Turbo-Boost
+ // Es wird unterstellt, dass die Buchstaben eines Fonts nicht
+ // groesser als doppelt so breit wie hoch sind.
+ // 7659: Ganz verrueckt: man muss sich auf den Ascent beziehen.
+ // Falle: GetSize() enthaelt die Wunschhoehe, die reale Hoehe
+ // ergibt sich erst im CalcAscent!
+ // 7697: Das Verhaeltnis ist noch krasser: ein Blank im Times
+ // New Roman besitzt einen Ascent von 182, eine Hoehe von 200
+ // und eine Breite von 53! Daraus folgt, dass eine Zeile mit
+ // vielen Blanks falsch eingeschaetzt wird. Wir erhoehen von
+ // Faktor 2 auf 8 (wg. negativen Kernings).
+
+ pPor->SetLen(1);
+ CalcAscent( rInf, pPor );
+
+ const SwFont* pTmpFnt = rInf.GetFont();
+ KSHORT nExpect = Min( KSHORT( ((Font *)pTmpFnt)->GetSize().Height() ),
+ KSHORT( pPor->GetAscent() ) ) / 8;
+ if ( !nExpect )
+ nExpect = 1;
+ nExpect = (USHORT)(rInf.GetIdx() + ((rInf.Width() - rInf.X()) / nExpect));
+ if( nExpect > rInf.GetIdx() && nNextChg > nExpect )
+ nNextChg = Min( nExpect, rInf.GetTxt().Len() );
+
+ // we keep an invariant during method calls:
+ // there are no portion ending characters like hard spaces
+ // or tabs in [ nLeftScanIdx, nRightScanIdx ]
+ if ( nLeftScanIdx <= rInf.GetIdx() && rInf.GetIdx() <= nRightScanIdx )
+ {
+ if ( nNextChg > nRightScanIdx )
+ nNextChg = nRightScanIdx =
+ rInf.ScanPortionEnd( nRightScanIdx, nNextChg );
+ }
+ else
+ {
+ nLeftScanIdx = rInf.GetIdx();
+ nNextChg = nRightScanIdx =
+ rInf.ScanPortionEnd( rInf.GetIdx(), nNextChg );
+ }
+
+ pPor->SetLen( nNextChg - rInf.GetIdx() );
+ rInf.SetLen( pPor->GetLen() );
+ return pPor;
+}
+
+
+/*************************************************************************
+ * SwTxtFormatter::WhichFirstPortion()
+ *************************************************************************/
+
+SwLinePortion *SwTxtFormatter::WhichFirstPortion(SwTxtFormatInfo &rInf)
+{
+ SwLinePortion *pPor = 0;
+
+ if( rInf.GetRest() )
+ {
+ // 5010: Tabs und Felder
+ if( '\0' != rInf.GetHookChar() )
+ return 0;
+
+ pPor = rInf.GetRest();
+ if( pPor->IsErgoSumPortion() )
+ rInf.SetErgoDone(sal_True);
+ else
+ if( pPor->IsFtnNumPortion() )
+ rInf.SetFtnDone(sal_True);
+ else
+ if( pPor->InNumberGrp() )
+ rInf.SetNumDone(sal_True);
+ if( pPor )
+ {
+ rInf.SetRest(0);
+ pCurr->SetRest( sal_True );
+ return pPor;
+ }
+ }
+
+ // ???? und ????: im Follow duerfen wir schon stehen,
+ // entscheidend ist, ob pFrm->GetOfst() == 0 ist!
+ if( rInf.GetIdx() )
+ {
+ // Nun koennen auch FtnPortions und ErgoSumPortions
+ // verlaengert werden.
+
+ // 1) Die ErgoSumTexte
+ if( !rInf.IsErgoDone() )
+ {
+ if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
+ pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
+ rInf.SetErgoDone( sal_True );
+ }
+
+ // 2) Arrow portions
+ if( !pPor && !rInf.IsArrowDone() )
+ {
+ if( pFrm->GetOfst() && !pFrm->IsFollow() &&
+ rInf.GetIdx() == pFrm->GetOfst() )
+ pPor = new SwArrowPortion( *pCurr );
+ rInf.SetArrowDone( sal_True );
+ }
+
+ // 3) Kerning portions at beginning of line in grid mode
+ if ( ! pPor && ! pCurr->GetPortion() )
+ {
+ GETGRID( GetTxtFrm()->FindPageFrm() )
+ if ( pGrid )
+ pPor = new SwKernPortion( *pCurr );
+ }
+
+ // 4) Die Zeilenreste (mehrzeilige Felder)
+ if( !pPor )
+ {
+ pPor = rInf.GetRest();
+ // 6922: Nur bei pPor natuerlich.
+ if( pPor )
+ {
+ pCurr->SetRest( sal_True );
+ rInf.SetRest(0);
+ }
+ }
+ }
+ else
+ {
+ // 5) Die Fussnotenzahlen
+ if( !rInf.IsFtnDone() )
+ {
+ ASSERT( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
+ "Rotated number portion trouble" )
+
+ sal_Bool bFtnNum = pFrm->IsFtnNumFrm();
+ rInf.GetParaPortion()->SetFtnNum( bFtnNum );
+ if( bFtnNum )
+ pPor = (SwLinePortion*)NewFtnNumPortion( rInf );
+ rInf.SetFtnDone( sal_True );
+ }
+
+ // 6) Die ErgoSumTexte gibt es natuerlich auch im TextMaster,
+ // entscheidend ist, ob der SwFtnFrm ein Follow ist.
+ if( !rInf.IsErgoDone() && !pPor && ! rInf.IsMulti() )
+ {
+ if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
+ pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
+ rInf.SetErgoDone( sal_True );
+ }
+
+ // 7) Die Numerierungen
+ if( !rInf.IsNumDone() && !pPor )
+ {
+ ASSERT( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
+ "Rotated number portion trouble" )
+
+ // Wenn wir im Follow stehen, dann natuerlich nicht.
+ if( GetTxtFrm()->GetTxtNode()->GetNumRule() )
+ pPor = (SwLinePortion*)NewNumberPortion( rInf );
+ rInf.SetNumDone( sal_True );
+ }
+ // 8) Die DropCaps
+ if( !pPor && GetDropFmt() && ! rInf.IsMulti() )
+ pPor = (SwLinePortion*)NewDropPortion( rInf );
+
+ // 9) Kerning portions at beginning of line in grid mode
+ if ( !pPor && !pCurr->GetPortion() )
+ {
+ GETGRID( GetTxtFrm()->FindPageFrm() )
+ if ( pGrid )
+ pPor = new SwKernPortion( *pCurr );
+ }
+ }
+
+ // 10) Decimal tab portion at the beginning of each line in table cells
+ if ( !pPor && !pCurr->GetPortion() &&
+ GetTxtFrm()->IsInTab() &&
+ GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) )
+ {
+ pPor = NewTabPortion( rInf, true );
+ }
+
+ // 11) suffix of meta-field
+ if (!pPor)
+ {
+ pPor = TryNewNoLengthPortion(rInf);
+ }
+
+ return pPor;
+}
+
+sal_Bool lcl_OldFieldRest( const SwLineLayout* pCurr )
+{
+ if( !pCurr->GetNext() )
+ return sal_False;
+ const SwLinePortion *pPor = pCurr->GetNext()->GetPortion();
+ sal_Bool bRet = sal_False;
+ while( pPor && !bRet )
+ {
+ bRet = (pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()) ||
+ (pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsFollowFld());
+ if( !pPor->GetLen() )
+ break;
+ pPor = pPor->GetPortion();
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewPortion()
+ *************************************************************************/
+
+/* NewPortion stellt rInf.nLen ein.
+ * Eine SwTxtPortion wird begrenzt durch ein tab, break, txtatr,
+ * attrwechsel.
+ * Drei Faelle koennen eintreten:
+ * 1) Die Zeile ist voll und der Umbruch wurde nicht emuliert
+ * -> return 0;
+ * 2) Die Zeile ist voll und es wurde ein Umbruch emuliert
+ * -> Breite neu einstellen und return new FlyPortion
+ * 3) Es muss eine neue Portion gebaut werden.
+ * -> CalcFlyWidth emuliert ggf. die Breite und return Portion
+ */
+
+SwLinePortion *SwTxtFormatter::NewPortion( SwTxtFormatInfo &rInf )
+{
+ // Underflow hat Vorrang
+ rInf.SetStopUnderFlow( sal_False );
+ if( rInf.GetUnderFlow() )
+ {
+ ASSERT( rInf.IsFull(), "SwTxtFormatter::NewPortion: underflow but not full" );
+ return UnderFlow( rInf );
+ }
+
+ // Wenn die Zeile voll ist, koennten noch Flys oder
+ // UnderFlow-LinePortions warten ...
+ if( rInf.IsFull() )
+ {
+ // ????: LineBreaks und Flys (bug05.sdw)
+ // 8450: IsDummy()
+ if( rInf.IsNewLine() && (!rInf.GetFly() || !pCurr->IsDummy()) )
+ return 0;
+
+ // Wenn der Text an den Fly gestossen ist, oder wenn
+ // der Fly als erstes drankommt, weil er ueber dem linken
+ // Rand haengt, wird GetFly() returnt.
+ // Wenn IsFull() und kein GetFly() vorhanden ist, gibt's
+ // naturgemaesz eine 0.
+ if( rInf.GetFly() )
+ {
+ if( rInf.GetLast()->IsBreakPortion() )
+ {
+ delete rInf.GetFly();
+ rInf.SetFly( 0 );
+ }
+
+ return rInf.GetFly();
+ }
+ // Ein fieser Sonderfall: ein Rahmen ohne Umlauf kreuzt den
+ // Ftn-Bereich. Wir muessen die Ftn-Portion als Zeilenrest
+ // bekanntgeben, damit SwTxtFrm::Format nicht abbricht
+ // (die Textmasse wurde ja durchformatiert).
+ if( rInf.GetRest() )
+ rInf.SetNewLine( sal_True );
+ else
+ {
+ // Wenn die naechste Zeile mit einem Rest eines Feldes beginnt,
+ // jetzt aber kein Rest mehr anliegt,
+ // muss sie auf jeden Fall neu formatiert werden!
+ if( lcl_OldFieldRest( GetCurr() ) )
+ rInf.SetNewLine( sal_True );
+ else
+ {
+ SwLinePortion *pFirst = WhichFirstPortion( rInf );
+ if( pFirst )
+ {
+ rInf.SetNewLine( sal_True );
+ if( pFirst->InNumberGrp() )
+ rInf.SetNumDone( sal_False) ;
+ delete pFirst;
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ SwLinePortion *pPor = WhichFirstPortion( rInf );
+
+ // Check for Hidden Portion:
+ if ( !pPor )
+ {
+ xub_StrLen nEnd = rInf.GetIdx();
+ if ( lcl_BuildHiddenPortion( rInf, nEnd ) )
+ pPor = new SwHiddenTextPortion( nEnd - rInf.GetIdx() );
+ }
+
+ if( !pPor )
+ {
+ if( ( !pMulti || pMulti->IsBidi() ) &&
+ // --> FME 2005-02-14 #i42734#
+ // No multi portion if there is a hook character waiting:
+ ( !rInf.GetRest() || '\0' == rInf.GetHookChar() ) )
+ // <--
+ {
+ // We open a multiportion part, if we enter a multi-line part
+ // of the paragraph.
+ xub_StrLen nEnd = rInf.GetIdx();
+ SwMultiCreator* pCreate = rInf.GetMultiCreator( nEnd, pMulti );
+ if( pCreate )
+ {
+ SwMultiPortion* pTmp = NULL;
+
+ if ( SW_MC_BIDI == pCreate->nId )
+ pTmp = new SwBidiPortion( nEnd, pCreate->nLevel );
+ else if ( SW_MC_RUBY == pCreate->nId )
+ {
+ Seek( rInf.GetIdx() );
+ sal_Bool bRubyTop;
+ sal_Bool* pRubyPos = 0;
+
+ if ( rInf.SnapToGrid() )
+ {
+ GETGRID( GetTxtFrm()->FindPageFrm() )
+ if ( pGrid )
+ {
+ bRubyTop = ! pGrid->GetRubyTextBelow();
+ pRubyPos = &bRubyTop;
+ }
+ }
+
+ pTmp = new SwRubyPortion( *pCreate, *rInf.GetFont(),
+ *GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess(),
+ nEnd, 0, pRubyPos );
+ }
+ else if( SW_MC_ROTATE == pCreate->nId )
+ pTmp = new SwRotatedPortion( *pCreate, nEnd,
+ GetTxtFrm()->IsRightToLeft() );
+ else
+ pTmp = new SwDoubleLinePortion( *pCreate, nEnd );
+
+ delete pCreate;
+ CalcFlyWidth( rInf );
+
+ return pTmp;
+ }
+ }
+ // 5010: Tabs und Felder
+ xub_Unicode cChar = rInf.GetHookChar();
+
+ if( cChar )
+ {
+ /* Wir holen uns nocheinmal cChar, um sicherzustellen, dass das
+ * Tab jetzt wirklich ansteht und nicht auf die naechste Zeile
+ * gewandert ist ( so geschehen hinter Rahmen ).
+ * Wenn allerdings eine FldPortion im Rest wartet, muessen wir
+ * das cChar natuerlich aus dem Feldinhalt holen, z.B. bei
+ * DezimalTabs und Feldern (22615)
+ */
+ if( !rInf.GetRest() || !rInf.GetRest()->InFldGrp() )
+ cChar = rInf.GetChar( rInf.GetIdx() );
+ rInf.ClearHookChar();
+ }
+ else
+ {
+ if( rInf.GetIdx() >= rInf.GetTxt().Len() )
+ {
+ rInf.SetFull(sal_True);
+ CalcFlyWidth( rInf );
+ return pPor;
+ }
+ cChar = rInf.GetChar( rInf.GetIdx() );
+ }
+
+ switch( cChar )
+ {
+ case CH_TAB:
+ pPor = NewTabPortion( rInf, false ); break;
+
+ case CH_BREAK:
+ pPor = new SwBreakPortion( *rInf.GetLast() ); break;
+
+ case CHAR_SOFTHYPHEN: // soft hyphen
+ pPor = new SwSoftHyphPortion; break;
+
+ case CHAR_HARDBLANK: // no-break space
+ pPor = new SwBlankPortion( ' ' ); break;
+
+ case CHAR_HARDHYPHEN: // non-breaking hyphen
+ pPor = new SwBlankPortion( '-' ); break;
+
+ case CHAR_ZWSP: // zero width space
+ case CHAR_ZWNBSP : // word joiner
+// case CHAR_RLM : // right to left mark
+// case CHAR_LRM : // left to right mark
+ pPor = new SwControlCharPortion( cChar ); break;
+
+ case CH_TXTATR_BREAKWORD:
+ case CH_TXTATR_INWORD:
+ if( rInf.HasHint( rInf.GetIdx() ) )
+ {
+ pPor = NewExtraPortion( rInf );
+ break;
+ }
+ // No break
+ default :
+ {
+ SwTabPortion* pLastTabPortion = rInf.GetLastTab();
+ if ( pLastTabPortion && cChar == rInf.GetTabDecimal() )
+ {
+ // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full:
+ // We have a decimal tab portion in the line and the next character has to be
+ // aligned at the tab stop position. We store the width from the beginning of
+ // the tab stop portion up to the portion containint the decimal separator:
+ if ( GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) /*rInf.GetVsh()->IsTabCompat();*/ &&
+ POR_TABDECIMAL == pLastTabPortion->GetWhichPor() )
+ {
+ ASSERT( rInf.X() >= pLastTabPortion->Fix(), "Decimal tab stop position cannot be calculated" )
+ const USHORT nWidthOfPortionsUpToDecimalPosition = (USHORT)(rInf.X() - pLastTabPortion->Fix() );
+ static_cast<SwTabDecimalPortion*>(pLastTabPortion)->SetWidthOfPortionsUpToDecimalPosition( nWidthOfPortionsUpToDecimalPosition );
+ rInf.SetTabDecimal( 0 );
+ }
+ // <--
+ else
+ rInf.SetFull( rInf.GetLastTab()->Format( rInf ) );
+ }
+
+ if( rInf.GetRest() )
+ {
+ if( rInf.IsFull() )
+ {
+ rInf.SetNewLine(sal_True);
+ return 0;
+ }
+ pPor = rInf.GetRest();
+ rInf.SetRest(0);
+ }
+ else
+ {
+ if( rInf.IsFull() )
+ return 0;
+ pPor = NewTxtPortion( rInf );
+ }
+ break;
+ }
+ }
+
+ // Wenn eine Portion erzeugt wird, obwohl eine RestPortion ansteht,
+ // dann haben wir es mit einem Feld zu tun, das sich aufgesplittet
+ // hat, weil z.B. ein Tab enthalten ist.
+ if( pPor && rInf.GetRest() )
+ pPor->SetLen( 0 );
+
+ // robust:
+ if( !pPor || rInf.IsStop() )
+ {
+ delete pPor;
+ return 0;
+ }
+ }
+
+ // Special portions containing numbers (footnote anchor, footnote number,
+ // numbering) can be contained in a rotated portion, if the user
+ // choose a rotated character attribute.
+ if ( pPor && ! pMulti )
+ {
+ if ( pPor->IsFtnPortion() )
+ {
+ const SwTxtFtn* pTxtFtn = ((SwFtnPortion*)pPor)->GetTxtFtn();
+
+ if ( pTxtFtn )
+ {
+ SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
+ const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
+ const SwEndNoteInfo* pInfo;
+ if( rFtn.IsEndNote() )
+ pInfo = &pDoc->GetEndNoteInfo();
+ else
+ pInfo = &pDoc->GetFtnInfo();
+ const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
+
+ const SfxPoolItem* pItem;
+ USHORT nDir = 0;
+ if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
+ sal_True, &pItem ))
+ nDir = ((SvxCharRotateItem*)pItem)->GetValue();
+
+ if ( 0 != nDir )
+ {
+ delete pPor;
+ pPor = new SwRotatedPortion( rInf.GetIdx() + 1, 900 == nDir ?
+ DIR_BOTTOM2TOP :
+ DIR_TOP2BOTTOM );
+ }
+ }
+ }
+ else if ( pPor->InNumberGrp() )
+ {
+ const SwFont* pNumFnt = ((SwFldPortion*)pPor)->GetFont();
+
+ if ( pNumFnt )
+ {
+ USHORT nDir = pNumFnt->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
+ if ( 0 != nDir )
+ {
+ delete pPor;
+ pPor = new SwRotatedPortion( 0, 900 == nDir ?
+ DIR_BOTTOM2TOP :
+ DIR_TOP2BOTTOM );
+
+ rInf.SetNumDone( sal_False );
+ rInf.SetFtnDone( sal_False );
+ }
+ }
+ }
+ }
+
+ // Der Font wird im Outputdevice eingestellt,
+ // der Ascent und die Hoehe werden berechnet.
+ if( !pPor->GetAscent() && !pPor->Height() )
+ CalcAscent( rInf, pPor );
+ rInf.SetLen( pPor->GetLen() );
+
+ // In CalcFlyWidth wird Width() verkuerzt, wenn eine FlyPortion vorliegt.
+ CalcFlyWidth( rInf );
+
+ // Man darf nicht vergessen, dass pCurr als GetLast() vernuenftige
+ // Werte bereithalten muss:
+ if( !pCurr->Height() )
+ {
+ ASSERT( pCurr->Height(), "SwTxtFormatter::NewPortion: limbo dance" );
+ pCurr->Height( pPor->Height() );
+ pCurr->SetAscent( pPor->GetAscent() );
+ }
+
+ ASSERT( !pPor || pPor->Height(),
+ "SwTxtFormatter::NewPortion: something went wrong");
+ if( pPor->IsPostItsPortion() && rInf.X() >= rInf.Width() && rInf.GetFly() )
+ {
+ delete pPor;
+ pPor = rInf.GetFly();
+ }
+ return pPor;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::FormatLine()
+ *************************************************************************/
+
+xub_StrLen SwTxtFormatter::FormatLine( const xub_StrLen nStartPos )
+{
+ ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
+ "SwTxtFormatter::FormatLine( nStartPos ) with unswapped frame" );
+
+ // For the formatting routines, we set pOut to the reference device.
+ SwHookOut aHook( GetInfo() );
+ if( GetInfo().GetLen() < GetInfo().GetTxt().Len() )
+ GetInfo().SetLen( GetInfo().GetTxt().Len() );
+
+ sal_Bool bBuild = sal_True;
+ SetFlyInCntBase( sal_False );
+ GetInfo().SetLineHeight( 0 );
+ GetInfo().SetLineNettoHeight( 0 );
+
+ // Recycling muss bei geaenderter Zeilenhoehe unterdrueckt werden
+ // und auch bei geaendertem Ascent (Absenken der Grundlinie).
+ const KSHORT nOldHeight = pCurr->Height();
+ const KSHORT nOldAscent = pCurr->GetAscent();
+
+ pCurr->SetEndHyph( sal_False );
+ pCurr->SetMidHyph( sal_False );
+
+ // fly positioning can make it necessary format a line several times
+ // for this, we have to keep a copy of our rest portion
+ SwLinePortion* pFld = GetInfo().GetRest();
+ SwFldPortion* pSaveFld = 0;
+
+ if ( pFld && pFld->InFldGrp() && !pFld->IsFtnPortion() )
+ pSaveFld = new SwFldPortion( *((SwFldPortion*)pFld) );
+
+ // for an optimal repaint rectangle, we want to compare fly portions
+ // before and after the BuildPortions call
+ const sal_Bool bOptimizeRepaint = AllowRepaintOpt();
+ const xub_StrLen nOldLineEnd = nStartPos + pCurr->GetLen();
+ SvLongs* pFlyStart = 0;
+
+ // these are the conditions for a fly position comparison
+ if ( bOptimizeRepaint && pCurr->IsFly() )
+ {
+ pFlyStart = new SvLongs;
+ SwLinePortion* pPor = pCurr->GetFirstPortion();
+ long nPOfst = 0;
+ USHORT nCnt = 0;
+
+ while ( pPor )
+ {
+ if ( pPor->IsFlyPortion() )
+ // insert start value of fly portion
+ pFlyStart->Insert( nPOfst, nCnt++ );
+
+ nPOfst += pPor->Width();
+ pPor = pPor->GetPortion();
+ }
+ }
+
+ // Hier folgt bald die Unterlaufpruefung.
+ while( bBuild )
+ {
+ GetInfo().SetFtnInside( sal_False );
+ GetInfo().SetOtherThanFtnInside( sal_False );
+
+ // These values must not be reset by FormatReset();
+ sal_Bool bOldNumDone = GetInfo().IsNumDone();
+ sal_Bool bOldArrowDone = GetInfo().IsArrowDone();
+ sal_Bool bOldErgoDone = GetInfo().IsErgoDone();
+
+ // besides other things, this sets the repaint offset to 0
+ FormatReset( GetInfo() );
+
+ GetInfo().SetNumDone( bOldNumDone );
+ GetInfo().SetArrowDone( bOldArrowDone );
+ GetInfo().SetErgoDone( bOldErgoDone );
+
+ // build new portions for this line
+ BuildPortions( GetInfo() );
+
+ if( GetInfo().IsStop() )
+ {
+ pCurr->SetLen( 0 );
+ pCurr->Height( GetFrmRstHeight() + 1 );
+ pCurr->SetRealHeight( GetFrmRstHeight() + 1 );
+ pCurr->Width(0);
+ pCurr->Truncate();
+ return nStartPos;
+ }
+ else if( GetInfo().IsDropInit() )
+ {
+ DropInit();
+ GetInfo().SetDropInit( sal_False );
+ }
+
+ pCurr->CalcLine( *this, GetInfo() );
+ CalcRealHeight( GetInfo().IsNewLine() );
+
+ if ( IsFlyInCntBase() && !IsQuick() )
+ {
+ KSHORT nTmpAscent, nTmpHeight;
+ CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+ AlignFlyInCntBase( Y() + long( nTmpAscent ) );
+ pCurr->CalcLine( *this, GetInfo() );
+ CalcRealHeight();
+ }
+
+ // bBuild entscheidet, ob noch eine Ehrenrunde gedreht wird
+ if ( pCurr->GetRealHeight() <= GetInfo().GetLineHeight() )
+ {
+ pCurr->SetRealHeight( GetInfo().GetLineHeight() );
+ bBuild = sal_False;
+ }
+ else
+ {
+ bBuild = ( GetInfo().GetTxtFly()->IsOn() && ChkFlyUnderflow( GetInfo() )
+ || GetInfo().CheckFtnPortion( pCurr ) );
+ if( bBuild )
+ {
+ GetInfo().SetNumDone( bOldNumDone );
+ GetInfo().ResetMaxWidthDiff();
+
+ // delete old rest
+ if ( GetInfo().GetRest() )
+ {
+ delete GetInfo().GetRest();
+ GetInfo().SetRest( 0 );
+ }
+
+ // set original rest portion
+ if ( pSaveFld )
+ GetInfo().SetRest( new SwFldPortion( *pSaveFld ) );
+
+ pCurr->SetLen( 0 );
+ pCurr->Width(0);
+ pCurr->Truncate();
+ }
+ }
+ }
+
+ // calculate optimal repaint rectangle
+ if ( bOptimizeRepaint )
+ {
+ GetInfo().SetPaintOfst( CalcOptRepaint( nOldLineEnd, pFlyStart ) );
+ if ( pFlyStart )
+ delete pFlyStart;
+ }
+ else
+ // Special case: We do not allow an optimitation of the repaint
+ // area, but during formatting the repaint offset is set to indicate
+ // a maximum value for the offset. This value has to be reset:
+ GetInfo().SetPaintOfst( 0 );
+
+ // This corrects the start of the reformat range if something has
+ // moved to the next line. Otherwise IsFirstReformat in AllowRepaintOpt
+ // will give us a wrong result if we have to reformat another line
+ GetInfo().GetParaPortion()->GetReformat()->LeftMove( GetInfo().GetIdx() );
+
+ // delete master copy of rest portion
+ if ( pSaveFld )
+ delete pSaveFld;
+
+ xub_StrLen nNewStart = nStartPos + pCurr->GetLen();
+
+ // adjust text if kana compression is enabled
+ if ( GetInfo().CompressLine() )
+ {
+ SwTwips nRepaintOfst = CalcKanaAdj( pCurr );
+
+ // adjust repaint offset
+ if ( nRepaintOfst < GetInfo().GetPaintOfst() )
+ GetInfo().SetPaintOfst( nRepaintOfst );
+ }
+
+ CalcAdjustLine( pCurr );
+
+ if( nOldHeight != pCurr->Height() || nOldAscent != pCurr->GetAscent() )
+ {
+ SetFlyInCntBase();
+ GetInfo().SetPaintOfst( 0 ); //geaenderte Zeilenhoehe => kein Recycling
+ // alle weiteren Zeilen muessen gepaintet und, wenn Flys im Spiel sind
+ // auch formatiert werden.
+ GetInfo().SetShift( sal_True );
+ }
+
+ if ( IsFlyInCntBase() && !IsQuick() )
+ UpdatePos( pCurr, GetTopLeft(), GetStart() );
+
+ return nNewStart;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::RecalcRealHeight()
+ *************************************************************************/
+
+void SwTxtFormatter::RecalcRealHeight()
+{
+ sal_Bool bMore = sal_True;
+ while(bMore)
+ {
+ DBG_LOOP;
+ CalcRealHeight();
+ bMore = Next() != 0;
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcRealHeight()
+ *************************************************************************/
+
+void SwTxtFormatter::CalcRealHeight( sal_Bool bNewLine )
+{
+ KSHORT nLineHeight = pCurr->Height();
+ pCurr->SetClipping( sal_False );
+
+ GETGRID( pFrm->FindPageFrm() )
+ if ( pGrid && GetInfo().SnapToGrid() )
+ {
+ const USHORT nGridWidth = pGrid->GetBaseHeight();
+ const USHORT nRubyHeight = pGrid->GetRubyHeight();
+ const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow();
+
+ nLineHeight = nGridWidth + nRubyHeight;
+ USHORT nLineDist = nLineHeight;
+
+ while ( pCurr->Height() > nLineHeight )
+ nLineHeight = nLineHeight + nLineDist;
+
+ KSHORT nAsc = pCurr->GetAscent() +
+ ( bRubyTop ?
+ ( nLineHeight - pCurr->Height() + nRubyHeight ) / 2 :
+ ( nLineHeight - pCurr->Height() - nRubyHeight ) / 2 );
+
+ pCurr->Height( nLineHeight );
+ pCurr->SetAscent( nAsc );
+ pInf->GetParaPortion()->SetFixLineHeight();
+
+ // we ignore any line spacing options except from ...
+ const SvxLineSpacingItem* pSpace = aLineInf.GetLineSpacing();
+ if ( ! IsParaLine() && pSpace &&
+ SVX_INTER_LINE_SPACE_PROP == pSpace->GetInterLineSpaceRule() )
+ {
+ ULONG nTmp = pSpace->GetPropLineSpace();
+
+ if( nTmp < 100 )
+ nTmp = 100;
+
+ nTmp *= nLineHeight;
+ nLineHeight = (USHORT)(nTmp / 100);
+ }
+
+ pCurr->SetRealHeight( nLineHeight );
+ return;
+ }
+
+ // Das Dummyflag besitzen Zeilen, die nur Flyportions enthalten, diese
+ // sollten kein Register etc. beachten. Dummerweise hat kann es eine leere
+ // Zeile am Absatzende geben (bei leeren Abs?tzen oder nach einem
+ // Shift-Return), die das Register durchaus beachten soll.
+ if( !pCurr->IsDummy() || ( !pCurr->GetNext() &&
+ GetStart() >= GetTxtFrm()->GetTxt().Len() && !bNewLine ) )
+ {
+ const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
+ if( pSpace )
+ {
+ switch( pSpace->GetLineSpaceRule() )
+ {
+ case SVX_LINE_SPACE_AUTO:
+ break;
+ case SVX_LINE_SPACE_MIN:
+ {
+ if( nLineHeight < KSHORT( pSpace->GetLineHeight() ) )
+ nLineHeight = pSpace->GetLineHeight();
+ break;
+ }
+ case SVX_LINE_SPACE_FIX:
+ {
+ nLineHeight = pSpace->GetLineHeight();
+ KSHORT nAsc = ( 4 * nLineHeight ) / 5; // 80%
+ if( nAsc < pCurr->GetAscent() ||
+ nLineHeight - nAsc < pCurr->Height() - pCurr->GetAscent() )
+ pCurr->SetClipping( sal_True );
+ pCurr->Height( nLineHeight );
+ pCurr->SetAscent( nAsc );
+ pInf->GetParaPortion()->SetFixLineHeight();
+ }
+ break;
+ default: ASSERT( sal_False, ": unknown LineSpaceRule" );
+ }
+ if( !IsParaLine() )
+ switch( pSpace->GetInterLineSpaceRule() )
+ {
+ case SVX_INTER_LINE_SPACE_OFF:
+ break;
+ case SVX_INTER_LINE_SPACE_PROP:
+ {
+ long nTmp = pSpace->GetPropLineSpace();
+ // 50% ist das Minimum, bei 0% schalten wir auf
+ // den Defaultwert 100% um ...
+ if( nTmp < 50 )
+ nTmp = nTmp ? 50 : 100;
+
+ nTmp *= nLineHeight;
+ nTmp /= 100;
+ if( !nTmp )
+ ++nTmp;
+ nLineHeight = (KSHORT)nTmp;
+ break;
+ }
+ case SVX_INTER_LINE_SPACE_FIX:
+ {
+ nLineHeight = nLineHeight + pSpace->GetInterLineSpace();
+ break;
+ }
+ default: ASSERT( sal_False, ": unknown InterLineSpaceRule" );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ KSHORT nDummy = nLineHeight + 1;
+ (void)nDummy;
+#endif
+
+ if( IsRegisterOn() )
+ {
+ SwTwips nTmpY = Y() + pCurr->GetAscent() + nLineHeight - pCurr->Height();
+ SWRECTFN( pFrm )
+ if ( bVert )
+ nTmpY = pFrm->SwitchHorizontalToVertical( nTmpY );
+ nTmpY = (*fnRect->fnYDiff)( nTmpY, RegStart() );
+ KSHORT nDiff = KSHORT( nTmpY % RegDiff() );
+ if( nDiff )
+ nLineHeight += RegDiff() - nDiff;
+ }
+ }
+ pCurr->SetRealHeight( nLineHeight );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::FeedInf()
+ *************************************************************************/
+
+void SwTxtFormatter::FeedInf( SwTxtFormatInfo &rInf ) const
+{
+ // 3260, 3860: Fly auf jeden Fall loeschen!
+ ClearFly( rInf );
+ rInf.Init();
+
+ rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
+ rInf.SetRoot( pCurr );
+ rInf.SetLineStart( nStart );
+ rInf.SetIdx( nStart );
+
+ // Handle overflows:
+ // --> FME 2004-11-25 #i34348# Changed type from USHORT to SwTwips
+ SwTwips nTmpLeft = Left();
+ SwTwips nTmpRight = Right();
+ SwTwips nTmpFirst = FirstLeft();
+ // <--
+
+ if ( nTmpLeft > USHRT_MAX ||
+ nTmpRight > USHRT_MAX ||
+ nTmpFirst > USHRT_MAX )
+ {
+ SWRECTFN( rInf.GetTxtFrm() )
+ nTmpLeft = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetLeft)();
+ nTmpRight = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetRight)();
+ nTmpFirst = nTmpLeft;
+ }
+
+ rInf.Left( nTmpLeft );
+ rInf.Right( nTmpRight );
+ rInf.First( nTmpFirst );
+
+ rInf.RealWidth( KSHORT(rInf.Right()) - KSHORT(GetLeftMargin()) );
+ rInf.Width( rInf.RealWidth() );
+ if( ((SwTxtFormatter*)this)->GetRedln() )
+ {
+ ((SwTxtFormatter*)this)->GetRedln()->Clear( ((SwTxtFormatter*)this)->GetFnt() );
+ ((SwTxtFormatter*)this)->GetRedln()->Reset();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::FormatReset()
+ *************************************************************************/
+
+void SwTxtFormatter::FormatReset( SwTxtFormatInfo &rInf )
+{
+ pCurr->Truncate();
+ pCurr->Init();
+ if( pBlink && pCurr->IsBlinking() )
+ pBlink->Delete( pCurr );
+
+ // delete pSpaceAdd und pKanaComp
+ pCurr->FinishSpaceAdd();
+ pCurr->FinishKanaComp();
+ pCurr->ResetFlags();
+ FeedInf( rInf );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcOnceMore()
+ *************************************************************************/
+
+sal_Bool SwTxtFormatter::CalcOnceMore()
+{
+ if( pDropFmt )
+ {
+ const KSHORT nOldDrop = GetDropHeight();
+ CalcDropHeight( pDropFmt->GetLines() );
+ bOnceMore = nOldDrop != GetDropHeight();
+ }
+ else
+ bOnceMore = sal_False;
+ return bOnceMore;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcBottomLine()
+ *************************************************************************/
+
+SwTwips SwTxtFormatter::CalcBottomLine() const
+{
+ SwTwips nRet = Y() + GetLineHeight();
+ SwTwips nMin = GetInfo().GetTxtFly()->GetMinBottom();
+ if( nMin && ++nMin > nRet )
+ {
+ SwTwips nDist = pFrm->Frm().Height() - pFrm->Prt().Height()
+ - pFrm->Prt().Top();
+ if( nRet + nDist < nMin )
+ {
+ sal_Bool bRepaint = HasTruncLines() &&
+ GetInfo().GetParaPortion()->GetRepaint()->Bottom() == nRet-1;
+ nRet = nMin - nDist;
+ if( bRepaint )
+ {
+ ((SwRepaint*)GetInfo().GetParaPortion()
+ ->GetRepaint())->Bottom( nRet-1 );
+ ((SwTxtFormatInfo&)GetInfo()).SetPaintOfst( 0 );
+ }
+ }
+ }
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::_CalcFitToContent()
+ *
+ * FME/OD: This routine does a limited text formatting.
+ *************************************************************************/
+
+SwTwips SwTxtFormatter::_CalcFitToContent()
+{
+ FormatReset( GetInfo() );
+ BuildPortions( GetInfo() );
+ pCurr->CalcLine( *this, GetInfo() );
+ return pCurr->Width();
+}
+
+/*************************************************************************
+ * SwTxtFormatter::AllowRepaintOpt()
+ *
+ * determines if the calculation of a repaint offset is allowed
+ * otherwise each line is painted from 0 (this is a copy of the beginning
+ * of the former SwTxtFormatter::Recycle() function
+ *************************************************************************/
+sal_Bool SwTxtFormatter::AllowRepaintOpt() const
+{
+ // reformat position in front of current line? Only in this case
+ // we want to set the repaint offset
+ sal_Bool bOptimizeRepaint = nStart < GetInfo().GetReformatStart() &&
+ pCurr->GetLen();
+
+ // a special case is the last line of a block adjusted paragraph:
+ if ( bOptimizeRepaint )
+ {
+ switch( GetAdjust() )
+ {
+ case SVX_ADJUST_BLOCK:
+ {
+ if( IsLastBlock() || IsLastCenter() )
+ bOptimizeRepaint = sal_False;
+ else
+ {
+ // ????: Blank in der letzten Masterzeile (blocksat.sdw)
+ bOptimizeRepaint = 0 == pCurr->GetNext() && !pFrm->GetFollow();
+ if ( bOptimizeRepaint )
+ {
+ SwLinePortion *pPos = pCurr->GetFirstPortion();
+ while ( pPos && !pPos->IsFlyPortion() )
+ pPos = pPos->GetPortion();
+ bOptimizeRepaint = !pPos;
+ }
+ }
+ break;
+ }
+ case SVX_ADJUST_CENTER:
+ case SVX_ADJUST_RIGHT:
+ bOptimizeRepaint = sal_False;
+ break;
+ default: ;
+ }
+ }
+
+ // Schon wieder ein Sonderfall: unsichtbare SoftHyphs
+ const xub_StrLen nReformat = GetInfo().GetReformatStart();
+ if( bOptimizeRepaint && STRING_LEN != nReformat )
+ {
+ const xub_Unicode cCh = GetInfo().GetTxt().GetChar( nReformat );
+ bOptimizeRepaint = ( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh )
+ || ! GetInfo().HasHint( nReformat );
+ }
+
+ return bOptimizeRepaint;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcOptRepaint()
+ *
+ * calculates an optimal repaint offset for the current line
+ *************************************************************************/
+long SwTxtFormatter::CalcOptRepaint( xub_StrLen nOldLineEnd,
+ const SvLongs* pFlyStart )
+{
+ if ( GetInfo().GetIdx() < GetInfo().GetReformatStart() )
+ // the reformat position is behind our new line, that means
+ // something of our text has moved to the next line
+ return 0;
+
+ xub_StrLen nReformat = Min( GetInfo().GetReformatStart(), nOldLineEnd );
+
+ // in case we do not have any fly in our line, our repaint position
+ // is the changed position - 1
+ if ( ! pFlyStart && ! pCurr->IsFly() )
+ {
+ // this is the maximum repaint offset determined during formatting
+ // for example: the beginning of the first right tab stop
+ // if this value is 0, this means that we do not have an upper
+ // limit for the repaint offset
+ const long nFormatRepaint = GetInfo().GetPaintOfst();
+
+ if ( nReformat < GetInfo().GetLineStart() + 3 )
+ return 0;
+
+ // step back two positions for smoother repaint
+ nReformat -= 2;
+
+#ifndef QUARTZ
+#ifndef ENABLE_GRAPHITE
+ // --> FME 2004-09-27 #i28795#, #i34607#, #i38388#
+ // step back six(!) more characters for complex scripts
+ // this is required e.g., for Khmer (thank you, Javier!)
+ const SwScriptInfo& rSI = GetInfo().GetParaPortion()->GetScriptInfo();
+ xub_StrLen nMaxContext = 0;
+ if( ::i18n::ScriptType::COMPLEX == rSI.ScriptType( nReformat ) )
+ nMaxContext = 6;
+#else
+ // Some Graphite fonts need context for scripts not marked as complex
+ static const xub_StrLen nMaxContext = 10;
+#endif
+#else
+ // some fonts like Quartz's Zapfino need more context
+ // TODO: query FontInfo for maximum unicode context
+ static const xub_StrLen nMaxContext = 8;
+#endif
+ if( nMaxContext > 0 )
+ {
+ if ( nReformat > GetInfo().GetLineStart() + nMaxContext )
+ nReformat = nReformat - nMaxContext;
+ else
+ nReformat = GetInfo().GetLineStart();
+ }
+ // <--
+
+ // Weird situation: Our line used to end with a hole portion
+ // and we delete some characters at the end of our line. We have
+ // to take care for repainting the blanks which are not anymore
+ // covered by the hole portion
+ while ( nReformat > GetInfo().GetLineStart() &&
+ CH_BLANK == GetInfo().GetChar( nReformat ) )
+ --nReformat;
+
+ ASSERT( nReformat < GetInfo().GetIdx(), "Reformat too small for me!" );
+ SwRect aRect;
+
+ // Note: GetChareRect is not const. It definitely changes the
+ // bMulti flag. We have to save and resore the old value.
+ sal_Bool bOldMulti = GetInfo().IsMulti();
+ GetCharRect( &aRect, nReformat );
+ GetInfo().SetMulti( bOldMulti );
+
+ return nFormatRepaint ? Min( aRect.Left(), nFormatRepaint ) :
+ aRect.Left();
+ }
+ else
+ {
+ // nReformat may be wrong, if something around flys has changed:
+ // we compare the former and the new fly positions in this line
+ // if anything has changed, we carefully have to adjust the right
+ // repaint position
+ long nPOfst = 0;
+ USHORT nCnt = 0;
+ USHORT nX = 0;
+ USHORT nIdx = GetInfo().GetLineStart();
+ SwLinePortion* pPor = pCurr->GetFirstPortion();
+
+ while ( pPor )
+ {
+ if ( pPor->IsFlyPortion() )
+ {
+ // compare start of fly with former start of fly
+ if ( pFlyStart &&
+ nCnt < pFlyStart->Count() &&
+ nX == (*pFlyStart)[ nCnt ] &&
+ nIdx < nReformat
+ )
+ // found fix position, nothing has changed left from nX
+ nPOfst = nX + pPor->Width();
+ else
+ break;
+
+ nCnt++;
+ }
+ nX = nX + pPor->Width();
+ nIdx = nIdx + pPor->GetLen();
+ pPor = pPor->GetPortion();
+ }
+
+ return nPOfst + GetLeftMargin();
+ }
+}
+
+bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos )
+{
+ // Only if hidden text should not be shown:
+// if ( rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar() )
+ const bool bShowInDocView = rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar();
+ const bool bShowForPrinting = rInf.GetOpt().IsShowHiddenChar( TRUE ) && rInf.GetOpt().IsPrinting();
+ if (bShowInDocView || bShowForPrinting)
+ return false;
+
+ const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
+ xub_StrLen nHiddenStart;
+ xub_StrLen nHiddenEnd;
+ rSI.GetBoundsOfHiddenRange( rPos, nHiddenStart, nHiddenEnd );
+ if ( nHiddenEnd )
+ {
+ rPos = nHiddenEnd;
+ return true;
+ }
+
+ return false;
+}
diff --git a/sw/source/core/text/itrform2.hxx b/sw/source/core/text/itrform2.hxx
new file mode 100644
index 000000000000..0e3522883bc1
--- /dev/null
+++ b/sw/source/core/text/itrform2.hxx
@@ -0,0 +1,214 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _ITRFORM2_HXX
+#define _ITRFORM2_HXX
+#include "itrpaint.hxx"
+
+class SwFlyCntPortion;
+class SwInterHyphInfo;
+class SwDropPortion;
+class SwFmtDrop;
+class SwTxtAttr;
+class SwNumberPortion;
+class SwErgoSumPortion;
+class SwExpandPortion;
+class SwMultiPortion;
+class SwFtnPortion;
+class SvLongs;
+
+/*************************************************************************
+ * class SwTxtFormatter
+ *************************************************************************/
+
+class SwTxtFormatter : public SwTxtPainter
+{
+ const SwFmtDrop *pDropFmt;
+ SwMultiPortion* pMulti; // during formatting a multi-portion
+ sal_uInt8 nCntEndHyph; // zaehlt aufeinanderfolgende Hyphens am Zeilenende
+ sal_uInt8 nCntMidHyph; // zaehlt aufeinanderfolgende Hyphens vor Flies
+ xub_StrLen nLeftScanIdx; // for increasing performance during
+ xub_StrLen nRightScanIdx; // scanning for portion ends
+ sal_Bool bOnceMore : 1; // noch 'ne Runde?
+ sal_Bool bFlyInCntBase : 1; // Base-Referenz der zeichengeb. Rahmen setzen
+ sal_Bool bChanges : 1; // Flag, fuer die Berechnung des Repaint-Rechtecks
+ sal_Bool bTruncLines : 1; // Flag, Repaint-Rechtecks ggf. erweitern
+ sal_Bool bUnclipped : 1; // Flag, ob Repaint groesser als feste Zeilenhoehe
+ USHORT m_nHintEndIndex; // HACK for TryNewNoLengthPortion
+ SwLinePortion *NewPortion( SwTxtFormatInfo &rInf );
+ SwTxtPortion *NewTxtPortion( SwTxtFormatInfo &rInf );
+ SwLinePortion *NewExtraPortion( SwTxtFormatInfo &rInf );
+ SwTabPortion *NewTabPortion( SwTxtFormatInfo &rInf, bool bAuto ) const;
+ SwNumberPortion *NewNumberPortion( SwTxtFormatInfo &rInf ) const;
+ SwDropPortion *NewDropPortion( SwTxtFormatInfo &rInf );
+ SwNumberPortion *NewFtnNumPortion( SwTxtFormatInfo &rInf ) const;
+ SwErgoSumPortion *NewErgoSumPortion( SwTxtFormatInfo &rInf ) const;
+ SwExpandPortion *NewFldPortion( SwTxtFormatInfo &rInf,
+ const SwTxtAttr *pHt ) const;
+ SwFtnPortion *NewFtnPortion( SwTxtFormatInfo &rInf, SwTxtAttr *pHt );
+ SwFlyCntPortion *NewFlyCntPortion( SwTxtFormatInfo &rInf,
+ SwTxtAttr *pHt ) const;
+ SwLinePortion *WhichFirstPortion( SwTxtFormatInfo &rInf );
+ SwTxtPortion *WhichTxtPor( SwTxtFormatInfo &rInf ) const;
+ SwExpandPortion * TryNewNoLengthPortion( SwTxtFormatInfo & rInfo );
+
+ // Das Herzstueck der Formatierung
+ void BuildPortions( SwTxtFormatInfo &rInf );
+ BOOL BuildMultiPortion( SwTxtFormatInfo &rInf, SwMultiPortion& rMulti );
+
+ // Berechnung des emulierten rechten Rands
+ void CalcFlyWidth( SwTxtFormatInfo &rInf );
+
+ // wird von SwTxtFormatter wegen UpdatePos ueberladen
+ void CalcAdjustLine( SwLineLayout *pCurr );
+
+ // consideres line spacing attributes
+ void CalcRealHeight( sal_Bool bNewLine = sal_False );
+
+ // uebertraegt die Daten nach rInf
+ void FeedInf( SwTxtFormatInfo &rInf ) const;
+
+ // behandelt die Unterlaufsituationen
+ SwLinePortion *UnderFlow( SwTxtFormatInfo &rInf );
+
+ // errechnet den Ascent und die Hoehe aus der Fontmetric
+ void CalcAscent( SwTxtFormatInfo &rInf, SwLinePortion *pPor );
+
+ // determines, if a optimized repaint rectange is allowed
+ sal_Bool AllowRepaintOpt() const;
+
+ // calculates and sets the optimized repaint offset
+ long CalcOptRepaint( xub_StrLen nOldLineEnd, const SvLongs* pFlyStart );
+
+ // wird von FormatLine gerufen.
+ void FormatReset( SwTxtFormatInfo &rInf );
+
+ // durch das Adjustment aendert sich die Position der Portions
+ void UpdatePos( SwLineLayout *pCurr, Point aStart, xub_StrLen nStartIdx,
+ sal_Bool bAllWays = sal_False ) const;
+
+ // Setze alle FlyInCntFrms auf die uebergebene BaseLine
+ void AlignFlyInCntBase( long nBaseLine ) const;
+
+ // Unterlaufbedingungen bei Flys
+ sal_Bool ChkFlyUnderflow( SwTxtFormatInfo &rInf ) const;
+
+ // Portion einfuegen.
+ void InsertPortion( SwTxtFormatInfo &rInf, SwLinePortion *pPor ) const;
+
+ // schaetzt die Hoehe fuer die DropPortion
+ void GuessDropHeight( const MSHORT nLines );
+
+public:
+ // errechnet die Hoehe fuer die DropPortion
+ void CalcDropHeight( const MSHORT nLines );
+
+ // errechnet den Bottom des Absatzes, beruecksichtigt an diesem verankerte
+ // Objekte mit Umlauf 1. Absatz.
+ SwTwips CalcBottomLine() const;
+
+ // Beruecksichtigt zeichengebundene Objekte bei der Repaintrechteck-
+ // berechnung in Zeilen mit fester Zeilenhoehe
+ void CalcUnclipped( SwTwips& rTop, SwTwips& rBottom );
+
+ // u.a. fuer DropCaps
+ sal_Bool CalcOnceMore();
+
+ void CtorInitTxtFormatter( SwTxtFrm *pFrm, SwTxtFormatInfo *pInf );
+ inline SwTxtFormatter( SwTxtFrm *pTxtFrm, SwTxtFormatInfo *pTxtFmtInf ) : SwTxtPainter(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL)
+ { CtorInitTxtFormatter( pTxtFrm, pTxtFmtInf ); }
+ ~SwTxtFormatter();
+
+ xub_StrLen FormatLine( const xub_StrLen nStart );
+
+ void RecalcRealHeight();
+
+ // Wir formatieren eine Zeile fuer die interaktive Trennung
+ sal_Bool Hyphenate( SwInterHyphInfo &rInf );
+
+ // Spezialmethode fuer QuoVadis-Texte
+ // nErgo ist die Seitennummer der ErgoSum-Ftn
+ // Bei 0 ist es noch unklar.
+ xub_StrLen FormatQuoVadis( const xub_StrLen nStart );
+
+ // Die Notbremse: Formatierung abbrechen, Zeile verwerfen.
+ inline sal_Bool IsStop() const { return GetInfo().IsStop(); }
+
+ // Das Gegenstueck: Formatierung unbedingt fortsetzen.
+ inline sal_Bool IsNewLine() const { return GetInfo().IsNewLine(); }
+
+ // FormatQuick(); auffrischen von Formatinformationen
+ inline sal_Bool IsQuick() const { return GetInfo().IsQuick(); }
+
+ // erzeugt ggfs. ein SwLineLayout, dass Ftn/Fly--Oszillation unterbindet.
+ void MakeDummyLine();
+
+ // SwTxtIter-Funktionalitaet
+ void Insert( SwLineLayout *pLine );
+
+ // die noch verbleibende Hoehe bis zum Seitenrand
+ KSHORT GetFrmRstHeight() const;
+
+ // Wie breit waerest Du ohne rechte Begrenzungen (Flys etc.)?
+ SwTwips _CalcFitToContent( );
+
+ SwLinePortion* MakeRestPortion(const SwLineLayout* pLine, xub_StrLen nPos);
+
+ inline const SwFmtDrop *GetDropFmt() const { return pDropFmt; }
+ inline void ClearDropFmt() { pDropFmt = 0; }
+
+ inline SwMultiPortion *GetMulti() const { return pMulti; }
+
+ inline sal_Bool IsOnceMore() const { return bOnceMore; }
+ inline void SetOnceMore( sal_Bool bNew ) { bOnceMore = bNew; }
+
+ inline sal_Bool HasChanges() const { return bChanges; }
+ inline void SetChanges() { bChanges = sal_True; }
+
+ inline sal_Bool HasTruncLines() const { return bTruncLines; }
+ inline void SetTruncLines( sal_Bool bNew ) { bTruncLines = bNew; }
+
+ inline sal_Bool IsUnclipped() const { return bUnclipped; }
+ inline void SetUnclipped( sal_Bool bNew ) { bUnclipped = bNew; }
+
+ inline sal_Bool IsFlyInCntBase() const { return bFlyInCntBase; }
+ inline void SetFlyInCntBase( sal_Bool bNew = sal_True ){ bFlyInCntBase = bNew; }
+
+ inline SwTxtFormatInfo &GetInfo()
+ { return (SwTxtFormatInfo&)SwTxtIter::GetInfo(); }
+ inline const SwTxtFormatInfo &GetInfo() const
+ { return (const SwTxtFormatInfo&)SwTxtIter::GetInfo(); }
+
+ inline void InitCntHyph() { CntHyphens( nCntEndHyph, nCntMidHyph ); }
+ inline const sal_uInt8 &CntEndHyph() const { return nCntEndHyph; }
+ inline const sal_uInt8 &CntMidHyph() const { return nCntMidHyph; }
+ inline sal_uInt8 &CntEndHyph() { return nCntEndHyph; }
+ inline sal_uInt8 &CntMidHyph() { return nCntMidHyph; }
+};
+
+
+
+#endif
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
new file mode 100644
index 000000000000..2bd7a46ac09f
--- /dev/null
+++ b/sw/source/core/text/itrpaint.cxx
@@ -0,0 +1,718 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+#include "flyfrm.hxx" // SwFlyInCntFrm
+#include "viewopt.hxx" // SwViewOptions
+#include "errhdl.hxx"
+#include "txtatr.hxx" // SwINetFmt
+#include <tools/multisel.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <txtinet.hxx>
+#include <fchrfmt.hxx>
+#include <frmatr.hxx>
+#include <sfx2/printer.hxx>
+#include <fmtftn.hxx>
+#include <fmtfld.hxx>
+#include <fldbas.hxx> // SwField
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+
+// --> FME 2004-06-08 #i12836# enhanced pdf export
+#include <EnhancedPDFExportHelper.hxx>
+// <--
+
+
+#include "flyfrms.hxx"
+#include "viewsh.hxx"
+#include "txtcfg.hxx"
+#include "itrpaint.hxx"
+#include "txtfrm.hxx" // pFrm
+#include "txtfly.hxx"
+#include "swfont.hxx"
+#include "txtpaint.hxx"
+#include "portab.hxx" // SwTabPortion::IsFilled
+#include "porfly.hxx" // SwFlyCntPortion
+#include "porfld.hxx" // SwGrfNumPortion
+#include "frmfmt.hxx" // LRSpace
+#include "txatbase.hxx" // SwTxtAttr
+#include "charfmt.hxx" // SwFmtCharFmt
+#include "redlnitr.hxx" // SwRedlineItr
+#include "porrst.hxx" // SwArrowPortion
+#include "pormulti.hxx"
+
+/*************************************************************************
+ * IsUnderlineBreak
+ *
+ * Returns, if we have an underline breaking situation
+ * Adding some more conditions here means you also have to change them
+ * in SwTxtPainter::CheckSpecialUnderline
+ *************************************************************************/
+sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
+{
+ return UNDERLINE_NONE == rFnt.GetUnderline() ||
+ rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
+ rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
+ rPor.IsHolePortion() ||
+ ( rPor.IsMultiPortion() && ! ((SwMultiPortion&)rPor).IsBidi() ) ||
+ rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
+ SVX_CASEMAP_KAPITAELCHEN == rFnt.GetCaseMap();
+}
+
+/*************************************************************************
+ * SwTxtPainter::CtorInitTxtPainter()
+ *************************************************************************/
+void SwTxtPainter::CtorInitTxtPainter( SwTxtFrm *pNewFrm, SwTxtPaintInfo *pNewInf )
+{
+ CtorInitTxtCursor( pNewFrm, pNewInf );
+ pInf = pNewInf;
+ SwFont *pMyFnt = GetFnt();
+ GetInfo().SetFont( pMyFnt );
+#ifdef DBG_UTIL
+ if( ALIGN_BASELINE != pMyFnt->GetAlign() )
+ {
+ ASSERT( ALIGN_BASELINE == pMyFnt->GetAlign(),
+ "+SwTxtPainter::CTOR: font alignment revolution" );
+ pMyFnt->SetAlign( ALIGN_BASELINE );
+ }
+#endif
+ bPaintDrop = sal_False;
+}
+
+
+/*************************************************************************
+ * SwTxtPainter::CalcPaintOfst()
+ *************************************************************************/
+SwLinePortion *SwTxtPainter::CalcPaintOfst( const SwRect &rPaint )
+{
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+ GetInfo().SetPaintOfst( 0 );
+ SwTwips nPaintOfst = rPaint.Left();
+
+ // nPaintOfst wurde exakt auf das Ende eingestellt, deswegen <=
+ // nPaintOfst ist dokumentglobal, deswegen nLeftMar aufaddieren
+ // const KSHORT nLeftMar = KSHORT(GetLeftMargin());
+ // 8310: painten von LineBreaks in leeren Zeilen.
+ if( nPaintOfst && pCurr->Width() )
+ {
+ SwLinePortion *pLast = 0;
+ // 7529 und 4757: nicht <= nPaintOfst
+ while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
+ < nPaintOfst )
+ {
+ DBG_LOOP;
+ if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
+ {
+ long nTmp = GetInfo().X() +pPor->Width() +
+ pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
+ if( nTmp + (pPor->Height()/2) >= nPaintOfst )
+ break;
+ GetInfo().X( nTmp );
+ GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
+ }
+ else
+ pPor->Move( GetInfo() );
+ pLast = pPor;
+ pPor = pPor->GetPortion();
+ }
+
+ // 7529: bei PostIts auch pLast returnen.
+ if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
+ {
+ pPor = pLast;
+ GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
+ }
+ }
+ return pPor;
+}
+
+/*************************************************************************
+ * SwTxtPainter::DrawTextLine()
+ *
+ * Es gibt zwei Moeglichkeiten bei transparenten Font auszugeben:
+ * 1) DrawRect auf die ganze Zeile und die DrawText hinterher
+ * (objektiv schnell, subjektiv langsam).
+ * 2) Fuer jede Portion ein DrawRect mit anschliessendem DrawText
+ * ausgefuehrt (objektiv langsam, subjektiv schnell).
+ * Da der User in der Regel subjektiv urteilt, wird die 2. Methode
+ * als Default eingestellt.
+ *************************************************************************/
+void SwTxtPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
+ const sal_Bool bUnderSz )
+{
+#if OSL_DEBUG_LEVEL > 1
+// USHORT nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
+// USHORT nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
+#endif
+
+ // Adjustierung ggf. nachholen
+ GetAdjusted();
+ GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
+ GetInfo().ResetSpaceIdx();
+ GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
+ GetInfo().ResetKanaIdx();
+ // Die Groesse des Frames
+ GetInfo().SetIdx( GetStart() );
+ GetInfo().SetPos( GetTopLeft() );
+
+ const sal_Bool bDrawInWindow = GetInfo().OnWin();
+
+ // 6882: Leerzeilen duerfen nicht wegoptimiert werden bei Paragraphzeichen.
+ const sal_Bool bEndPor = GetInfo().GetOpt().IsParagraph() && !GetInfo().GetTxt().Len();
+
+ SwLinePortion *pPor = bEndPor ? pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
+
+ // Optimierung!
+ const SwTwips nMaxRight = Min( rPaint.Right(), Right() );
+ const SwTwips nTmpLeft = GetInfo().X();
+ if( !bEndPor && nTmpLeft >= nMaxRight )
+ return;
+
+ // DropCaps!
+ // 7538: natuerlich auch auf dem Drucker
+ if( !bPaintDrop )
+ {
+ // 8084: Optimierung, weniger Painten.
+ // AMA: Durch 8084 wurde 7538 wiederbelebt!
+ // bDrawInWindow entfernt, damit DropCaps auch gedruckt werden
+ bPaintDrop = pPor == pCurr->GetFirstPortion()
+ && GetDropLines() >= GetLineNr();
+ }
+
+ KSHORT nTmpHeight, nTmpAscent;
+ CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+
+ // bClip entscheidet darueber, ob geclippt werden muss.
+ // Das Ganze muss vor der Retusche stehen
+
+ sal_Bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg();
+ if( bClip && pPor )
+ {
+ // Wenn TopLeft oder BottomLeft der Line ausserhalb liegen,
+ // muss geclippt werden. Die Ueberpruefung auf Right() erfolgt
+ // in der folgenden Ausgabeschleife...
+
+ if( GetInfo().GetPos().X() < rPaint.Left() ||
+ GetInfo().GetPos().Y() < rPaint.Top() ||
+ GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
+ {
+ bClip = sal_False;
+ rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ static sal_Bool bClipAlways = sal_False;
+ if( bClip && bClipAlways )
+ { bClip = sal_False;
+ rClip.ChgClip( rPaint );
+ }
+#endif
+ }
+
+ // Alignment:
+ sal_Bool bPlus = sal_False;
+ OutputDevice* pOut = GetInfo().GetOut();
+ Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
+ if ( aPnt1.X() < rPaint.Left() )
+ aPnt1.X() = rPaint.Left();
+ if ( aPnt1.Y() < rPaint.Top() )
+ aPnt1.Y() = rPaint.Top();
+ Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
+ GetInfo().GetPos().Y() + nTmpHeight );
+ if ( aPnt2.X() > rPaint.Right() )
+ aPnt2.X() = rPaint.Right();
+ if ( aPnt2.Y() > rPaint.Bottom() )
+ {
+ aPnt2.Y() = rPaint.Bottom();
+ bPlus = sal_True;
+ }
+
+ const SwRect aLineRect( aPnt1, aPnt2 );
+
+ if( pCurr->IsClipping() )
+ {
+ rClip.ChgClip( aLineRect, pFrm );
+ bClip = sal_False;
+ }
+
+ if( !pPor && !bEndPor )
+ {
+#ifdef DBGTXT
+ aDbstream << "PAINTER: done nothing" << endl;
+#endif
+ return;
+ }
+
+ // Baseline-Ausgabe auch bei nicht-TxtPortions (vgl. TabPor mit Fill)
+ // if no special vertical alignment is used,
+ // we calculate Y value for the whole line
+ GETGRID( GetTxtFrm()->FindPageFrm() )
+ const sal_Bool bAdjustBaseLine =
+ GetLineInfo().HasSpecialAlign( GetTxtFrm()->IsVertical() ) ||
+ ( 0 != pGrid );
+ const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
+ if ( ! bAdjustBaseLine )
+ GetInfo().Y( nLineBaseLine );
+
+ // 7529: PostIts prepainten
+ if( GetInfo().OnWin() && pPor && !pPor->Width() )
+ {
+ SeekAndChg( GetInfo() );
+
+ if( bAdjustBaseLine )
+ {
+ const SwTwips nOldY = GetInfo().Y();
+
+ GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, 0,
+ GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
+ GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
+ ) );
+
+ pPor->PrePaint( GetInfo(), pPor );
+ GetInfo().Y( nOldY );
+ }
+ else
+ pPor->PrePaint( GetInfo(), pPor );
+ }
+
+ // 7923: EndPortions geben auch Zeichen aus, deswegen den Fnt wechseln!
+ if( bEndPor )
+ SeekStartAndChg( GetInfo() );
+
+ sal_Bool bRest = pCurr->IsRest();
+ sal_Bool bFirst = sal_True;
+
+ SwArrowPortion *pArrow = NULL;
+ // Reference portion for the paragraph end portion
+ SwLinePortion* pEndTempl = pCurr->GetFirstPortion();
+
+ while( pPor )
+ {
+ DBG_LOOP;
+ sal_Bool bSeeked = sal_True;
+ GetInfo().SetLen( pPor->GetLen() );
+
+ const SwTwips nOldY = GetInfo().Y();
+
+ if ( bAdjustBaseLine )
+ {
+ GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, pPor ) );
+
+ // we store the last portion, because a possible paragraph
+ // end character has the same font as this portion
+ // (only in special vertical alignment case, otherwise the first
+ // portion of the line is used)
+ if ( pPor->Width() && pPor->InTxtGrp() )
+ pEndTempl = pPor;
+ }
+
+ // Ein Sonderfall sind GluePortions, die Blanks ausgeben.
+
+ // 6168: Der Rest einer FldPortion zog sich die Attribute der naechsten
+ // Portion an, dies wird durch SeekAndChgBefore vermieden:
+ if( ( bRest && pPor->InFldGrp() && !pPor->GetLen() ) )
+ SeekAndChgBefore( GetInfo() );
+ else if ( pPor->IsQuoVadisPortion() )
+ {
+ xub_StrLen nOffset = GetInfo().GetIdx();
+ SeekStartAndChg( GetInfo(), sal_True );
+ if( GetRedln() && pCurr->HasRedline() )
+ GetRedln()->Seek( *pFnt, nOffset, 0 );
+ }
+ else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
+ SeekAndChg( GetInfo() );
+ else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
+ {
+ // Paragraphzeichen sollten den gleichen Font wie das Zeichen vor
+ // haben, es sei denn, es gibt Redlining in dem Absatz.
+ if( GetRedln() )
+ SeekAndChg( GetInfo() );
+ else
+ SeekAndChgBefore( GetInfo() );
+ }
+ else
+ bSeeked = sal_False;
+
+// bRest = sal_False;
+
+ // Wenn das Ende der Portion hinausragt, wird geclippt.
+ // Es wird ein Sicherheitsabstand von Height-Halbe aufaddiert,
+ // damit die TTF-"f" nicht im Seitenrand haengen...
+ if( bClip &&
+ GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
+ {
+ bClip = sal_False;
+ rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
+ }
+
+ // Portions, die "unter" dem Text liegen wie PostIts
+ SwLinePortion *pNext = pPor->GetPortion();
+ if( GetInfo().OnWin() && pNext && !pNext->Width() )
+ {
+ // Fix 11289: Felder waren hier ausgeklammert wg. Last!=Owner beim
+ // Laden von Brief.sdw. Jetzt sind die Felder wieder zugelassen,
+ // durch bSeeked wird Last!=Owner vermieden.
+ if ( !bSeeked )
+ SeekAndChg( GetInfo() );
+ pNext->PrePaint( GetInfo(), pPor );
+ }
+
+ // We calculate a separate font for underlining.
+ CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
+ SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
+ if ( pUnderLineFnt )
+ {
+ const Point aTmpPoint( GetInfo().X(),
+ bAdjustBaseLine ?
+ pUnderLineFnt->GetPos().Y() :
+ nLineBaseLine );
+ pUnderLineFnt->SetPos( aTmpPoint );
+ }
+
+
+ // in extended input mode we do not want a common underline font.
+ SwUnderlineFont* pOldUnderLineFnt = 0;
+ if ( GetRedln() && GetRedln()->ExtOn() )
+ {
+ pOldUnderLineFnt = GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( 0 );
+ }
+
+ {
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ Por_Info aPorInfo( *pPor, *this );
+ SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, &aPorInfo, *pOut );
+ // <--
+
+ if( pPor->IsMultiPortion() )
+ PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor );
+ else
+ pPor->Paint( GetInfo() );
+ }
+
+ // reset underline font
+ if ( pOldUnderLineFnt )
+ GetInfo().SetUnderFnt( pOldUnderLineFnt );
+
+ // reset (for special vertical alignment)
+ GetInfo().Y( nOldY );
+
+ if( GetFnt()->IsURL() && pPor->InTxtGrp() )
+ GetInfo().NotifyURL( *pPor );
+
+ bFirst &= !pPor->GetLen();
+ if( pNext || !pPor->IsMarginPortion() )
+ pPor->Move( GetInfo() );
+ if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
+ pArrow = (SwArrowPortion*)pPor;
+
+ pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ ( GetInfo().GetVsh() &&
+ GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
+ pNext && pNext->IsHolePortion() ) ?
+ // <--
+ pNext :
+ 0;
+ }
+
+ // delete underline font
+ delete GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( 0 );
+
+ // paint remaining stuff
+ if( bDrawInWindow )
+ {
+ // If special vertical alignment is enabled, GetInfo().Y() is the
+ // top of the current line. Therefore is has to be adjusted for
+ // the painting of the remaining stuff. We first store the old value.
+ const SwTwips nOldY = GetInfo().Y();
+
+ if( !GetNextLine() &&
+ GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() &&
+ GetInfo().GetOpt().IsParagraph() && !GetTxtFrm()->GetFollow() &&
+ GetInfo().GetIdx() >= GetInfo().GetTxt().Len() )
+ {
+ const SwTmpEndPortion aEnd( *pEndTempl );
+ GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
+
+ if ( bAdjustBaseLine )
+ GetInfo().Y( GetInfo().GetPos().Y()
+ + AdjustBaseLine( *pCurr, &aEnd ) );
+
+ aEnd.Paint( GetInfo() );
+ GetInfo().Y( nOldY );
+ }
+ if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() )
+ {
+ const sal_Bool bNextUndersized =
+ ( GetTxtFrm()->GetNext() &&
+ 0 == GetTxtFrm()->GetNext()->Prt().Height() &&
+ GetTxtFrm()->GetNext()->IsTxtFrm() &&
+ ((SwTxtFrm*)GetTxtFrm()->GetNext())->IsUndersized() ) ;
+
+ if( bUnderSz || bNextUndersized )
+ {
+ if ( bAdjustBaseLine )
+ GetInfo().Y( GetInfo().GetPos().Y() + pCurr->GetAscent() );
+
+ if( pArrow )
+ GetInfo().DrawRedArrow( *pArrow );
+
+ // GetInfo().Y() must be current baseline.
+ SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTxtFrm()->Frm().Bottom();
+ if( ( nDiff > 0 &&
+ ( GetEnd() < GetInfo().GetTxt().Len() ||
+ ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
+ nDiff >= 0 && bNextUndersized )
+
+ {
+ SwArrowPortion aArrow( GetInfo() );
+ GetInfo().DrawRedArrow( aArrow );
+ }
+
+ GetInfo().Y( nOldY );
+ }
+ }
+ }
+
+ if( pCurr->IsClipping() )
+ rClip.ChgClip( rPaint, pFrm );
+}
+
+void SwTxtPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
+ long nAdjustBaseLine )
+{
+ // Check if common underline should not be continued.
+ if ( IsUnderlineBreak( *pPor, *pFnt ) )
+ {
+ // delete underline font
+ delete GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( 0 );
+ return;
+ }
+
+ // If current underline matches the common underline font, we continue
+ // to use the common underline font.
+ if ( GetInfo().GetUnderFnt() &&
+ GetInfo().GetUnderFnt()->GetFont().GetUnderline() ==
+ GetFnt()->GetUnderline() )
+ return;
+
+ // calculate the new common underline font
+ SwFont* pUnderlineFnt = 0;
+ Point aCommonBaseLine;
+
+ Range aRange( 0, GetInfo().GetTxt().Len() );
+ MultiSelection aUnderMulti( aRange );
+
+ ASSERT( GetFnt() && UNDERLINE_NONE != GetFnt()->GetUnderline(),
+ "CheckSpecialUnderline without underlined font" )
+ const SwFont* pParaFnt = GetAttrHandler().GetFont();
+ if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
+ aUnderMulti.SelectAll();
+
+ SwTxtAttr* pTxtAttr;
+ if( HasHints() )
+ {
+ sal_Bool bUnder = sal_False;
+ MSHORT nTmp = 0;
+
+ while( nTmp < pHints->GetStartCount() )
+ {
+ pTxtAttr = pHints->GetStart( nTmp++ );
+ sal_Bool bUnderSelect = sal_False;
+
+ const SvxUnderlineItem* pItem =
+ static_cast<const SvxUnderlineItem*>(CharFmt::GetItem( *pTxtAttr, RES_CHRATR_UNDERLINE ));
+
+ if ( pItem )
+ {
+ bUnder = sal_True;
+ bUnderSelect = pFnt->GetUnderline() == pItem->GetLineStyle();
+ }
+
+ if( bUnder )
+ {
+ xub_StrLen nSt = *pTxtAttr->GetStart();
+ xub_StrLen nEnd = *pTxtAttr->GetEnd();
+ if( nEnd > nSt )
+ {
+ Range aTmp( nSt, nEnd - 1 );
+ if( bUnder )
+ aUnderMulti.Select( aTmp, bUnderSelect );
+ }
+ bUnder = sal_False;
+ }
+ }
+ }
+
+ MSHORT i;
+ xub_StrLen nIndx = GetInfo().GetIdx();
+ long nUnderStart = 0;
+ long nUnderEnd = 0;
+ MSHORT nCnt = (MSHORT)aUnderMulti.GetRangeCount();
+
+ // find the underline range the current portion is contained in
+ for( i = 0; i < nCnt; ++i )
+ {
+ const Range& rRange = aUnderMulti.GetRange( i );
+ if( nUnderEnd == rRange.Min() )
+ nUnderEnd = rRange.Max();
+ else if( nIndx >= rRange.Min() )
+ {
+ nUnderStart = rRange.Min();
+ nUnderEnd = rRange.Max();
+ }
+ else
+ break;
+ }
+
+ // restrict start and end to current line
+ if ( GetStart() > nUnderStart )
+ nUnderStart = GetStart();
+
+ if ( GetEnd() && GetEnd() <= nUnderEnd )
+ nUnderEnd = GetEnd() - 1;
+
+
+ // check, if underlining is not isolated
+ if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 )
+ {
+ //
+ // here starts the algorithm for calculating the underline font
+ //
+ SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
+ SwAttrIter aIter( *(SwTxtNode*)GetInfo().GetTxtFrm()->GetTxtNode(),
+ rScriptInfo );
+
+ xub_StrLen nTmpIdx = nIndx;
+ ULONG nSumWidth = 0;
+ ULONG nSumHeight = 0;
+ ULONG nBold = 0;
+ USHORT nMaxBaseLineOfst = 0;
+ USHORT nNumberOfPortions = 0;
+
+ while( nTmpIdx <= nUnderEnd && pPor )
+ {
+ if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
+ pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
+ pPor->IsHolePortion() ||
+ ( pPor->IsMultiPortion() && ! ((SwMultiPortion*)pPor)->IsBidi() ) )
+ break;
+
+ aIter.Seek( nTmpIdx );
+
+ if ( aIter.GetFnt()->GetEscapement() < 0 || pFnt->IsWordLineMode() ||
+ SVX_CASEMAP_KAPITAELCHEN == pFnt->GetCaseMap() )
+ break;
+
+ if ( !aIter.GetFnt()->GetEscapement() )
+ {
+ nSumWidth += pPor->Width();
+ const ULONG nFontHeight = aIter.GetFnt()->GetHeight();
+
+ // If we do not have a common baseline we take the baseline
+ // and the font of the lowest portion.
+ if ( nAdjustBaseLine )
+ {
+ USHORT nTmpBaseLineOfst = AdjustBaseLine( *pCurr, pPor );
+ if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
+ {
+ nMaxBaseLineOfst = nTmpBaseLineOfst;
+ nSumHeight = nFontHeight;
+ }
+ }
+ // in horizontal layout we build a weighted sum of the heights
+ else
+ nSumHeight += pPor->Width() * nFontHeight;
+
+ if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
+ nBold += pPor->Width();
+ }
+
+ ++nNumberOfPortions;
+
+ nTmpIdx = nTmpIdx + pPor->GetLen();
+ pPor = pPor->GetPortion();
+ }
+
+ // resulting height
+ if ( nNumberOfPortions > 1 && nSumWidth )
+ {
+ const ULONG nNewFontHeight = nAdjustBaseLine ?
+ nSumHeight :
+ nSumHeight / nSumWidth;
+
+ pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
+
+ // font height
+ const BYTE nActual = pUnderlineFnt->GetActual();
+ pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
+ nNewFontHeight ), nActual );
+
+ // font weight
+ if ( 2 * nBold > nSumWidth )
+ pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
+ else
+ pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
+
+ // common base line
+ aCommonBaseLine.Y() = nAdjustBaseLine + nMaxBaseLineOfst;
+ }
+ }
+
+ // an escaped redlined portion should also have a special underlining
+ if( ! pUnderlineFnt && pFnt->GetEscapement() > 0 && GetRedln() &&
+ GetRedln()->ChkSpecialUnderline() )
+ pUnderlineFnt = new SwFont( *pFnt );
+
+ delete GetInfo().GetUnderFnt();
+
+ if ( pUnderlineFnt )
+ {
+ pUnderlineFnt->SetProportion( 100 );
+ pUnderlineFnt->SetEscapement( 0 );
+ pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
+ pUnderlineFnt->SetOverline( UNDERLINE_NONE );
+ const Color aFillColor( COL_TRANSPARENT );
+ pUnderlineFnt->SetFillColor( aFillColor );
+
+ GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt,
+ aCommonBaseLine ) );
+ }
+ else
+ // I'm sorry, we do not have a special underlining font for you.
+ GetInfo().SetUnderFnt( 0 );
+}
diff --git a/sw/source/core/text/itrpaint.hxx b/sw/source/core/text/itrpaint.hxx
new file mode 100644
index 000000000000..b7410d57d881
--- /dev/null
+++ b/sw/source/core/text/itrpaint.hxx
@@ -0,0 +1,69 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _ITRPAINT_HXX
+#define _ITRPAINT_HXX
+#include "itrtxt.hxx"
+
+class SwSaveClip; // SwTxtPainter
+class SwMultiPortion;
+
+/*************************************************************************
+ * class SwTxtPainter
+ *************************************************************************/
+
+class SwTxtPainter : public SwTxtCursor
+{
+ sal_Bool bPaintDrop;
+
+ SwLinePortion *CalcPaintOfst( const SwRect &rPaint );
+ void CheckSpecialUnderline( const SwLinePortion* pPor,
+ long nAdjustBaseLine = 0 );
+protected:
+ void CtorInitTxtPainter( SwTxtFrm *pFrm, SwTxtPaintInfo *pInf );
+ inline SwTxtPainter(SwTxtNode* pTxtNode) : SwTxtCursor(pTxtNode) { }
+
+public:
+ inline SwTxtPainter( SwTxtFrm *pTxtFrm, SwTxtPaintInfo *pTxtPaintInf ) : SwTxtCursor(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL)
+ { CtorInitTxtPainter( pTxtFrm, pTxtPaintInf ); }
+ void DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
+ const sal_Bool bUnderSz );
+ void PaintDropPortion();
+ // if PaintMultiPortion is called recursively, we have to pass the
+ // surrounding SwBidiPortion
+ void PaintMultiPortion( const SwRect &rPaint, SwMultiPortion& rMulti,
+ const SwMultiPortion* pEnvPor = 0 );
+ inline void SetPaintDrop( const sal_Bool bNew ) { bPaintDrop = bNew; }
+ inline sal_Bool IsPaintDrop() const { return bPaintDrop; }
+ inline SwTxtPaintInfo &GetInfo()
+ { return (SwTxtPaintInfo&)SwTxtIter::GetInfo(); }
+ inline const SwTxtPaintInfo &GetInfo() const
+ { return (const SwTxtPaintInfo&)SwTxtIter::GetInfo(); }
+};
+
+
+
+#endif
diff --git a/sw/source/core/text/itrtxt.cxx b/sw/source/core/text/itrtxt.cxx
new file mode 100644
index 000000000000..9ea46606945a
--- /dev/null
+++ b/sw/source/core/text/itrtxt.cxx
@@ -0,0 +1,523 @@
+/*************************************************************************
+ *
+ * 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 "ndtxt.hxx"
+#include "flyfrm.hxx"
+#include "paratr.hxx"
+#include "errhdl.hxx"
+#include <vcl/outdev.hxx>
+#include <editeng/paravertalignitem.hxx>
+
+#include "pormulti.hxx"
+#include <pagefrm.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <porfld.hxx>
+
+#include "txtcfg.hxx"
+#include "itrtxt.hxx"
+#include "txtfrm.hxx"
+#include "porfly.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+# include "txtfrm.hxx" // GetFrmID,
+#endif
+
+/*************************************************************************
+ * SwTxtIter::CtorInitTxtIter()
+ *************************************************************************/
+
+void SwTxtIter::CtorInitTxtIter( SwTxtFrm *pNewFrm, SwTxtInfo *pNewInf )
+{
+#ifdef DBGTXT
+ // nStopAt laesst sich vom CV bearbeiten.
+ static MSHORT nStopAt = 0;
+ if( nStopAt == pNewFrm->GetFrmId() )
+ {
+ int i = pNewFrm->GetFrmId();
+ }
+#endif
+
+ SwTxtNode *pNode = pNewFrm->GetTxtNode();
+
+ ASSERT( pNewFrm->GetPara(), "No paragraph" );
+
+ CtorInitAttrIter( *pNode, pNewFrm->GetPara()->GetScriptInfo(), pNewFrm );
+
+ pFrm = pNewFrm;
+ pInf = pNewInf;
+ // --> OD 2008-01-17 #newlistlevelattrs#
+ aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode );
+ // <--
+ nFrameStart = pFrm->Frm().Pos().Y() + pFrm->Prt().Pos().Y();
+ SwTxtIter::Init();
+ if( pNode->GetSwAttrSet().GetRegister().GetValue() )
+ bRegisterOn = pFrm->FillRegister( nRegStart, nRegDiff );
+ else
+ bRegisterOn = sal_False;
+}
+
+/*************************************************************************
+ * SwTxtIter::Init()
+ *************************************************************************/
+
+void SwTxtIter::Init()
+{
+ pCurr = pInf->GetParaPortion();
+ nStart = pInf->GetTxtStart();
+ nY = nFrameStart;
+ bPrev = sal_True;
+ pPrev = 0;
+ nLineNr = 1;
+}
+
+/*************************************************************************
+ * SwTxtIter::_GetHeightAndAscent()
+ *************************************************************************/
+
+void SwTxtIter::CalcAscentAndHeight( KSHORT &rAscent, KSHORT &rHeight ) const
+{
+ rHeight = GetLineHeight();
+ rAscent = pCurr->GetAscent() + rHeight - pCurr->Height();
+}
+
+/*************************************************************************
+ * SwTxtIter::_GetPrev()
+ *************************************************************************/
+
+SwLineLayout *SwTxtIter::_GetPrev()
+{
+ pPrev = 0;
+ bPrev = sal_True;
+ SwLineLayout *pLay = pInf->GetParaPortion();
+ if( pCurr == pLay )
+ return 0;
+ while( pLay->GetNext() != pCurr )
+ pLay = pLay->GetNext();
+ return pPrev = pLay;
+}
+
+/*************************************************************************
+ * SwTxtIter::GetPrev()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::GetPrev()
+{
+ if(! bPrev)
+ _GetPrev();
+ return pPrev;
+}
+
+/*************************************************************************
+ * SwTxtIter::Prev()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::Prev()
+{
+ if( !bPrev )
+ _GetPrev();
+ if( pPrev )
+ {
+ bPrev = sal_False;
+ pCurr = pPrev;
+ nStart = nStart - pCurr->GetLen();
+ nY = nY - GetLineHeight();
+ if( !pCurr->IsDummy() && !(--nLineNr) )
+ ++nLineNr;
+ return pCurr;
+ }
+ else
+ return 0;
+}
+
+/*************************************************************************
+ * SwTxtIter::Next()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::Next()
+{
+ if(pCurr->GetNext())
+ {
+ pPrev = pCurr;
+ bPrev = sal_True;
+ nStart = nStart + pCurr->GetLen();
+ nY += GetLineHeight();
+ if( pCurr->GetLen() || ( nLineNr>1 && !pCurr->IsDummy() ) )
+ ++nLineNr;
+ return pCurr = pCurr->GetNext();
+ }
+ else
+ return 0;
+}
+
+/*************************************************************************
+ * SwTxtIter::NextLine()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::NextLine()
+{
+ const SwLineLayout *pNext = Next();
+ while( pNext && pNext->IsDummy() && pNext->GetNext() )
+ {
+ DBG_LOOP;
+ pNext = Next();
+ }
+ return pNext;
+}
+
+/*************************************************************************
+ * SwTxtIter::GetNextLine()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::GetNextLine() const
+{
+ const SwLineLayout *pNext = pCurr->GetNext();
+ while( pNext && pNext->IsDummy() && pNext->GetNext() )
+ {
+ DBG_LOOP;
+ pNext = pNext->GetNext();
+ }
+ return (SwLineLayout*)pNext;
+}
+
+/*************************************************************************
+ * SwTxtIter::GetPrevLine()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::GetPrevLine()
+{
+ const SwLineLayout *pRoot = pInf->GetParaPortion();
+ if( pRoot == pCurr )
+ return 0;
+ const SwLineLayout *pLay = pRoot;
+
+ while( pLay->GetNext() != pCurr )
+ pLay = pLay->GetNext();
+
+ if( pLay->IsDummy() )
+ {
+ const SwLineLayout *pTmp = pRoot;
+ pLay = pRoot->IsDummy() ? 0 : pRoot;
+ while( pTmp->GetNext() != pCurr )
+ {
+ if( !pTmp->IsDummy() )
+ pLay = pTmp;
+ pTmp = pTmp->GetNext();
+ }
+ }
+
+ // Wenn sich nichts getan hat, dann gibt es nur noch Dummys
+ return (SwLineLayout*)pLay;
+}
+
+/*************************************************************************
+ * SwTxtIter::PrevLine()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::PrevLine()
+{
+ const SwLineLayout *pMyPrev = Prev();
+ if( !pMyPrev )
+ return 0;
+
+ const SwLineLayout *pLast = pMyPrev;
+ while( pMyPrev && pMyPrev->IsDummy() )
+ {
+ DBG_LOOP;
+ pLast = pMyPrev;
+ pMyPrev = Prev();
+ }
+ return (SwLineLayout*)(pMyPrev ? pMyPrev : pLast);
+}
+
+/*************************************************************************
+ * SwTxtIter::Bottom()
+ *************************************************************************/
+
+void SwTxtIter::Bottom()
+{
+ while( Next() )
+ {
+ DBG_LOOP;
+ }
+}
+
+/*************************************************************************
+ * SwTxtIter::CharToLine()
+ *************************************************************************/
+
+void SwTxtIter::CharToLine(const xub_StrLen nChar)
+{
+ while( nStart + pCurr->GetLen() <= nChar && Next() )
+ ;
+ while( nStart > nChar && Prev() )
+ ;
+}
+
+/*************************************************************************
+ * SwTxtIter::CharCrsrToLine()
+ *************************************************************************/
+
+// 1170: beruecksichtigt Mehrdeutigkeiten:
+const SwLineLayout *SwTxtCursor::CharCrsrToLine( const xub_StrLen nPosition )
+{
+ CharToLine( nPosition );
+ if( nPosition != nStart )
+ bRightMargin = sal_False;
+ sal_Bool bPrevious = bRightMargin && pCurr->GetLen() && GetPrev() &&
+ GetPrev()->GetLen();
+ if( bPrevious && nPosition && CH_BREAK == GetInfo().GetChar( nPosition-1 ) )
+ bPrevious = sal_False;
+ return bPrevious ? PrevLine() : pCurr;
+}
+
+/*************************************************************************
+ * SwTxtCrsr::AdjustBaseLine()
+ *************************************************************************/
+
+USHORT SwTxtCursor::AdjustBaseLine( const SwLineLayout& rLine,
+ const SwLinePortion* pPor,
+ USHORT nPorHeight, USHORT nPorAscent,
+ const sal_Bool bAutoToCentered ) const
+{
+ if ( pPor )
+ {
+ nPorHeight = pPor->Height();
+ nPorAscent = pPor->GetAscent();
+ }
+
+ USHORT nOfst = rLine.GetRealHeight() - rLine.Height();
+
+ GETGRID( pFrm->FindPageFrm() )
+ const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
+
+ if ( bHasGrid )
+ {
+ const USHORT nRubyHeight = pGrid->GetRubyHeight();
+ const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow();
+
+ if ( GetInfo().IsMulti() )
+ // we are inside the GetCharRect recursion for multi portions
+ // we center the portion in its surrounding line
+ nOfst = ( pCurr->Height() - nPorHeight ) / 2 + nPorAscent;
+ else
+ {
+ // We have to take care for ruby portions.
+ // The ruby portion is NOT centered
+ nOfst = nOfst + nPorAscent;
+
+ if ( ! pPor || ! pPor->IsMultiPortion() ||
+ ! ((SwMultiPortion*)pPor)->IsRuby() )
+ {
+ // Portions which are bigger than on grid distance are
+ // centered inside the whole line.
+
+ //for text refactor
+ const USHORT nLineNetto = rLine.Height() - nRubyHeight;
+ //const USHORT nLineNetto = ( nPorHeight > nGridWidth ) ?
+ // rLine.Height() - nRubyHeight :
+ // nGridWidth;
+ nOfst += ( nLineNetto - nPorHeight ) / 2;
+ if ( bRubyTop )
+ nOfst = nOfst + nRubyHeight;
+ }
+ }
+ }
+ else
+ {
+ switch ( GetLineInfo().GetVertAlign() ) {
+ case SvxParaVertAlignItem::TOP :
+ nOfst = nOfst + nPorAscent;
+ break;
+ case SvxParaVertAlignItem::CENTER :
+ ASSERT( rLine.Height() >= nPorHeight, "Portion height > Line height");
+ nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
+ break;
+ case SvxParaVertAlignItem::BOTTOM :
+ nOfst += rLine.Height() - nPorHeight + nPorAscent;
+ break;
+ case SvxParaVertAlignItem::AUTOMATIC :
+ if ( bAutoToCentered || GetInfo().GetTxtFrm()->IsVertical() )
+ {
+ nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
+ break;
+ }
+ case SvxParaVertAlignItem::BASELINE :
+ // base line
+ nOfst = nOfst + rLine.GetAscent();
+ break;
+ }
+ }
+
+ return nOfst;
+}
+
+/*************************************************************************
+ * SwTxtIter::TwipsToLine()
+ *************************************************************************/
+
+const SwLineLayout *SwTxtIter::TwipsToLine( const SwTwips y)
+{
+ while( nY + GetLineHeight() <= y && Next() )
+ ;
+ while( nY > y && Prev() )
+ ;
+ return pCurr;
+}
+
+//
+// Local helper function to check, if pCurr needs a field rest portion:
+//
+sal_Bool lcl_NeedsFieldRest( const SwLineLayout* pCurr )
+{
+ const SwLinePortion *pPor = pCurr->GetPortion();
+ sal_Bool bRet = sal_False;
+ while( pPor && !bRet )
+ {
+ bRet = pPor->InFldGrp() && ((SwFldPortion*)pPor)->HasFollow();
+ if( !pPor->GetPortion() || !pPor->GetPortion()->InFldGrp() )
+ break;
+ pPor = pPor->GetPortion();
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtIter::TruncLines()
+ *************************************************************************/
+
+void SwTxtIter::TruncLines( sal_Bool bNoteFollow )
+{
+ SwLineLayout *pDel = pCurr->GetNext();
+ const xub_StrLen nEnd = nStart + pCurr->GetLen();
+
+ if( pDel )
+ {
+ pCurr->SetNext( 0 );
+ if( GetHints() && bNoteFollow )
+ {
+ GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() ||
+ lcl_NeedsFieldRest( pCurr ) );
+
+ // bug 88534: wrong positioning of flys
+ SwTxtFrm* pFollow = GetTxtFrm()->GetFollow();
+ if ( pFollow && ! pFollow->IsLocked() &&
+ nEnd == pFollow->GetOfst() )
+ {
+ xub_StrLen nRangeEnd = nEnd;
+ SwLineLayout* pLine = pDel;
+
+ // determine range to be searched for flys anchored as characters
+ while ( pLine )
+ {
+ nRangeEnd = nRangeEnd + pLine->GetLen();
+ pLine = pLine->GetNext();
+ }
+
+ SwpHints* pTmpHints = GetTxtFrm()->GetTxtNode()->GetpSwpHints();
+
+ // examine hints in range nEnd - (nEnd + nRangeChar)
+ for( USHORT i = 0; i < pTmpHints->Count(); i++ )
+ {
+ const SwTxtAttr* pHt = pTmpHints->GetTextHint( i );
+ if( RES_TXTATR_FLYCNT == pHt->Which() )
+ {
+ // check, if hint is in our range
+ const USHORT nTmpPos = *pHt->GetStart();
+ if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd )
+ pFollow->_InvalidateRange(
+ SwCharRange( nTmpPos, nTmpPos ), 0 );
+ }
+ }
+ }
+ }
+ delete pDel;
+ }
+ if( pCurr->IsDummy() &&
+ !pCurr->GetLen() &&
+ nStart < GetTxtFrm()->GetTxt().Len() )
+ pCurr->SetRealHeight( 1 );
+ if( GetHints() )
+ pFrm->RemoveFtn( nEnd );
+}
+
+/*************************************************************************
+ * SwTxtIter::CntHyphens()
+ *************************************************************************/
+
+void SwTxtIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const
+{
+ nEndCnt = 0;
+ nMidCnt = 0;
+ if ( bPrev && pPrev && !pPrev->IsEndHyph() && !pPrev->IsMidHyph() )
+ return;
+ SwLineLayout *pLay = pInf->GetParaPortion();
+ if( pCurr == pLay )
+ return;
+ while( pLay != pCurr )
+ {
+ DBG_LOOP;
+ if ( pLay->IsEndHyph() )
+ nEndCnt++;
+ else
+ nEndCnt = 0;
+ if ( pLay->IsMidHyph() )
+ nMidCnt++;
+ else
+ nMidCnt = 0;
+ pLay = pLay->GetNext();
+ }
+}
+
+/*************************************************************************
+ * SwHookOut
+ *
+ * Change current output device to formatting device, this has to be done before
+ * formatting.
+ *************************************************************************/
+
+SwHookOut::SwHookOut( SwTxtSizeInfo& rInfo ) :
+ pInf( &rInfo ),
+ pOut( rInfo.GetOut() ),
+ bOnWin( rInfo.OnWin() )
+{
+ ASSERT( rInfo.GetRefDev(), "No reference device for text formatting" )
+
+ // set new values
+ rInfo.SetOut( rInfo.GetRefDev() );
+ rInfo.SetOnWin( sal_False );
+}
+
+SwHookOut::~SwHookOut()
+{
+ pInf->SetOut( pOut );
+ pInf->SetOnWin( bOnWin );
+}
diff --git a/sw/source/core/text/itrtxt.hxx b/sw/source/core/text/itrtxt.hxx
new file mode 100644
index 000000000000..2ea324539f32
--- /dev/null
+++ b/sw/source/core/text/itrtxt.hxx
@@ -0,0 +1,340 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _ITRTXT_HXX
+#define _ITRTXT_HXX
+#include "swtypes.hxx"
+#include "itratr.hxx"
+#include "inftxt.hxx"
+
+class SwTxtFrm;
+struct SwPosition;
+struct SwCrsrMoveState;
+class SwMarginPortion;
+class SwFlyPortion;
+
+/*************************************************************************
+ * class SwTxtIter
+ *************************************************************************/
+
+class SwTxtIter : public SwAttrIter
+{
+protected:
+ SwLineInfo aLineInf;
+ SwTxtFrm *pFrm;
+ SwTxtInfo *pInf;
+ SwLineLayout *pCurr;
+ SwLineLayout *pPrev;
+ SwTwips nFrameStart;
+ SwTwips nY;
+ SwTwips nRegStart; // Anfangsposition (Y) des Registers
+ xub_StrLen nStart; // Start im Textstring, Ende = pCurr->GetLen()
+ KSHORT nRegDiff; // Zeilenabstand des Registers
+ MSHORT nLineNr; // Zeilennummer
+ sal_Bool bPrev : 1;
+ sal_Bool bRegisterOn : 1; // Registerhaltigkeit
+ sal_Bool bOneBlock : 1; // Blocksatz: Einzelwoerter austreiben
+ sal_Bool bLastBlock : 1; // Blocksatz: Auch die letzte Zeile
+ sal_Bool bLastCenter : 1; // Blocksatz: Letzte Zeile zentrieren
+
+ SwLineLayout *_GetPrev();
+
+ // Zuruecksetzen in die erste Zeile.
+ void Init();
+ void CtorInitTxtIter( SwTxtFrm *pFrm, SwTxtInfo *pInf );
+ inline SwTxtIter(SwTxtNode* pTxtNode) : SwAttrIter(pTxtNode) { }
+
+public:
+ inline SwTxtIter( SwTxtFrm *pTxtFrm, SwTxtInfo *pTxtInf ) : SwAttrIter(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL)
+ { CtorInitTxtIter( pTxtFrm, pTxtInf ); }
+ inline const SwLineLayout *GetCurr() const { return pCurr; } // niemals 0!
+ inline const SwLineLayout *GetNext() const { return pCurr->GetNext(); }
+ const SwLineLayout *GetPrev();
+ inline xub_StrLen GetLength() const { return pCurr->GetLen(); }
+ inline MSHORT GetLineNr() const { return nLineNr; }
+ inline xub_StrLen GetStart() const { return nStart; }
+ inline xub_StrLen GetEnd() const { return GetStart() + GetLength(); }
+ inline SwTwips Y() const { return nY; }
+
+ inline SwTwips RegStart() const { return nRegStart; }
+ inline KSHORT RegDiff() const { return nRegDiff; }
+ inline sal_Bool IsRegisterOn() const { return bRegisterOn; }
+
+ inline SwTxtInfo &GetInfo() { return *pInf; }
+ inline const SwTxtInfo &GetInfo() const { return *pInf; }
+
+ inline void Top() { Init(); }
+ void Bottom();
+ const SwLineLayout *Next();
+ const SwLineLayout *Prev();
+
+ // Ueberspringt die Dummyzeilen der FlyFrms
+ const SwLineLayout *NextLine();
+ const SwLineLayout *PrevLine();
+ const SwLineLayout *GetNextLine() const;
+ const SwLineLayout *GetPrevLine();
+
+ void CharToLine( const xub_StrLen );
+ const SwLineLayout *TwipsToLine(const SwTwips);
+
+ // schneidet ab pCurr alle ab.
+ void TruncLines( sal_Bool bNoteFollow = sal_False );
+
+ inline KSHORT GetLineHeight() const { return pCurr->GetRealHeight(); }
+ void CalcAscentAndHeight( KSHORT &rAscent, KSHORT &rHeight ) const;
+
+ // 5298, viel Aerger durch die Abfrage auf pCurr == pPara
+ inline sal_Bool IsFirstTxtLine() const
+ { return nStart == GetInfo().GetTxtStart() &&
+ !( pCurr->IsDummy() && GetNextLine() ); }
+
+ // Als Ersatz fuer das alte IsFirstLine()
+ inline sal_Bool IsParaLine() const
+ { return pCurr == pInf->GetParaPortion(); }
+
+ const SwLineInfo &GetLineInfo() const { return aLineInf; }
+ inline SwTwips GetFirstPos() const { return nFrameStart; }
+ inline sal_Bool SeekAndChg( SwTxtSizeInfo &rInf );
+ inline sal_Bool SeekAndChgBefore( SwTxtSizeInfo &rInf );
+ inline sal_Bool SeekStartAndChg( SwTxtSizeInfo &rInf, const sal_Bool bPara=sal_False );
+
+ inline SwTxtFrm *GetTxtFrm() { return pFrm; }
+ inline const SwTxtFrm *GetTxtFrm() const { return pFrm; }
+
+ // zaehlt aufeinanderfolgende Trennungen, um MaxHyphens einzuhalten
+ void CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const;
+};
+
+/*************************************************************************
+ * class SwTxtMargin
+ *************************************************************************/
+
+class SwTxtMargin : public SwTxtIter
+{
+private:
+ SwTwips nLeft;
+ SwTwips nRight;
+ SwTwips nFirst;
+ KSHORT nDropLeft;
+ KSHORT nDropHeight;
+ KSHORT nDropDescent;
+ MSHORT nDropLines;
+ MSHORT nAdjust;
+ // --> OD 2008-06-30 #i91133#
+ SwTwips mnTabLeft;
+ // <--
+
+protected:
+ // fuer FormatQuoVadis
+ inline void Right( const SwTwips nNew ) { nRight = nNew; }
+ // fuer CalcFlyAdjust
+ inline void SetDropLeft( const KSHORT nNew ) { nDropLeft = nNew; }
+
+ void CtorInitTxtMargin( SwTxtFrm *pFrm, SwTxtSizeInfo *pInf );
+ inline SwTxtMargin(SwTxtNode* pTxtNode) : SwTxtIter(pTxtNode) { }
+public:
+ inline SwTxtMargin( SwTxtFrm *pTxtFrm, SwTxtSizeInfo *pTxtSizeInf ) : SwTxtIter(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL)
+ { CtorInitTxtMargin( pTxtFrm, pTxtSizeInf ); }
+ inline SwTwips GetLeftMargin() const;
+ inline SwTwips Left() const;
+ inline SwTwips Right() const { return nRight; }
+ inline SwTwips FirstLeft() const { return nFirst; }
+ inline SwTwips CurrWidth() const { return pCurr->PrtWidth(); }
+ SwTwips GetLineStart() const;
+ inline SwTwips GetLineEnd() const { return GetLineStart() + CurrWidth(); }
+ inline Point GetTopLeft() const { return Point( GetLineStart(), Y() ); }
+ inline sal_Bool IsOneBlock() const { return bOneBlock; }
+ inline sal_Bool IsLastBlock() const { return bLastBlock; }
+ inline sal_Bool IsLastCenter() const { return bLastCenter; }
+ inline MSHORT GetAdjust() const { return nAdjust; }
+ inline KSHORT GetLineWidth() const
+ { return KSHORT( Right() - GetLeftMargin() + 1 ); }
+ inline SwTwips GetLeftMin() const { return nFirst < nLeft ? nFirst : nLeft; }
+ inline sal_Bool HasNegFirst() const { return nFirst < nLeft; }
+
+ // --> OD 2008-06-30 #i91133#
+ inline SwTwips GetTabLeft() const
+ {
+ return mnTabLeft;
+ }
+ // <--
+ // DropCaps
+ inline MSHORT GetDropLines() const { return nDropLines; }
+ inline void SetDropLines( const MSHORT nNew ) { nDropLines = nNew; }
+ inline KSHORT GetDropLeft() const { return nDropLeft; }
+ inline KSHORT GetDropHeight() const { return nDropHeight; }
+ inline void SetDropHeight( const KSHORT nNew ) { nDropHeight = nNew; }
+ inline KSHORT GetDropDescent() const { return nDropDescent; }
+ inline void SetDropDescent( const KSHORT nNew ) { nDropDescent = nNew; }
+ void DropInit();
+
+ // liefert TxtPos fuer Start und Ende der aktuellen Zeile ohne whitespaces
+ // In frminf.cxx implementiert.
+ xub_StrLen GetTxtStart() const;
+ xub_StrLen GetTxtEnd() const;
+
+ inline SwTxtSizeInfo &GetInfo()
+ { return (SwTxtSizeInfo&)SwTxtIter::GetInfo(); }
+ inline const SwTxtSizeInfo &GetInfo() const
+ { return (const SwTxtSizeInfo&)SwTxtIter::GetInfo(); }
+
+};
+
+
+/*************************************************************************
+ * class SwTxtAdjuster
+ *************************************************************************/
+
+class SwTxtAdjuster : public SwTxtMargin
+{
+ // Gleicht die Portions aus, wenn Adjustment und FlyFrms vorliegen.
+ void CalcFlyAdjust( SwLineLayout *pCurr );
+
+ // ruft SplitGlues und CalcBlockAdjust
+ void FormatBlock( );
+
+ // Erstellt bei kurzen Zeilen die Glue-Kette.
+ SwMarginPortion* CalcRightMargin( SwLineLayout *pCurr, SwTwips nReal = 0 );
+
+ // Berechnung des Adjustments (FlyPortions)
+ SwFlyPortion *CalcFlyPortion( const long nRealWidth,
+ const SwRect &rCurrRect );
+
+protected:
+ inline SwTxtAdjuster(SwTxtNode* pTxtNode) : SwTxtMargin(pTxtNode) { }
+ // spannt beim Blocksatz die Glues auf.
+ void CalcNewBlock( SwLineLayout *pCurr, const SwLinePortion *pStopAt,
+ SwTwips nReal = 0, bool bSkipKashida = false );
+ SwTwips CalcKanaAdj( SwLineLayout *pCurr );
+public:
+ inline SwTxtAdjuster( SwTxtFrm *pTxtFrm, SwTxtSizeInfo *pTxtSizeInf ) : SwTxtMargin(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL)
+ { CtorInitTxtMargin( pTxtFrm, pTxtSizeInf ); }
+
+ // wird von SwTxtFormatter wegen UpdatePos ueberladen
+ void CalcAdjLine( SwLineLayout *pCurr );
+
+ // sorgt fuer das nachtraegliche adjustieren
+ inline void GetAdjusted() const
+ {
+ if( pCurr->IsFormatAdj() )
+ ((SwTxtAdjuster*)this)->CalcAdjLine( pCurr );
+ }
+
+ // DropCaps-Extrawurst
+ void CalcDropAdjust();
+ void CalcDropRepaint();
+};
+
+/*************************************************************************
+ * class SwTxtCursor
+ *************************************************************************/
+
+class SwTxtCursor : public SwTxtAdjuster
+{
+ // A small helper-class to save SwTxtCursor member, manipulate them
+ // and to restore them
+ friend class SwTxtCursorSave;
+
+ // 1170: Mehrdeutigkeiten
+ static sal_Bool bRightMargin;
+ void _GetCharRect(SwRect *, const xub_StrLen, SwCrsrMoveState* );
+protected:
+ void CtorInitTxtCursor( SwTxtFrm *pFrm, SwTxtSizeInfo *pInf );
+ inline SwTxtCursor(SwTxtNode* pTxtNode) : SwTxtAdjuster(pTxtNode) { }
+public:
+ inline SwTxtCursor( SwTxtFrm *pTxtFrm, SwTxtSizeInfo *pTxtSizeInf ) : SwTxtAdjuster(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL)
+ { CtorInitTxtCursor( pTxtFrm, pTxtSizeInf ); }
+ sal_Bool GetCharRect(SwRect *, const xub_StrLen, SwCrsrMoveState* = 0,
+ const long nMax = 0 );
+ sal_Bool GetEndCharRect(SwRect *, const xub_StrLen, SwCrsrMoveState* = 0,
+ const long nMax = 0 );
+ xub_StrLen GetCrsrOfst( SwPosition *pPos, const Point &rPoint,
+ const MSHORT nChgNode, SwCrsrMoveState* = 0 ) const;
+ // 1170: beruecksichtigt Mehrdeutigkeiten; Implementierung s.u.
+ const SwLineLayout *CharCrsrToLine( const xub_StrLen nPos );
+
+ // calculates baseline for portion rPor
+ // bAutoToCentered indicates, if AUTOMATIC mode means CENTERED or BASELINE
+ USHORT AdjustBaseLine( const SwLineLayout& rLine, const SwLinePortion* pPor,
+ USHORT nPorHeight = 0, USHORT nAscent = 0,
+ const sal_Bool bAutoToCentered = sal_False ) const;
+
+ static inline void SetRightMargin( const sal_Bool bNew ){ bRightMargin = bNew; }
+ static inline sal_Bool IsRightMargin() { return bRightMargin; }
+};
+
+/*************************************************************************
+ * SwHookOut
+ *
+ * Change current output device to printer, this has to be done before
+ * formatting.
+ *************************************************************************/
+
+class SwHookOut
+{
+ SwTxtSizeInfo* pInf;
+ OutputDevice* pOut;
+ sal_Bool bOnWin;
+public:
+ SwHookOut( SwTxtSizeInfo& rInfo );
+ ~SwHookOut();
+};
+
+/*************************************************************************
+ * Inline-Implementierungen
+ *************************************************************************/
+
+inline sal_Bool SwTxtIter::SeekAndChg( SwTxtSizeInfo &rInf )
+{
+ return SeekAndChgAttrIter( rInf.GetIdx(), rInf.GetOut() );
+}
+
+inline sal_Bool SwTxtIter::SeekAndChgBefore( SwTxtSizeInfo &rInf )
+{
+ if ( rInf.GetIdx() )
+ return SeekAndChgAttrIter( rInf.GetIdx()-1, rInf.GetOut() );
+ else
+ return SeekAndChgAttrIter( rInf.GetIdx(), rInf.GetOut() );
+}
+
+inline sal_Bool SwTxtIter::SeekStartAndChg( SwTxtSizeInfo &rInf, const sal_Bool bPara )
+{
+ return SeekStartAndChgAttrIter( rInf.GetOut(), bPara );
+}
+
+inline SwTwips SwTxtMargin::GetLeftMargin() const
+{
+ return IsFirstTxtLine() ? nFirst : Left();
+}
+
+inline SwTwips SwTxtMargin::Left() const
+{
+ return (nDropLines >= nLineNr && 1 != nLineNr) ? nFirst + nDropLeft : nLeft;
+}
+
+
+
+#endif
diff --git a/sw/source/core/text/makefile.mk b/sw/source/core/text/makefile.mk
new file mode 100644
index 000000000000..0076a1748741
--- /dev/null
+++ b/sw/source/core/text/makefile.mk
@@ -0,0 +1,119 @@
+#*************************************************************************
+#
+# 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.
+#
+#*************************************************************************
+PRJ=..$/..$/..
+
+PRJNAME=sw
+TARGET=text
+
+AUTOSEG=true
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : $(PRJ)$/inc$/swpre.mk
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/inc$/sw.mk
+
+.IF "$(mydebug)" != ""
+CDEFS+=-Dmydebug
+.ENDIF
+
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+# --- Files --------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/atrstck.obj \
+ $(SLO)$/EnhancedPDFExportHelper.obj \
+ $(SLO)$/frmcrsr.obj \
+ $(SLO)$/frmform.obj \
+ $(SLO)$/frminf.obj \
+ $(SLO)$/frmpaint.obj \
+ $(SLO)$/guess.obj \
+ $(SLO)$/inftxt.obj \
+ $(SLO)$/itradj.obj \
+ $(SLO)$/itratr.obj \
+ $(SLO)$/itrcrsr.obj \
+ $(SLO)$/itrform2.obj \
+ $(SLO)$/itrpaint.obj \
+ $(SLO)$/itrtxt.obj \
+ $(SLO)$/porexp.obj \
+ $(SLO)$/porfld.obj \
+ $(SLO)$/porfly.obj \
+ $(SLO)$/porglue.obj \
+ $(SLO)$/porlay.obj \
+ $(SLO)$/porlin.obj \
+ $(SLO)$/pormulti.obj \
+ $(SLO)$/porref.obj \
+ $(SLO)$/porrst.obj \
+ $(SLO)$/portox.obj \
+ $(SLO)$/portxt.obj \
+ $(SLO)$/redlnitr.obj \
+ $(SLO)$/txtcache.obj \
+ $(SLO)$/txtdrop.obj \
+ $(SLO)$/txtfld.obj \
+ $(SLO)$/txtfly.obj \
+ $(SLO)$/txtfrm.obj \
+ $(SLO)$/txtftn.obj \
+ $(SLO)$/txthyph.obj \
+ $(SLO)$/txtinit.obj \
+ $(SLO)$/txtpaint.obj \
+ $(SLO)$/txttab.obj \
+ $(SLO)$/widorp.obj \
+ $(SLO)$/blink.obj \
+ $(SLO)$/noteurl.obj \
+ $(SLO)$/SwGrammarMarkUp.obj \
+ $(SLO)$/wrong.obj
+
+.IF "$(dbgutil)"!=""
+SLOFILES += \
+ $(SLO)$/txtio.obj
+.ENDIF
+
+EXCEPTIONSFILES = \
+ $(SLO)$/EnhancedPDFExportHelper.obj \
+ $(SLO)$/inftxt.obj \
+ $(SLO)$/itradj.obj \
+ $(SLO)$/itrcrsr.obj \
+ $(SLO)$/porlay.obj \
+ $(SLO)$/pormulti.obj \
+ $(SLO)$/SwGrammarMarkUp.obj \
+ $(SLO)$/txtfly.obj \
+ $(SLO)$/wrong.obj
+
+
+.IF "$(CPUNAME)" == "SPARC"
+.IF "$(OS)" == "NETBSD"
+NOOPTFILES = \
+ $(SLO)$/txtftn.obj
+.ENDIF
+.ENDIF
+
+# --- Tagets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/sw/source/core/text/noteurl.cxx b/sw/source/core/text/noteurl.cxx
new file mode 100644
index 000000000000..7fe36a990fca
--- /dev/null
+++ b/sw/source/core/text/noteurl.cxx
@@ -0,0 +1,87 @@
+/*************************************************************************
+ *
+ * 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 "swtypes.hxx"
+#include <vcl/outdev.hxx>
+#include <svtools/imaprect.hxx>
+#include <svtools/imap.hxx>
+
+#include "txttypes.hxx"
+#include "noteurl.hxx"
+
+// globale Variable, wird in noteurl.Hxx bekanntgegeben
+SwNoteURL *pNoteURL = NULL;
+
+SV_IMPL_PTRARR( SwURLNoteList, SwURLNotePtr )
+
+
+void SwNoteURL::InsertURLNote( const XubString& rURL, const XubString& rTarget,
+ const SwRect& rRect )
+{
+ MSHORT i;
+ MSHORT nCount = aList.Count();
+ for( i = 0; i < nCount; i++ )
+ if( rRect == aList.GetObject(i)->GetRect() )
+ break;
+ if( i == nCount )
+ {
+ SwURLNote *pNew = new SwURLNote( rURL, rTarget, rRect );
+ aList.Insert( pNew, nCount );
+ }
+}
+
+
+void SwNoteURL::FillImageMap( ImageMap *pMap, const Point &rPos,
+ const MapMode& rMap )
+{
+ ASSERT( pMap, "FillImageMap: No ImageMap, no cookies!" );
+ MSHORT nCount = Count();
+ if( nCount )
+ {
+ MapMode aMap( MAP_100TH_MM );
+ for( MSHORT i = 0; i < nCount; ++i )
+ {
+ const SwURLNote &rNote = GetURLNote( i );
+ SwRect aSwRect( rNote.GetRect() );
+ aSwRect -= rPos;
+ Rectangle aRect( OutputDevice::LogicToLogic( aSwRect.SVRect(),
+ rMap, aMap ) );
+ IMapRectangleObject aObj( aRect, rNote.GetURL(), aEmptyStr, aEmptyStr,
+ rNote.GetTarget(), aEmptyStr, sal_True, sal_False );
+ pMap->InsertIMapObject( aObj );
+ }
+ }
+}
+
+
+
+
diff --git a/sw/source/core/text/pordrop.hxx b/sw/source/core/text/pordrop.hxx
new file mode 100644
index 000000000000..c4cb9089381c
--- /dev/null
+++ b/sw/source/core/text/pordrop.hxx
@@ -0,0 +1,119 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORDROP_HXX
+#define _PORDROP_HXX
+
+#include "portxt.hxx"
+
+class SwFont;
+
+// DropCap-Cache, globale Variable, in txtinit.cxx initialisiert/zerstoert
+// und in txtdrop.cxx benutzt bei der Initialenberechnung
+
+class SwDropCapCache;
+extern SwDropCapCache *pDropCapCache;
+
+/*************************************************************************
+ * class SwDropPortionPart
+ *
+ * A drop portion can consist of one or more parts in order to allow
+ * attribute changes inside them.
+ *************************************************************************/
+
+class SwDropPortionPart
+{
+ SwDropPortionPart* pFollow;
+ SwFont* pFnt;
+ xub_StrLen nLen;
+ USHORT nWidth;
+
+public:
+ SwDropPortionPart( SwFont& rFont, const xub_StrLen nL )
+ : pFollow( 0 ), pFnt( &rFont ), nLen( nL ), nWidth( 0 ) {};
+ ~SwDropPortionPart();
+
+ inline SwDropPortionPart* GetFollow() const { return pFollow; };
+ inline void SetFollow( SwDropPortionPart* pNew ) { pFollow = pNew; };
+ inline SwFont& GetFont() const { return *pFnt; }
+ inline xub_StrLen GetLen() const { return nLen; }
+ inline USHORT GetWidth() const { return nWidth; }
+ inline void SetWidth( USHORT nNew ) { nWidth = nNew; }
+};
+
+/*************************************************************************
+ * class SwDropPortion
+ *************************************************************************/
+
+class SwDropPortion : public SwTxtPortion
+{
+ friend class SwDropCapCache;
+ SwDropPortionPart* pPart; // due to script / attribute changes
+ MSHORT nLines; // Anzahl der Zeilen
+ KSHORT nDropHeight; // Hoehe
+ KSHORT nDropDescent; // Abstand zur naechsten Zeile
+ KSHORT nDistance; // Abstand zum Text
+ KSHORT nFix; // Fixposition
+ short nX; // X-PaintOffset
+ short nY; // Y-Offset
+
+ sal_Bool FormatTxt( SwTxtFormatInfo &rInf );
+ void PaintTxt( const SwTxtPaintInfo &rInf ) const;
+
+ inline void Fix( const KSHORT nNew ) { nFix = nNew; }
+public:
+ SwDropPortion( const MSHORT nLineCnt,
+ const KSHORT nDropHeight,
+ const KSHORT nDropDescent,
+ const KSHORT nDistance );
+ virtual ~SwDropPortion();
+
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ void PaintDrop( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+ virtual xub_StrLen GetCrsrOfst( const MSHORT nOfst ) const;
+
+ inline MSHORT GetLines() const { return nLines; }
+ inline KSHORT GetDistance() const { return nDistance; }
+ inline KSHORT GetDropHeight() const { return nDropHeight; }
+ inline KSHORT GetDropDescent() const { return nDropDescent; }
+ inline KSHORT GetDropLeft() const { return Width() + nFix; }
+
+ inline SwDropPortionPart* GetPart() const { return pPart; }
+ inline void SetPart( SwDropPortionPart* pNew ) { pPart = pNew; }
+
+ inline void SetY( short nNew ) { nY = nNew; }
+
+ inline SwFont* GetFnt() const { return pPart ? &pPart->GetFont() : NULL; }
+
+ static void DeleteDropCapCache();
+
+ OUTPUT_OPERATOR
+};
+
+
+#endif
diff --git a/sw/source/core/text/porexp.cxx b/sw/source/core/text/porexp.cxx
new file mode 100644
index 000000000000..95fae4d7b64e
--- /dev/null
+++ b/sw/source/core/text/porexp.cxx
@@ -0,0 +1,312 @@
+/*************************************************************************
+ *
+ * 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 <viewopt.hxx> // SwViewOptions
+#include <SwPortionHandler.hxx>
+#include <inftxt.hxx>
+#include <porexp.hxx>
+
+/*************************************************************************
+ * class SwExpandPortion
+ *************************************************************************/
+
+xub_StrLen SwExpandPortion::GetCrsrOfst( const MSHORT nOfst ) const
+{ return SwLinePortion::GetCrsrOfst( nOfst ); }
+
+/*************************************************************************
+ * virtual SwExpandPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwExpandPortion::GetExpTxt( const SwTxtSizeInfo&,
+ XubString &rTxt ) const
+{
+ rTxt.Erase();
+ // Nicht etwa: return 0 != rTxt.Len();
+ // Weil: leere Felder ersetzen CH_TXTATR gegen einen Leerstring
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwExpandPortion::HandlePortion()
+ *************************************************************************/
+
+void SwExpandPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString;
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
+/*************************************************************************
+ * virtual SwExpandPortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwExpandPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
+{
+ SwTxtSlot aDiffTxt( &rInf, this, false, false );
+ return rInf.GetTxtSize();
+}
+
+/*************************************************************************
+ * virtual SwExpandPortion::Format()
+ *************************************************************************/
+
+// 5010: Exp und Tabs
+
+sal_Bool SwExpandPortion::Format( SwTxtFormatInfo &rInf )
+{
+ SwTxtSlot aDiffTxt( &rInf, this, true, false );
+ const xub_StrLen nFullLen = rInf.GetLen();
+
+ // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der
+ // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs)
+ // sal_False returnen wegen SetFull ...
+ if( !nFullLen )
+ {
+ // nicht Init(), weil wir Hoehe und Ascent brauchen
+ Width(0);
+ return sal_False;
+ }
+ return SwTxtPortion::Format( rInf );
+}
+
+/*************************************************************************
+ * virtual SwExpandPortion::Paint()
+ *************************************************************************/
+
+void SwExpandPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ SwTxtSlot aDiffTxt( &rInf, this, true, true );
+
+ rInf.DrawBackBrush( *this );
+
+ // do we have to repaint a post it portion?
+ if( rInf.OnWin() && pPortion && !pPortion->Width() )
+ pPortion->PrePaint( rInf, this );
+
+ // The contents of field portions is not considered during the
+ // calculation of the directions. Therefore we let vcl handle
+ // the calculation by removing the BIDI_STRONG_FLAG temporarily.
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ aLayoutModeModifier.SetAuto();
+
+ // ST2
+ if ( rInf.GetSmartTags() || rInf.GetGrammarCheckList() )
+ rInf.DrawMarkedText( *this, rInf.GetLen(), sal_False, sal_False,
+ 0 != rInf.GetSmartTags(), 0 != rInf.GetGrammarCheckList() );
+ else
+ rInf.DrawText( *this, rInf.GetLen(), sal_False );
+}
+
+/*************************************************************************
+ * class SwBlankPortion
+ *************************************************************************/
+
+SwLinePortion *SwBlankPortion::Compress() { return this; }
+
+/*************************************************************************
+ * SwBlankPortion::MayUnderFlow()
+ *************************************************************************/
+
+// 5497: Es gibt schon Gemeinheiten auf der Welt...
+// Wenn eine Zeile voll mit HardBlanks ist und diese ueberlaeuft,
+// dann duerfen keine Underflows generiert werden!
+// Komplikationen bei Flys...
+
+MSHORT SwBlankPortion::MayUnderFlow( const SwTxtFormatInfo &rInf,
+ xub_StrLen nIdx, sal_Bool bUnderFlow ) const
+{
+ if( rInf.StopUnderFlow() )
+ return 0;
+ const SwLinePortion *pPos = rInf.GetRoot();
+ if( pPos->GetPortion() )
+ pPos = pPos->GetPortion();
+ while( pPos && pPos->IsBlankPortion() )
+ pPos = pPos->GetPortion();
+ if( !pPos || !rInf.GetIdx() || ( !pPos->GetLen() && pPos == rInf.GetRoot() ) )
+ return 0; // Nur noch BlankPortions unterwegs
+ // Wenn vor uns ein Blank ist, brauchen wir kein Underflow ausloesen,
+ // wenn hinter uns ein Blank ist, brauchen wir kein Underflow weiterreichen
+ if( bUnderFlow && CH_BLANK == rInf.GetTxt().GetChar( nIdx + 1) )
+ return 0;
+ if( nIdx && !((SwTxtFormatInfo&)rInf).GetFly() )
+ {
+ while( pPos && !pPos->IsFlyPortion() )
+ pPos = pPos->GetPortion();
+ if( !pPos )
+ {
+ //Hier wird ueberprueft, ob es in dieser Zeile noch sinnvolle Umbrueche
+ //gibt, Blanks oder Felder etc., wenn nicht, kein Underflow.
+ //Wenn Flys im Spiel sind, lassen wir das Underflow trotzdem zu.
+ xub_StrLen nBlank = nIdx;
+ while( --nBlank > rInf.GetLineStart() )
+ {
+ const xub_Unicode cCh = rInf.GetChar( nBlank );
+ if( CH_BLANK == cCh ||
+ (( CH_TXTATR_BREAKWORD == cCh || CH_TXTATR_INWORD == cCh )
+ && rInf.HasHint( nBlank ) ) )
+ break;
+ }
+ if( nBlank <= rInf.GetLineStart() )
+ return 0;
+ }
+ }
+ xub_Unicode cCh;
+ if( nIdx < 2 || CH_BLANK == (cCh = rInf.GetChar( nIdx - 1 )) )
+ return 1;
+ if( CH_BREAK == cCh )
+ return 0;
+ return 2;
+}
+
+/*************************************************************************
+ * virtual SwBlankPortion::FormatEOL()
+ *************************************************************************/
+// Format end of Line
+
+void SwBlankPortion::FormatEOL( SwTxtFormatInfo &rInf )
+{
+ MSHORT nMay = MayUnderFlow( rInf, rInf.GetIdx() - nLineLength, sal_True );
+ if( nMay )
+ {
+ if( nMay > 1 )
+ {
+ if( rInf.GetLast() == this )
+ rInf.SetLast( FindPrevPortion( rInf.GetRoot() ) );
+ rInf.X( rInf.X() - PrtWidth() );
+ rInf.SetIdx( rInf.GetIdx() - GetLen() );
+ }
+ Truncate();
+ rInf.SetUnderFlow( this );
+ if( rInf.GetLast()->IsKernPortion() )
+ rInf.SetUnderFlow( rInf.GetLast() );
+ }
+}
+
+/*************************************************************************
+ * virtual SwBlankPortion::Format()
+ *************************************************************************/
+
+// 7771: UnderFlows weiterreichen und selbst ausloesen!
+sal_Bool SwBlankPortion::Format( SwTxtFormatInfo &rInf )
+{
+ const sal_Bool bFull = rInf.IsUnderFlow() || SwExpandPortion::Format( rInf );
+ if( bFull && MayUnderFlow( rInf, rInf.GetIdx(), rInf.IsUnderFlow() ) )
+ {
+ Truncate();
+ rInf.SetUnderFlow( this );
+ if( rInf.GetLast()->IsKernPortion() )
+ rInf.SetUnderFlow( rInf.GetLast() );
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwBlankPortion::Paint()
+ *************************************************************************/
+
+void SwBlankPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( !bMulti ) // No gray background for multiportion brackets
+ rInf.DrawViewOpt( *this, POR_BLANK );
+ SwExpandPortion::Paint( rInf );
+}
+
+/*************************************************************************
+ * virtual SwBlankPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwBlankPortion::GetExpTxt( const SwTxtSizeInfo&, XubString &rTxt ) const
+{
+ rTxt = cChar;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwBlankPortion::HandlePortion()
+ *************************************************************************/
+
+void SwBlankPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString( cChar );
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
+/*************************************************************************
+ * class SwPostItsPortion
+ *************************************************************************/
+
+SwPostItsPortion::SwPostItsPortion( sal_Bool bScrpt )
+ : nViewWidth(0), bScript( bScrpt )
+{
+ nLineLength = 1;
+ SetWhichPor( POR_POSTITS );
+}
+
+void SwPostItsPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( rInf.OnWin() && Width() )
+ rInf.DrawPostIts( *this, IsScript() );
+}
+
+KSHORT SwPostItsPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ // Nicht zu fassen: PostIts sind immer zu sehen.
+ return rInf.OnWin() ?
+ (KSHORT)rInf.GetOpt().GetPostItsWidth( rInf.GetOut() ) : 0;
+}
+
+/*************************************************************************
+ * virtual SwPostItsPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwPostItsPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_Bool bRet = SwLinePortion::Format( rInf );
+ // 32749: PostIts sollen keine Auswirkung auf Zeilenhoehe etc. haben
+ SetAscent( 1 );
+ Height( 1 );
+ return bRet;
+}
+
+/*************************************************************************
+ * virtual SwPostItsPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwPostItsPortion::GetExpTxt( const SwTxtSizeInfo &rInf,
+ XubString &rTxt ) const
+{
+ if( rInf.OnWin() && rInf.GetOpt().IsPostIts() )
+ rTxt = ' ';
+ else
+ rTxt.Erase();
+ return sal_True;
+}
+
diff --git a/sw/source/core/text/porexp.hxx b/sw/source/core/text/porexp.hxx
new file mode 100644
index 000000000000..6cecd542c764
--- /dev/null
+++ b/sw/source/core/text/porexp.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _POREXP_HXX
+#define _POREXP_HXX
+
+#include "portxt.hxx"
+
+/*************************************************************************
+ * class SwExpandPortion
+ *************************************************************************/
+
+class SwExpandPortion : public SwTxtPortion
+{
+public:
+ inline SwExpandPortion() { SetWhichPor( POR_EXP ); }
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual xub_StrLen GetCrsrOfst( const MSHORT nOfst ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+
+/*************************************************************************
+ * class SwBlankPortion
+ *************************************************************************/
+
+class SwBlankPortion : public SwExpandPortion
+{
+ xub_Unicode cChar;
+ BOOL bMulti; // For multiportion brackets
+public:
+ inline SwBlankPortion( xub_Unicode cCh, BOOL bMult = sal_False )
+ : cChar( cCh ), bMulti( bMult )
+ { cChar = cCh; SetLen(1); SetWhichPor( POR_BLANK ); }
+
+ BOOL IsMulti() const { return bMulti; }
+ void SetMulti( BOOL bNew ) { bMulti = bNew; }
+
+ virtual SwLinePortion *Compress();
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ MSHORT MayUnderFlow( const SwTxtFormatInfo &rInf, xub_StrLen nIdx,
+ sal_Bool bUnderFlow ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwPostItsPortion
+ *************************************************************************/
+
+class SwPostItsPortion : public SwExpandPortion
+{
+ KSHORT nViewWidth;
+ sal_Bool bScript;
+public:
+ SwPostItsPortion( sal_Bool bScrpt );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ sal_Bool IsScript() const { return bScript; }
+ OUTPUT_OPERATOR
+};
+
+
+CLASSIO( SwExpandPortion )
+CLASSIO( SwBlankPortion )
+CLASSIO( SwPostItsPortion )
+
+
+#endif
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
new file mode 100644
index 000000000000..1a05aa38098a
--- /dev/null
+++ b/sw/source/core/text/porfld.cxx
@@ -0,0 +1,1389 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+
+#ifndef _GRAPH_HXX //autogen
+#include <vcl/graph.hxx>
+#endif
+#include <editeng/brshitem.hxx>
+#ifndef _METRIC_HXX //autogen
+#include <vcl/metric.hxx>
+#endif
+#ifndef _OUTDEV_HXX //autogen
+#include <vcl/outdev.hxx>
+#endif
+#include <viewopt.hxx> // SwViewOptions
+#include <txtcfg.hxx>
+#include <SwPortionHandler.hxx>
+#include <porlay.hxx>
+#include <porfld.hxx>
+#include <inftxt.hxx>
+#include <blink.hxx> // pBlink
+#include <frmtool.hxx> // DrawGraphic
+#include <viewsh.hxx>
+#ifndef _DOCSH_HXX
+#include <docsh.hxx>
+#endif
+#include <doc.hxx>
+#include <breakit.hxx>
+#include <porrst.hxx>
+#include <porftn.hxx> // SwFtnPortion
+#include <accessibilityoptions.hxx>
+#include <editeng/lrspitem.hxx>
+
+#include <unicode/ubidi.h>
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * class SwFldPortion
+ *************************************************************************/
+
+SwLinePortion *SwFldPortion::Compress()
+{ return (GetLen() || aExpand.Len() || SwLinePortion::Compress()) ? this : 0; }
+
+SwFldPortion *SwFldPortion::Clone( const XubString &rExpand ) const
+{
+ SwFont *pNewFnt;
+ if( 0 != ( pNewFnt = pFnt ) )
+ {
+ pNewFnt = new SwFont( *pFnt );
+ }
+ // --> OD 2009-11-25 #i107143#
+ // pass placeholder property to created <SwFldPortion> instance.
+ SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder );
+ // <--
+ pClone->SetNextOffset( nNextOffset );
+ pClone->m_bNoLength = this->m_bNoLength;
+ return pClone;
+}
+
+void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld )
+{
+ ASSERT( pFld, "TakeNextOffset: Missing Source" );
+ nNextOffset = pFld->GetNextOffset();
+ aExpand.Erase( 0, nNextOffset );
+ bFollow = sal_True;
+}
+
+SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold )
+ : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0),
+ bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold )
+ , m_bNoLength( sal_False )
+{
+ SetWhichPor( POR_FLD );
+}
+
+SwFldPortion::SwFldPortion( const SwFldPortion& rFld )
+ : SwExpandPortion( rFld ),
+ aExpand( rFld.GetExp() ),
+ nNextOffset( rFld.GetNextOffset() ),
+ nNextScriptChg( rFld.GetNextScriptChg() ),
+ bFollow( rFld.IsFollow() ),
+ bLeft( rFld.IsLeft() ),
+ bHide( rFld.IsHide() ),
+ bCenter( rFld.IsCenter() ),
+ bHasFollow( rFld.HasFollow() ),
+ bPlaceHolder( rFld.bPlaceHolder )
+ , m_bNoLength( rFld.m_bNoLength )
+{
+ if ( rFld.HasFont() )
+ pFnt = new SwFont( *rFld.GetFont() );
+ else
+ pFnt = 0;
+
+ SetWhichPor( POR_FLD );
+}
+
+SwFldPortion::~SwFldPortion()
+{
+ delete pFnt;
+ if( pBlink )
+ pBlink->Delete( this );
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::GetViewWidth()
+ *************************************************************************/
+
+KSHORT SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
+ // Moment errechnet werden:
+ SwFldPortion* pThis = (SwFldPortion*)this;
+ if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() &&
+ !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
+ {
+ if( !nViewWidth )
+ pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width();
+ }
+ else
+ pThis->nViewWidth = 0;
+ return nViewWidth;
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::Format()
+ *************************************************************************/
+
+// 8653: in keinem Fall nur SetLen(0);
+
+/*************************************************************************
+ * Hilfsklasse SwFldSlot
+ **************************************************************************/
+
+class SwFldSlot
+{
+ const XubString *pOldTxt;
+ XubString aTxt;
+ xub_StrLen nIdx;
+ xub_StrLen nLen;
+ sal_Bool bOn;
+ SwTxtFormatInfo *pInf;
+public:
+ SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor );
+ ~SwFldSlot();
+};
+
+SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor )
+{
+ bOn = pPor->GetExpTxt( *pNew, aTxt );
+
+ // Der Text wird ausgetauscht...
+ if( bOn )
+ {
+ pInf = (SwTxtFormatInfo*)pNew;
+ nIdx = pInf->GetIdx();
+ nLen = pInf->GetLen();
+ pOldTxt = &(pInf->GetTxt());
+ pInf->SetLen( aTxt.Len() );
+ if( pPor->IsFollow() )
+ {
+ pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
+ pInf->SetIdx( 0 );
+ }
+ else
+ {
+ XubString aTmp( aTxt );
+ aTxt = *pOldTxt;
+ aTxt.Erase( nIdx, 1 );
+ aTxt.Insert( aTmp, nIdx );
+ }
+ pInf->SetTxt( aTxt );
+ }
+}
+
+SwFldSlot::~SwFldSlot()
+{
+ if( bOn )
+ {
+ pInf->SetTxt( *pOldTxt );
+ pInf->SetIdx( nIdx );
+ pInf->SetLen( nLen );
+ pInf->SetFakeLineStart( sal_False );
+ }
+}
+
+void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf )
+{
+ String aTxt;
+ if( GetExpTxt( rInf, aTxt ) && aTxt.Len() && pBreakIt->GetBreakIter().is() )
+ {
+ BYTE nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual();
+ USHORT nScript;
+ {
+ nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 );
+ xub_StrLen nChg = 0;
+ if( i18n::ScriptType::WEAK == nScript )
+ {
+ nChg =(xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript);
+ if( nChg < aTxt.Len() )
+ nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg );
+ }
+
+ //
+ // nNextScriptChg will be evaluated during SwFldPortion::Format()
+ //
+ if ( nChg < aTxt.Len() )
+ nNextScriptChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript );
+ else
+ nNextScriptChg = aTxt.Len();
+
+ }
+ BYTE nTmp;
+ switch ( nScript ) {
+ case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break;
+ case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break;
+ case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break;
+ default: nTmp = nActual;
+ }
+
+ // #i16354# Change script type for RTL text to CTL.
+ const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
+ // --> OD 2009-01-29 #i98418#
+// const BYTE nFldDir = IsNumberPortion() ?
+ const BYTE nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ?
+ rSI.GetDefaultDir() :
+ rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() );
+ // <--
+ if ( UBIDI_RTL == nFldDir )
+ {
+ UErrorCode nError = U_ZERO_ERROR;
+ UBiDi* pBidi = ubidi_openSized( aTxt.Len(), 0, &nError );
+ ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.GetBuffer()), aTxt.Len(), nFldDir, NULL, &nError );
+ int32_t nEnd;
+ UBiDiLevel nCurrDir;
+ ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir );
+ ubidi_close( pBidi );
+ const xub_StrLen nNextDirChg = (xub_StrLen)nEnd;
+ nNextScriptChg = Min( nNextScriptChg, nNextDirChg );
+
+ // #i89825# change the script type also to CTL
+ // if there is no strong LTR char in the LTR run (numbers)
+ if ( nCurrDir != UBIDI_RTL )
+ {
+ nCurrDir = UBIDI_RTL;
+ for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx )
+ {
+ UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx ));
+ if ( nCharDir == U_LEFT_TO_RIGHT ||
+ nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
+ nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
+ {
+ nCurrDir = UBIDI_LTR;
+ break;
+ }
+ }
+ }
+
+ if ( nCurrDir == UBIDI_RTL )
+ nTmp = SW_CTL;
+ }
+
+ // --> OD 2009-01-29 #i98418#
+ // keep determined script type for footnote portions as preferred script type.
+ // For footnote portions a font can not be created directly - see footnote
+ // portion format method.
+// if( !IsFtnPortion() && nTmp != nActual )
+ if ( IsFtnPortion() )
+ {
+ dynamic_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp );
+ }
+ else if ( nTmp != nActual )
+ {
+ if( !pFnt )
+ pFnt = new SwFont( *rInf.GetFont() );
+ pFnt->SetActual( nTmp );
+ }
+ // <--
+ }
+}
+
+sal_Bool SwFldPortion::Format( SwTxtFormatInfo &rInf )
+{
+ // Scope wegen aDiffTxt::DTOR!
+ xub_StrLen nRest;
+ sal_Bool bFull;
+ sal_Bool bEOL = sal_False;
+ long nTxtRest = rInf.GetTxt().Len() - rInf.GetIdx();
+ {
+ SwFldSlot aDiffTxt( &rInf, this );
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ aLayoutModeModifier.SetAuto();
+
+ // Field portion has to be split in several parts if
+ // 1. There are script/direction changes inside the field
+ // 2. There are portion breaks (tab, break) inside the field:
+ const xub_StrLen nOldFullLen = rInf.GetLen();
+ xub_StrLen nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx();
+ if ( nNextScriptChg < nFullLen )
+ {
+ nFullLen = nNextScriptChg;
+ rInf.SetHookChar( 0 );
+ }
+ rInf.SetLen( nFullLen );
+
+ if ( STRING_LEN != rInf.GetUnderScorePos() &&
+ rInf.GetUnderScorePos() > rInf.GetIdx() )
+ rInf.SetUnderScorePos( rInf.GetIdx() );
+
+ if( pFnt )
+ pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() );
+
+ SwFontSave aSave( rInf, pFnt );
+
+ // 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge
+ // gesetzt und wird in nRest uebertragen. Ansonsten bleibt die
+ // Laenge erhalten und wuerde auch in nRest einfliessen!
+ SetLen(0);
+ const MSHORT nFollow = IsFollow() ? 0 : 1;
+
+ // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der
+ // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs)
+ // sal_False returnen wegen SetFull ...
+ if( !nFullLen )
+ {
+ // nicht Init(), weil wir Hoehe und Ascent brauchen
+ Width(0);
+ bFull = rInf.Width() <= rInf.GetPos().X();
+ }
+ else
+ {
+ xub_StrLen nOldLineStart = rInf.GetLineStart();
+ if( IsFollow() )
+ rInf.SetLineStart( 0 );
+ rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow );
+
+ // the height depending on the fields font is set,
+ // this is required for SwTxtGuess::Guess
+ Height( rInf.GetTxtHeight() );
+ // If a kerning portion is inserted after our field portion,
+ // the ascent and height must be known
+ SetAscent( rInf.GetAscent() );
+ bFull = SwTxtPortion::Format( rInf );
+ rInf.SetNotEOL( sal_False );
+ rInf.SetLineStart( nOldLineStart );
+ }
+ xub_StrLen nTmpLen = GetLen();
+ bEOL = !nTmpLen && nFollow && bFull;
+ nRest = nOldFullLen - nTmpLen;
+
+ // Das Zeichen wird in der ersten Portion gehalten.
+ // Unbedingt nach Format!
+ SetLen( (m_bNoLength) ? 0 : nFollow );
+
+ if( nRest )
+ {
+ // aExpand ist noch nicht gekuerzt worden, der neue Ofst
+ // ergibt sich durch nRest.
+ xub_StrLen nNextOfst = aExpand.Len() - nRest;
+
+ if ( IsQuoVadisPortion() )
+ nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().Len();
+
+ XubString aNew( aExpand, nNextOfst, STRING_LEN );
+ aExpand.Erase( nNextOfst, STRING_LEN );
+
+ // These characters should not be contained in the follow
+ // field portion. They are handled via the HookChar mechanism.
+ switch( aNew.GetChar( 0 ))
+ {
+ case CH_BREAK : bFull = sal_True;
+ // kein break;
+ case ' ' :
+ case CH_TAB :
+ case CHAR_HARDHYPHEN: // non-breaking hyphen
+ case CHAR_SOFTHYPHEN:
+ case CHAR_HARDBLANK:
+ // --> FME 2006-01-11 #i59759# Erase additional control
+ // characters from field string, otherwise we get stuck in
+ // a loop.
+ case CHAR_ZWSP :
+ case CHAR_ZWNBSP :
+ // case CHAR_RLM :
+ // case CHAR_LRM :
+ // <--
+ {
+ aNew.Erase( 0, 1 );
+ ++nNextOfst;
+ break;
+ }
+ default: ;
+ }
+
+ // Even if there is no more text left for a follow field,
+ // we have to build a follow field portion (without font),
+ // otherwise the HookChar mechanism would not work.
+ SwFldPortion *pFld = Clone( aNew );
+ if( aNew.Len() && !pFld->GetFont() )
+ {
+ SwFont *pNewFnt = new SwFont( *rInf.GetFont() );
+ pFld->SetFont( pNewFnt );
+ }
+ pFld->SetFollow( sal_True );
+ SetHasFollow( sal_True );
+ // In nNextOffset steht bei einem neuangelegten Feld zunaechst
+ // der Offset, an dem es selbst im Originalstring beginnt.
+ // Wenn beim Formatieren ein FollowFeld angelegt wird, wird
+ // der Offset dieses FollowFelds in nNextOffset festgehalten.
+ nNextOffset = nNextOffset + nNextOfst;
+ pFld->SetNextOffset( nNextOffset );
+ rInf.SetRest( pFld );
+ }
+ }
+
+ if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() )
+ rInf.GetLast()->FormatEOL( rInf );
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::Paint()
+ *************************************************************************/
+
+void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ SwFontSave aSave( rInf, pFnt );
+
+ ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
+ if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
+ {
+ // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ...
+ rInf.DrawViewOpt( *this, POR_FLD );
+ SwExpandPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ if( !rTxt.Len() && rInf.OnWin() &&
+ !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() &&
+ SwViewOption::IsFieldShadings() &&
+ !HasFollow() )
+ rTxt = ' ';
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::HandlePortion()
+ *************************************************************************/
+
+void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Special( GetLen(), aExpand, GetWhichPor() );
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
+{
+ SwFontSave aSave( rInf, pFnt );
+ SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) );
+ return aSize;
+}
+
+/*************************************************************************
+ * class SwHiddenPortion
+ *************************************************************************/
+
+SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const
+{
+ SwFont *pNewFnt;
+ if( 0 != ( pNewFnt = pFnt ) )
+ pNewFnt = new SwFont( *pFnt );
+ return new SwHiddenPortion( rExpand, pNewFnt );
+}
+
+/*************************************************************************
+ * virtual SwHiddenPortion::Paint()
+ *************************************************************************/
+
+void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ {
+ SwFontSave aSave( rInf, pFnt );
+ rInf.DrawViewOpt( *this, POR_HIDDEN );
+ SwExpandPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * virtual SwHiddenPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ // Nicht auf IsHidden() abfragen !
+ return SwFldPortion::GetExpTxt( rInf, rTxt );
+}
+
+/*************************************************************************
+ * class SwNumberPortion
+ *************************************************************************/
+
+// --> OD 2008-01-23 #newlistlevelattrs#
+SwNumberPortion::SwNumberPortion( const XubString &rExpand,
+ SwFont *pFont,
+ const sal_Bool bLft,
+ const sal_Bool bCntr,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive )
+ : SwFldPortion( rExpand, pFont ),
+ nFixWidth(0),
+ nMinDist( nMinDst ),
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive )
+ // <--
+{
+ SetWhichPor( POR_NUMBER );
+ SetLeft( bLft );
+ SetHide( sal_False );
+ SetCenter( bCntr );
+}
+
+xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const
+{
+ return 0;
+}
+
+SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const
+{
+ SwFont *pNewFnt;
+ if( 0 != ( pNewFnt = pFnt ) )
+ pNewFnt = new SwFont( *pFnt );
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(),
+ nMinDist, mbLabelAlignmentPosAndSpaceModeActive );
+ // <--
+}
+
+/*************************************************************************
+ * virtual SwNumberPortion::Format()
+ *************************************************************************/
+
+// 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen!
+// 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text
+// eingibt, bis die Zeile ueberlaeuft.
+// Man muss die Fly-Ausweichmanoever beachten!
+
+sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf )
+{
+ SetHide( sal_False );
+ const sal_Bool bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+ // a numbering portion can be contained in a rotated portion!!!
+ nFixWidth = rInf.IsMulti() ? Height() : Width();
+ rInf.SetNumDone( !rInf.GetRest() );
+ if( rInf.IsNumDone() )
+ {
+// SetAscent( rInf.GetAscent() );
+ ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" );
+
+ long nDiff( 0 );
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ if ( !mbLabelAlignmentPosAndSpaceModeActive )
+ {
+ if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) &&
+ // --> FME 2004-08-13 #i32902#
+ !IsFtnNumPortion() )
+ // <--
+ {
+ nDiff = rInf.Left()
+ + rInf.GetTxtFrm()->GetTxtNode()->
+ GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst()
+ - rInf.First()
+ + rInf.ForcedLeftMargin();
+ }
+ else
+ {
+ nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
+ }
+ }
+ // <--
+ // Ein Vorschlag von Juergen und Volkmar:
+ // Der Textteil hinter der Numerierung sollte immer
+ // mindestens beim linken Rand beginnen.
+ if( nDiff < 0 )
+ nDiff = 0;
+ else if ( nDiff > rInf.X() )
+ nDiff -= rInf.X();
+ else
+ nDiff = 0;
+
+ if( nDiff < nFixWidth + nMinDist )
+ nDiff = nFixWidth + nMinDist;
+ // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
+ // fieser Sonderfall: FlyFrm liegt in dem Bereich,
+ // den wir uns gerade unter den Nagel reissen wollen.
+ // Die NumberPortion wird als verborgen markiert.
+ const sal_Bool bFly = rInf.GetFly() ||
+ ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
+ if( nDiff > rInf.Width() )
+ {
+ nDiff = rInf.Width();
+ if ( bFly )
+ SetHide( sal_True );
+ }
+
+ // A numbering portion can be inside a SwRotatedPortion. Then the
+ // Height has to be changed
+ if ( rInf.IsMulti() )
+ {
+ if ( Height() < nDiff )
+ Height( KSHORT( nDiff ) );
+ }
+ else if( Width() < nDiff )
+ Width( KSHORT(nDiff) );
+ }
+ return bFull;
+}
+
+void SwNumberPortion::FormatEOL( SwTxtFormatInfo& )
+{
+/* Ein FormatEOL deutet daraufhin, dass der folgende Text
+ * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert,
+ * wird diese NumberPortion verborgen.
+ */
+
+ // This caused trouble with flys anchored as characters.
+ // If one of these is numbered but does not fit to the line,
+ // it calls this function, causing a loop because both the number
+ // portion and the fly portion go to the next line
+// SetHide( sal_True );
+}
+
+/*************************************************************************
+ * virtual SwNumberPortion::Paint()
+ *************************************************************************/
+
+void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+/* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
+ * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
+ */
+
+ if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
+ {
+ SwLinePortion *pTmp = GetPortion();
+ while ( pTmp && !pTmp->InTxtGrp() )
+ pTmp = pTmp->GetPortion();
+ if ( !pTmp )
+ return;
+ }
+
+ // calculate the width of the number portion, including follows
+ const KSHORT nOldWidth = Width();
+ USHORT nSumWidth = 0;
+ USHORT nOffset = 0;
+
+ const SwLinePortion* pTmp = this;
+ while ( pTmp && pTmp->InNumberGrp() )
+ {
+ nSumWidth = nSumWidth + pTmp->Width();
+ if ( ((SwNumberPortion*)pTmp)->HasFollow() )
+ pTmp = pTmp->GetPortion();
+ else
+ {
+ nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth;
+ break;
+ }
+ }
+
+ // The master portion takes care for painting the background of the
+ // follow field portions
+ if ( ! IsFollow() )
+ {
+ SwLinePortion *pThis = (SwLinePortion*)this;
+ pThis->Width( nSumWidth );
+ rInf.DrawViewOpt( *this, POR_NUMBER );
+ pThis->Width( nOldWidth );
+ }
+
+ if( aExpand.Len() )
+ {
+ const SwFont *pTmpFnt = rInf.GetFont();
+ sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() ||
+ UNDERLINE_NONE != pTmpFnt->GetOverline() ||
+ STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) &&
+ !pTmpFnt->IsWordLineMode();
+ if( bPaintSpace && pFnt )
+ bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() ||
+ UNDERLINE_NONE != pFnt->GetOverline() ||
+ STRIKEOUT_NONE != pFnt->GetStrikeout() ) &&
+ !pFnt->IsWordLineMode();
+
+ SwFontSave aSave( rInf, pFnt );
+
+ if( nFixWidth == Width() && ! HasFollow() )
+ SwExpandPortion::Paint( rInf );
+ else
+ {
+ // logisches const: Width wird wieder zurueckgesetzt
+ SwLinePortion *pThis = (SwLinePortion*)this;
+ bPaintSpace = bPaintSpace && nFixWidth < nOldWidth;
+ KSHORT nSpaceOffs = nFixWidth;
+ pThis->Width( nFixWidth );
+
+ if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
+ ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) )
+ SwExpandPortion::Paint( rInf );
+ else
+ {
+ SwTxtPaintInfo aInf( rInf );
+ if( nOffset < nMinDist )
+ nOffset = 0;
+ else
+ {
+ if( IsCenter() )
+ {
+ /* #110778# a / 2 * 2 == a is not a tautology */
+ KSHORT nTmpOffset = nOffset;
+ nOffset /= 2;
+ if( nOffset < nMinDist )
+ nOffset = nTmpOffset - nMinDist;
+ }
+ else
+ nOffset = nOffset - nMinDist;
+ }
+ aInf.X( aInf.X() + nOffset );
+ SwExpandPortion::Paint( aInf );
+ if( bPaintSpace )
+ nSpaceOffs = nSpaceOffs + nOffset;
+ }
+ if( bPaintSpace && nOldWidth > nSpaceOffs )
+ {
+ SwTxtPaintInfo aInf( rInf );
+static sal_Char __READONLY_DATA sDoubleSpace[] = " ";
+ aInf.X( aInf.X() + nSpaceOffs );
+
+ // --> FME 2005-08-12 #i53199# Adjust position of underline:
+ if ( rInf.GetUnderFnt() )
+ {
+ const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() );
+ rInf.GetUnderFnt()->SetPos( aNewPos );
+ }
+ // <--
+
+ pThis->Width( nOldWidth - nSpaceOffs + 12 );
+ {
+ SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace );
+ aInf.DrawText( *this, aInf.GetLen(), sal_True );
+ }
+ }
+ pThis->Width( nOldWidth );
+ }
+ }
+}
+
+
+/*************************************************************************
+ * class SwBulletPortion
+ *************************************************************************/
+
+// --> OD 2008-01-23 #newlistlevelattrs#
+SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet,
+ const XubString& rBulletFollowedBy,
+ SwFont *pFont,
+ const sal_Bool bLft,
+ const sal_Bool bCntr,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive )
+ : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) ,
+ pFont, bLft, bCntr, nMinDst,
+ bLabelAlignmentPosAndSpaceModeActive )
+// <--
+{
+ SetWhichPor( POR_BULLET );
+}
+
+/*************************************************************************
+ * class SwGrfNumPortion
+ *************************************************************************/
+
+#define GRFNUM_SECURE 10
+
+// --> OD 2008-01-23 #newlistlevelattrs#
+SwGrfNumPortion::SwGrfNumPortion(
+ SwFrm*,
+ const XubString& rGraphicFollowedBy,
+ const SvxBrushItem* pGrfBrush,
+ const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize,
+ const sal_Bool bLft, const sal_Bool bCntr, const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive ) :
+ SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst,
+ bLabelAlignmentPosAndSpaceModeActive ),
+// <--
+ pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 )
+{
+ SetWhichPor( POR_GRFNUM );
+ SetAnimated( sal_False );
+ bReplace = sal_False;
+ if( pGrfBrush )
+ {
+ *pBrush = *pGrfBrush;
+ const Graphic* pGraph = pGrfBrush->GetGraphic();
+ if( pGraph )
+ SetAnimated( pGraph->IsAnimated() );
+ else
+ bReplace = sal_True;
+ }
+ if( pGrfOrient )
+ {
+ nYPos = pGrfOrient->GetPos();
+ eOrient = pGrfOrient->GetVertOrient();
+ }
+ else
+ {
+ nYPos = 0;
+ eOrient = text::VertOrientation::TOP;
+ }
+ Width( static_cast<USHORT>(rGrfSize.Width() + 2 * GRFNUM_SECURE) );
+ nFixWidth = Width();
+ nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE;
+ Height( KSHORT(nGrfHeight) );
+ bNoPaint = sal_False;
+}
+
+SwGrfNumPortion::~SwGrfNumPortion()
+{
+ if ( IsAnimated() )
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
+ delete pBrush;
+}
+
+void SwGrfNumPortion::StopAnimation( OutputDevice* pOut )
+{
+ if ( IsAnimated() )
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId );
+}
+
+sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf )
+{
+ SetHide( sal_False );
+ // --> OD 2008-01-29 #newlistlevelattrs#
+// Width( nFixWidth );
+ KSHORT nFollowedByWidth( 0 );
+ if ( mbLabelAlignmentPosAndSpaceModeActive )
+ {
+ SwFldPortion::Format( rInf );
+ nFollowedByWidth = Width();
+ SetLen( 0 );
+ }
+ Width( nFixWidth + nFollowedByWidth );
+ // <--
+ const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
+ const sal_Bool bFly = rInf.GetFly() ||
+ ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
+ SetAscent( static_cast<USHORT>(GetRelPos() > 0 ? GetRelPos() : 0) );
+ if( GetAscent() > Height() )
+ Height( GetAscent() );
+
+ if( bFull )
+ {
+ Width( rInf.Width() - (KSHORT)rInf.X() );
+ if( bFly )
+ {
+ SetLen( 0 );
+ SetNoPaint( sal_True );
+ rInf.SetNumDone( sal_False );
+ return sal_True;
+ }
+ }
+ rInf.SetNumDone( sal_True );
+ // --> OD 2008-01-23 #newlistlevelattrs#
+// long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
+ long nDiff = mbLabelAlignmentPosAndSpaceModeActive
+ ? 0
+ : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
+ // <--
+ // Ein Vorschlag von Juergen und Volkmar:
+ // Der Textteil hinter der Numerierung sollte immer
+ // mindestens beim linken Rand beginnen.
+ if( nDiff < 0 )
+ nDiff = 0;
+ else if ( nDiff > rInf.X() )
+ nDiff -= rInf.X();
+ if( nDiff < nFixWidth + nMinDist )
+ nDiff = nFixWidth + nMinDist;
+ // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
+ // fieser Sonderfall: FlyFrm liegt in dem Bereich,
+ // den wir uns gerade unter den Nagel reissen wollen.
+ // Die NumberPortion wird als verborgen markiert.
+ if( nDiff > rInf.Width() )
+ {
+ nDiff = rInf.Width();
+ if( bFly )
+ SetHide( sal_True );
+ }
+
+ if( Width() < nDiff )
+ Width( KSHORT(nDiff) );
+ return bFull;
+}
+
+void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( DontPaint() )
+ return;
+/* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
+ * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
+ */
+ if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
+ {
+ SwLinePortion *pTmp = GetPortion();
+ while ( pTmp && !pTmp->InTxtGrp() )
+ pTmp = pTmp->GetPortion();
+ if ( !pTmp )
+ return;
+ }
+ Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE );
+ long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) );
+ Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE );
+
+ // --> OD 2008-02-05 #newlistlevelattrs#
+ const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive ||
+ ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
+ ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() );
+ // <--
+
+ if( nFixWidth < Width() && !bTmpLeft )
+ {
+ KSHORT nOffset = Width() - nFixWidth;
+ if( nOffset < nMinDist )
+ nOffset = 0;
+ else
+ {
+ if( IsCenter() )
+ {
+ nOffset /= 2;
+ if( nOffset < nMinDist )
+ nOffset = Width() - nFixWidth - nMinDist;
+ }
+ else
+ nOffset = nOffset - nMinDist;
+ }
+ aPos.X() += nOffset;
+ }
+
+ if( bReplace )
+ {
+ KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120;
+ aSize = Size( nTmpH, nTmpH );
+ aPos.Y() = rInf.Y() - nTmpH;
+ }
+ SwRect aTmp( aPos, aSize );
+
+ sal_Bool bDraw = sal_True;
+
+ if ( IsAnimated() )
+ {
+ bDraw = !rInf.GetOpt().IsGraphic();
+ if( !nId )
+ {
+ SetId( long( rInf.GetTxtFrm() ) );
+ rInf.GetTxtFrm()->SetAnimation();
+ }
+ if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )
+ {
+ rInf.NoteAnimation();
+ const ViewShell* pViewShell = rInf.GetVsh();
+
+ // virtual device, not pdf export
+ if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() &&
+ pViewShell && pViewShell->GetWin() )
+ {
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId);
+ rInf.GetTxtFrm()->GetShell()->InvalidateWindows( aTmp );
+ }
+
+
+ else if ( pViewShell &&
+ !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
+ !pViewShell->IsPreView() &&
+ // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export.
+ pViewShell->GetWin() )
+ // <--
+ {
+ ( (Graphic*) pBrush->GetGraphic() )->StartAnimation(
+ (OutputDevice*)rInf.GetOut(), aPos, aSize, nId );
+ }
+
+ // pdf export, printing, preview, stop animations...
+ else
+ bDraw = sal_True;
+ }
+ if( bDraw )
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
+ }
+
+ SwRect aRepaint( rInf.GetPaintRect() );
+ const SwTxtFrm& rFrm = *rInf.GetTxtFrm();
+ if( rFrm.IsVertical() )
+ {
+ rFrm.SwitchHorizontalToVertical( aTmp );
+ rFrm.SwitchHorizontalToVertical( aRepaint );
+ }
+
+ if( rFrm.IsRightToLeft() )
+ {
+ rFrm.SwitchLTRtoRTL( aTmp );
+ rFrm.SwitchLTRtoRTL( aRepaint );
+ }
+
+ if( bDraw && aTmp.HasArea() )
+ DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(),
+ aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES );
+}
+
+void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent,
+ long nFlyAsc, long nFlyDesc )
+{
+ if ( GetOrient() != text::VertOrientation::NONE )
+ {
+ SetRelPos( 0 );
+ if ( GetOrient() == text::VertOrientation::CENTER )
+ SetRelPos( GetGrfHeight() / 2 );
+ else if ( GetOrient() == text::VertOrientation::TOP )
+ SetRelPos( GetGrfHeight() - GRFNUM_SECURE );
+ else if ( GetOrient() == text::VertOrientation::BOTTOM )
+ ;
+ else if ( GetOrient() == text::VertOrientation::CHAR_CENTER )
+ SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 );
+ else if ( GetOrient() == text::VertOrientation::CHAR_TOP )
+ SetRelPos( nLnAscent );
+ else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM )
+ SetRelPos( GetGrfHeight() - nLnDescent );
+ else
+ {
+ if( GetGrfHeight() >= nFlyAsc + nFlyDesc )
+ {
+ // wenn ich genauso gross bin wie die Zeile, brauche ich mich
+ // nicht an der Zeile nicht weiter ausrichten, ich lasse
+ // dann auch den max. Ascent der Zeile unveraendert
+
+ SetRelPos( nFlyAsc );
+ }
+ else if ( GetOrient() == text::VertOrientation::LINE_CENTER )
+ SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 );
+ else if ( GetOrient() == text::VertOrientation::LINE_TOP )
+ SetRelPos( nFlyAsc );
+ else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM )
+ SetRelPos( GetGrfHeight() - nFlyDesc );
+ }
+ }
+}
+
+void SwTxtFrm::StopAnimation( OutputDevice* pOut )
+{
+ ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" );
+ if( HasPara() )
+ {
+ SwLineLayout *pLine = GetPara();
+ while( pLine )
+ {
+ SwLinePortion *pPor = pLine->GetPortion();
+ while( pPor )
+ {
+ if( pPor->IsGrfNumPortion() )
+ ((SwGrfNumPortion*)pPor)->StopAnimation( pOut );
+ // Die Numerierungsportion sitzt immer vor dem ersten Zeichen,
+ // deshalb koennen wir abbrechen, sobald wir eine Portion mit
+ // einer Laenge > 0 erreicht haben.
+ pPor = pPor->GetLen() ? 0 : pPor->GetPortion();
+ }
+ pLine = pLine->GetLen() ? 0 : pLine->GetNext();
+ }
+ }
+}
+
+/*************************************************************************
+ * SwCombinedPortion::SwCombinedPortion(..)
+ * initializes the script array and clears the width array
+ *************************************************************************/
+
+SwCombinedPortion::SwCombinedPortion( const XubString &rTxt )
+ : SwFldPortion( rTxt )
+{
+ SetLen(1);
+ SetWhichPor( POR_COMBINED );
+ if( aExpand.Len() > 6 )
+ aExpand.Erase( 6 );
+ // Initialization of the scripttype array,
+ // the arrays of width and position are filled by the format function
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ BYTE nScr = SW_SCRIPTS;
+ for( USHORT i = 0; i < rTxt.Len(); ++i )
+ {
+ USHORT nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i );
+ switch ( nScript ) {
+ case i18n::ScriptType::LATIN : nScr = SW_LATIN; break;
+ case i18n::ScriptType::ASIAN : nScr = SW_CJK; break;
+ case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break;
+ }
+ aScrType[i] = nScr;
+ }
+ }
+ else
+ {
+ for( USHORT i = 0; i < 6; aScrType[i++] = 0 )
+ ; // nothing
+ }
+ memset( &aWidth, 0, sizeof(aWidth) );
+}
+
+/*************************************************************************
+ * SwCombinedPortion::Paint(..)
+ *************************************************************************/
+
+void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
+ if( Width() )
+ {
+ rInf.DrawBackBrush( *this );
+ rInf.DrawViewOpt( *this, POR_FLD );
+
+ // do we have to repaint a post it portion?
+ if( rInf.OnWin() && pPortion && !pPortion->Width() )
+ pPortion->PrePaint( rInf, this );
+
+ USHORT nCount = aExpand.Len();
+ if( !nCount )
+ return;
+ ASSERT( nCount < 7, "Too much combined characters" );
+
+ // the first character of the second row
+ USHORT nTop = ( nCount + 1 ) / 2;
+
+ SwFont aTmpFont( *rInf.GetFont() );
+ aTmpFont.SetProportion( nProportion ); // a smaller font
+ SwFontSave aFontSave( rInf, &aTmpFont );
+
+ USHORT i = 0;
+ Point aOldPos = rInf.GetPos();
+ Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row
+ while( i < nCount )
+ {
+ if( i == nTop ) // change the row
+ aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row
+ aOutPos.X() = aOldPos.X() + aPos[i]; // X position
+ const BYTE nAct = aScrType[i]; // script type
+ aTmpFont.SetActual( nAct );
+ // if there're more than 4 characters to display, we choose fonts
+ // with 2/3 of the original font width.
+ if( aWidth[ nAct ] )
+ {
+ Size aTmpSz = aTmpFont.GetSize( nAct );
+ if( aTmpSz.Width() != aWidth[ nAct ] )
+ {
+ aTmpSz.Width() = aWidth[ nAct ];
+ aTmpFont.SetSize( aTmpSz, nAct );
+ }
+ }
+ ((SwTxtPaintInfo&)rInf).SetPos( aOutPos );
+ rInf.DrawText( aExpand, *this, i, 1 );
+ ++i;
+ }
+ // rInf is const, so we have to take back our manipulations
+ ((SwTxtPaintInfo&)rInf).SetPos( aOldPos );
+ }
+}
+
+/*************************************************************************
+ * SwCombinedPortion::Format(..)
+ *************************************************************************/
+
+sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf )
+{
+ USHORT nCount = aExpand.Len();
+ if( !nCount )
+ {
+ Width( 0 );
+ return sal_False;
+ }
+
+ ASSERT( nCount < 7, "Too much combined characters" );
+ // If there are leading "weak"-scripttyped characters in this portion,
+ // they get the actual scripttype.
+ USHORT i = 0;
+ while( i < nCount && SW_SCRIPTS == aScrType[i] )
+ aScrType[i++] = rInf.GetFont()->GetActual();
+ if( nCount > 4 )
+ {
+ // more than four? Ok, then we need the 2/3 font width
+ i = 0;
+ while( i < aExpand.Len() )
+ {
+ ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" );
+ if( !aWidth[ aScrType[i] ] )
+ {
+ rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) );
+ aWidth[ aScrType[i] ] =
+ static_cast<USHORT>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3);
+ }
+ ++i;
+ }
+ }
+
+ USHORT nTop = ( nCount + 1 ) / 2; // the first character of the second line
+ ViewShell *pSh = rInf.GetTxtFrm()->GetShell();
+ SwFont aTmpFont( *rInf.GetFont() );
+ SwFontSave aFontSave( rInf, &aTmpFont );
+ nProportion = 55;
+ // In nMainAscent/Descent we store the ascent and descent
+ // of the original surrounding font
+ USHORT nMaxDescent, nMaxAscent, nMaxWidth;
+ USHORT nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() );
+ const USHORT nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() );
+ nMainDescent = nMainDescent - nMainAscent;
+ // we start with a 50% font, but if we notice that the combined portion
+ // becomes bigger than the surrounding font, we check 45% and maybe 40%.
+ do
+ {
+ nProportion -= 5;
+ aTmpFont.SetProportion( nProportion );
+ i = 0;
+ memset( &aPos, 0, sizeof(aPos) );
+ nMaxDescent = 0;
+ nMaxAscent = 0;
+ nMaxWidth = 0;
+ nUpPos = nLowPos = 0;
+
+ // Now we get the width of all characters.
+ // The ascent and the width of the first line are stored in the
+ // ascent member of the portion, the descent in nLowPos.
+ // The ascent, descent and width of the second line are stored in the
+ // local nMaxAscent, nMaxDescent and nMaxWidth variables.
+ while( i < nCount )
+ {
+ BYTE nScrp = aScrType[i];
+ aTmpFont.SetActual( nScrp );
+ if( aWidth[ nScrp ] )
+ {
+ Size aFontSize( aTmpFont.GetSize( nScrp ) );
+ aFontSize.Width() = aWidth[ nScrp ];
+ aTmpFont.SetSize( aFontSize, nScrp );
+ }
+
+ SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 );
+ Size aSize = aTmpFont._GetTxtSize( aDrawInf );
+ USHORT nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() );
+ aPos[ i ] = (USHORT)aSize.Width();
+ if( i == nTop ) // enter the second line
+ {
+ nLowPos = nMaxDescent;
+ Height( nMaxDescent + nMaxAscent );
+ Width( nMaxWidth );
+ SetAscent( nMaxAscent );
+ nMaxAscent = 0;
+ nMaxDescent = 0;
+ nMaxWidth = 0;
+ }
+ nMaxWidth = nMaxWidth + aPos[ i++ ];
+ if( nAsc > nMaxAscent )
+ nMaxAscent = nAsc;
+ if( aSize.Height() - nAsc > nMaxDescent )
+ nMaxDescent = static_cast<USHORT>(aSize.Height() - nAsc);
+ }
+ // for one or two characters we double the width of the portion
+ if( nCount < 3 )
+ {
+ nMaxWidth *= 2;
+ Width( 2*Width() );
+ if( nCount < 2 )
+ {
+ Height( nMaxAscent + nMaxDescent );
+ nLowPos = nMaxDescent;
+ }
+ }
+ Height( Height() + nMaxDescent + nMaxAscent );
+ nUpPos = nMaxAscent;
+ SetAscent( Height() - nMaxDescent - nLowPos );
+ } while( nProportion > 40 && ( GetAscent() > nMainAscent ||
+ Height() - GetAscent() > nMainDescent ) );
+ // if the combined portion is smaller than the surrounding text,
+ // the portion grows. This looks better, if there's a character background.
+ if( GetAscent() < nMainAscent )
+ {
+ Height( Height() + nMainAscent - GetAscent() );
+ SetAscent( nMainAscent );
+ }
+ if( Height() < nMainAscent + nMainDescent )
+ Height( nMainAscent + nMainDescent );
+
+ // We calculate the x positions of the characters in both lines..
+ USHORT nTopDiff = 0;
+ USHORT nBotDiff = 0;
+ if( nMaxWidth > Width() )
+ {
+ nTopDiff = ( nMaxWidth - Width() ) / 2;
+ Width( nMaxWidth );
+ }
+ else
+ nBotDiff = ( Width() - nMaxWidth ) / 2;
+ switch( nTop)
+ {
+ case 3: aPos[1] = aPos[0] + nTopDiff; // no break
+ case 2: aPos[nTop-1] = Width() - aPos[nTop-1];
+ }
+ aPos[0] = 0;
+ switch( nCount )
+ {
+ case 5: aPos[4] = aPos[3] + nBotDiff; // no break
+ case 3: aPos[nTop] = nBotDiff; break;
+ case 6: aPos[4] = aPos[3] + nBotDiff; // no break
+ case 4: aPos[nTop] = 0; // no break
+ case 2: aPos[nCount-1] = Width() - aPos[nCount-1];
+ }
+
+ // Does the combined portion fit the line?
+ const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
+ if( bFull )
+ {
+ if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp()
+ || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) )
+ Width( (USHORT)( rInf.Width() - rInf.X() ) );
+ else
+ {
+ Truncate();
+ Width( 0 );
+ SetLen( 0 );
+ if( rInf.GetLast() )
+ rInf.GetLast()->FormatEOL( rInf );
+ }
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * SwCombinedPortion::GetViewWidth(..)
+ *************************************************************************/
+
+KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ if( !GetLen() ) // for the dummy part at the end of the line, where
+ return 0; // the combined portion doesn't fit.
+ return SwFldPortion::GetViewWidth( rInf );
+}
diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx
new file mode 100644
index 000000000000..ad71ce0c6a47
--- /dev/null
+++ b/sw/source/core/text/porfld.hxx
@@ -0,0 +1,274 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORFLD_HXX
+#define _PORFLD_HXX
+
+#include "swtypes.hxx"
+#include "porexp.hxx"
+#include <fmtornt.hxx>
+
+class SwFont;
+class SvxBrushItem;
+class SwFmtVertOrient;
+class SwFrm;
+
+/*************************************************************************
+ * class SwFldPortion
+ *************************************************************************/
+
+class SwFldPortion : public SwExpandPortion
+{
+ friend class SwTxtFormatter;
+protected:
+ XubString aExpand; // das expandierte Feld
+ SwFont *pFnt; // Fuer mehrzeilige Felder
+ xub_StrLen nNextOffset; // Offset des Follows im Originalstring
+ xub_StrLen nNextScriptChg;
+ KSHORT nViewWidth; // Screenbreite fuer leere Felder
+ sal_Bool bFollow : 1; // 2. oder weiterer Teil eines Feldes
+ sal_Bool bLeft : 1; // wird von SwNumberPortion benutzt
+ sal_Bool bHide : 1; // wird von SwNumberPortion benutzt
+ sal_Bool bCenter : 1; // wird von SwNumberPortion benutzt
+ sal_Bool bHasFollow : 1; // geht in der naechsten Zeile weiter
+ sal_Bool bAnimated : 1; // wird von SwGrfNumPortion benutzt
+ sal_Bool bNoPaint : 1; // wird von SwGrfNumPortion benutzt
+ sal_Bool bReplace : 1; // wird von SwGrfNumPortion benutzt
+ const sal_Bool bPlaceHolder : 1;
+ sal_Bool m_bNoLength : 1; // HACK for meta suffix (no CH_TXTATR)
+
+ inline void SetFont( SwFont *pNew ) { pFnt = pNew; }
+ inline bool IsNoLength() const { return m_bNoLength; }
+ inline void SetNoLength() { m_bNoLength = sal_True; }
+
+public:
+ SwFldPortion( const SwFldPortion& rFld );
+ SwFldPortion( const XubString &rExpand, SwFont *pFnt = 0, sal_Bool bPlaceHolder = sal_False );
+ ~SwFldPortion();
+
+ void TakeNextOffset( const SwFldPortion* pFld );
+ void CheckScript( const SwTxtSizeInfo &rInf );
+ inline sal_Bool HasFont() const { return 0 != pFnt; }
+ // --> OD 2008-06-05 #i89179# - made public
+ inline const SwFont *GetFont() const { return pFnt; }
+ // <--
+
+ inline const XubString &GetExp() const { return aExpand; }
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+
+ // leere Felder sind auch erlaubt
+ virtual SwLinePortion *Compress();
+
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+
+ inline sal_Bool IsFollow() const { return bFollow; }
+ inline void SetFollow( sal_Bool bNew ) { bFollow = bNew; }
+
+ inline sal_Bool IsLeft() const { return bLeft; }
+ inline void SetLeft( sal_Bool bNew ) { bLeft = bNew; }
+
+ inline sal_Bool IsHide() const { return bHide; }
+ inline void SetHide( sal_Bool bNew ) { bHide = bNew; }
+
+ inline sal_Bool IsCenter() const { return bCenter; }
+ inline void SetCenter( sal_Bool bNew ) { bCenter = bNew; }
+
+ inline sal_Bool HasFollow() const { return bHasFollow; }
+ inline void SetHasFollow( sal_Bool bNew ) { bHasFollow = bNew; }
+
+ inline xub_StrLen GetNextOffset() const { return nNextOffset; }
+ inline void SetNextOffset( xub_StrLen nNew ) { nNextOffset = nNew; }
+
+ inline xub_StrLen GetNextScriptChg() const { return nNextScriptChg; }
+ inline void SetNextScriptChg( xub_StrLen nNew ) { nNextScriptChg = nNew; }
+
+ // Felder-Cloner fuer SplitGlue
+ virtual SwFldPortion *Clone( const XubString &rExpand ) const;
+
+ // Extra-GetTxtSize wegen pFnt
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwHiddenPortion
+ *************************************************************************/
+// Unterscheidung nur fuer's Painten/verstecken.
+
+class SwHiddenPortion : public SwFldPortion
+{
+public:
+ inline SwHiddenPortion( const XubString &rExpand, SwFont *pFntL = 0 )
+ : SwFldPortion( rExpand, pFntL )
+ { SetLen(1); SetWhichPor( POR_HIDDEN ); }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+
+ // Felder-Cloner fuer SplitGlue
+ virtual SwFldPortion *Clone( const XubString &rExpand ) const;
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwNumberPortion
+ *************************************************************************/
+
+class SwNumberPortion : public SwFldPortion
+{
+protected:
+ KSHORT nFixWidth; // vgl. Glues
+ KSHORT nMinDist; // minimaler Abstand zum Text
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ bool mbLabelAlignmentPosAndSpaceModeActive;
+ // <--
+
+public:
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ SwNumberPortion( const XubString &rExpand,
+ SwFont *pFnt,
+ const sal_Bool bLeft,
+ const sal_Bool bCenter,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive );
+ // <--
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual xub_StrLen GetCrsrOfst( const MSHORT nOfst ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+
+ // Felder-Cloner fuer SplitGlue
+ virtual SwFldPortion *Clone( const XubString &rExpand ) const;
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwBulletPortion
+ *************************************************************************/
+
+class SwBulletPortion : public SwNumberPortion
+{
+public:
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ SwBulletPortion( const xub_Unicode cCh,
+ const XubString& rBulletFollowedBy,
+ SwFont *pFnt,
+ const sal_Bool bLeft,
+ const sal_Bool bCenter,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive );
+ // <--
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwBmpBulletPortion
+ *************************************************************************/
+
+class SwGrfNumPortion : public SwNumberPortion
+{
+ SvxBrushItem* pBrush;
+ long nId; //fuer StopAnimation
+ SwTwips nYPos; //Enthaelt _immer_ die aktuelle RelPos.
+ SwTwips nGrfHeight;
+ sal_Int16 eOrient;
+public:
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ SwGrfNumPortion( SwFrm *pFrm,
+ const XubString& rGraphicFollowedBy,
+ const SvxBrushItem* pGrfBrush,
+ const SwFmtVertOrient* pGrfOrient,
+ const Size& rGrfSize,
+ const sal_Bool bLeft,
+ const sal_Bool bCenter,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive );
+ // <--
+ ~SwGrfNumPortion();
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+
+ void SetBase( long nLnAscent, long nLnDescent,
+ long nFlyAscent, long nFlyDescent );
+
+ void StopAnimation( OutputDevice* pOut );
+
+ inline sal_Bool IsAnimated() const { return bAnimated; }
+ inline void SetAnimated( sal_Bool bNew ) { bAnimated = bNew; }
+ inline sal_Bool DontPaint() const { return bNoPaint; }
+ inline void SetNoPaint( sal_Bool bNew ) { bNoPaint = bNew; }
+ inline void SetRelPos( SwTwips nNew ) { nYPos = nNew; }
+ inline void SetId( long nNew ) const
+ { ((SwGrfNumPortion*)this)->nId = nNew; }
+ inline SwTwips GetRelPos() const { return nYPos; }
+ inline SwTwips GetGrfHeight() const { return nGrfHeight; }
+ inline SwTwips GetId() const { return nId; }
+ inline sal_Int16 GetOrient() const { return eOrient; }
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwCombinedPortion
+ * Used in for asian layout specialities to display up to six characters
+ * in 2 rows and 2-3 columns.
+ * e.g.
+ *
+ * A.. A.. A.B A.B A.B.C A.B.C
+ * ... ..B .C. C.D .D.E. D.E.F
+ *************************************************************************/
+
+class SwCombinedPortion : public SwFldPortion
+{
+ USHORT aPos[6]; // up to six X positions
+ USHORT aWidth[3]; // one width for every scripttype
+ BYTE aScrType[6]; // scripttype of every character
+ USHORT nUpPos; // the Y position of the upper baseline
+ USHORT nLowPos; // the Y position of the lower baseline
+ BYTE nProportion; // relative font height
+public:
+ SwCombinedPortion( const XubString &rExpand );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+ OUTPUT_OPERATOR
+};
+
+
+CLASSIO( SwHiddenPortion )
+CLASSIO( SwNumberPortion )
+CLASSIO( SwBulletPortion )
+CLASSIO( SwGrfNumPortion )
+CLASSIO( SwCombinedPortion )
+
+
+#endif
diff --git a/sw/source/core/text/porfly.cxx b/sw/source/core/text/porfly.cxx
new file mode 100644
index 000000000000..0cad374e97e2
--- /dev/null
+++ b/sw/source/core/text/porfly.cxx
@@ -0,0 +1,454 @@
+/*************************************************************************
+ *
+ * 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 "dcontact.hxx" // SwDrawContact
+#include "dflyobj.hxx" // SwVirtFlyDrawObj
+#include "pam.hxx" // SwPosition
+#include "flyfrm.hxx" // SwFlyInCntFrm
+#include "frmfmt.hxx" // SwFrmFmt
+#include "viewsh.hxx"
+
+#include <vcl/outdev.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <fmtanchr.hxx>
+#include <fmtflcnt.hxx>
+#include <fmtornt.hxx>
+#include <frmatr.hxx>
+#include "flyfrms.hxx"
+#include "txatbase.hxx" // SwTxtAttr
+#include "porfly.hxx"
+#include "porlay.hxx" // SetFly
+#include "inftxt.hxx" // SwTxtPaintInfo
+
+// OD 2004-05-24 #i28701#
+#include <sortedobjs.hxx>
+
+
+/*************************************************************************
+ * class SwFlyPortion
+ *
+ * Wir erwarten ein framelokales SwRect !
+ *************************************************************************/
+
+void SwFlyPortion::Paint( const SwTxtPaintInfo& ) const
+{
+}
+
+/*************************************************************************
+ * virtual SwFlyPortion::Format()
+ *************************************************************************/
+sal_Bool SwFlyPortion::Format( SwTxtFormatInfo &rInf )
+{
+ ASSERT( Fix() >= rInf.X(), "SwFlyPortion::Format: rush hour" );
+ // 8537: Tabs muessen expandiert werden.
+ if( rInf.GetLastTab() )
+ ((SwLinePortion*)rInf.GetLastTab())->FormatEOL( rInf );
+
+ // Der Glue wird aufgespannt.
+ rInf.GetLast()->FormatEOL( rInf );
+ PrtWidth( static_cast<USHORT>(Fix() - rInf.X() + PrtWidth()) );
+ if( !Width() )
+ {
+ ASSERT( Width(), "+SwFlyPortion::Format: a fly is a fly is a fly" );
+ Width(1);
+ }
+
+ // Restaurierung
+ rInf.SetFly( 0 );
+ rInf.Width( rInf.RealWidth() );
+ rInf.GetParaPortion()->SetFly( sal_True );
+
+ // trailing blank:
+ if( rInf.GetIdx() < rInf.GetTxt().Len() && 1 < rInf.GetIdx()
+ && !rInf.GetRest()
+ && ' ' == rInf.GetChar( rInf.GetIdx() )
+ && ' ' != rInf.GetChar( rInf.GetIdx() - 1 )
+ && ( !rInf.GetLast() || !rInf.GetLast()->IsBreakPortion() ) )
+ {
+ SetBlankWidth( rInf.GetTxtSize( ' ' ).Width() );
+ SetLen( 1 );
+ }
+
+ const USHORT nNewWidth = static_cast<USHORT>(rInf.X() + PrtWidth());
+ if( rInf.Width() <= nNewWidth )
+ {
+ Truncate();
+ if( nNewWidth > rInf.Width() )
+ {
+ PrtWidth( nNewWidth - rInf.Width() );
+ SetFixWidth( PrtWidth() );
+ }
+ return sal_True;
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwFlyCntPortion::Format()
+ *************************************************************************/
+sal_Bool SwFlyCntPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_Bool bFull = rInf.Width() < rInf.X() + PrtWidth();
+
+ if( bFull )
+ {
+ // 3924: wenn die Zeile voll ist und der zeichengebundene Frame am
+ // Anfang der Zeile steht.
+ // 5157: nicht wenn einem Fly ausgewichen werden kann!
+ // "Begin of line" criteria ( ! rInf.X() ) has to be extended.
+ // KerningPortions at beginning of line, e.g., for grid layout
+ // must be considered.
+ const SwLinePortion* pLastPor = rInf.GetLast();
+ const USHORT nLeft = ( pLastPor &&
+ ( pLastPor->IsKernPortion() ||
+ pLastPor->IsErgoSumPortion() ) ) ?
+ pLastPor->Width() :
+ 0;
+
+ if( nLeft == rInf.X() && ! rInf.GetFly() )
+ {
+ Width( rInf.Width() );
+ bFull = sal_False; // Damit Notizen noch in dieser Zeile landen
+ }
+ else
+ {
+ if( !rInf.GetFly() )
+ rInf.SetNewLine( sal_True );
+ Width(0);
+ SetAscent(0);
+ SetLen(0);
+ if( rInf.GetLast() )
+ rInf.GetLast()->FormatEOL( rInf );
+
+ return bFull;
+ }
+ }
+
+ rInf.GetParaPortion()->SetFly( sal_True );
+ return bFull;
+}
+
+/*************************************************************************
+ * SwTxtFrm::MoveFlyInCnt() haengt jetzt die zeichengebundenen Objekte
+ * innerhalb des angegebenen Bereichs um, damit koennen diese vom Master
+ * zum Follow oder umgekehrt wandern.
+ *************************************************************************/
+void SwTxtFrm::MoveFlyInCnt( SwTxtFrm *pNew, xub_StrLen nStart, xub_StrLen nEnd )
+{
+ SwSortedObjs *pObjs = 0L;
+ if ( 0 != (pObjs = GetDrawObjs()) )
+ {
+ for ( sal_uInt32 i = 0; GetDrawObjs() && i < pObjs->Count(); ++i )
+ {
+ // OD 2004-03-29 #i26791#
+ // --> OD 2004-07-06 #i28701# - consider changed type of
+ // <SwSortedList> entries
+ SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
+ const SwFmtAnchor& rAnch = pAnchoredObj->GetFrmFmt().GetAnchor();
+ if (rAnch.GetAnchorId() == FLY_AS_CHAR)
+ {
+ const SwPosition* pPos = rAnch.GetCntntAnchor();
+ xub_StrLen nIdx = pPos->nContent.GetIndex();
+ if ( nIdx >= nStart && nEnd > nIdx )
+ {
+ if ( pAnchoredObj->ISA(SwFlyFrm) )
+ {
+ RemoveFly( static_cast<SwFlyFrm*>(pAnchoredObj) );
+ pNew->AppendFly( static_cast<SwFlyFrm*>(pAnchoredObj) );
+ }
+ else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) )
+ {
+ RemoveDrawObj( *pAnchoredObj );
+ pNew->AppendDrawObj( *pAnchoredObj );
+ }
+ --i;
+ }
+ }
+ // <--
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcFlyPos()
+ *************************************************************************/
+xub_StrLen SwTxtFrm::CalcFlyPos( SwFrmFmt* pSearch )
+{
+ SwpHints* pHints = GetTxtNode()->GetpSwpHints();
+ ASSERT( pHints, "CalcFlyPos: Why me?" );
+ if( !pHints )
+ return STRING_LEN;
+ SwTxtAttr* pFound = NULL;
+ for ( USHORT i = 0; i < pHints->Count(); i++)
+ {
+ SwTxtAttr *pHt = pHints->GetTextHint( i );
+ if( RES_TXTATR_FLYCNT == pHt->Which() )
+ {
+ SwFrmFmt* pFrmFmt = pHt->GetFlyCnt().GetFrmFmt();
+ if( pFrmFmt == pSearch )
+ pFound = pHt;
+ }
+ }
+ ASSERT( pHints, "CalcFlyPos: Not Found!" );
+ if( !pFound )
+ return STRING_LEN;
+ return *pFound->GetStart();
+}
+
+/*************************************************************************
+ * virtual SwFlyCntPortion::Paint()
+ *************************************************************************/
+void SwFlyCntPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( bDraw )
+ {
+ if( !((SwDrawContact*)pContact)->GetAnchorFrm() )
+ {
+ // OD 2004-04-01 #i26791# - no direct positioning of the drawing
+ // object is needed.
+ SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(pContact);
+ pDrawContact->ConnectToLayout();
+ }
+ }
+ else
+ {
+ // Baseline-Ausgabe !
+ // 7922: Bei CompletePaint alles painten
+ SwRect aRepaintRect( rInf.GetPaintRect() );
+
+ if ( rInf.GetTxtFrm()->IsRightToLeft() )
+ rInf.GetTxtFrm()->SwitchLTRtoRTL( aRepaintRect );
+
+ if ( rInf.GetTxtFrm()->IsVertical() )
+ rInf.GetTxtFrm()->SwitchHorizontalToVertical( aRepaintRect );
+
+ if( (GetFlyFrm()->IsCompletePaint() ||
+ GetFlyFrm()->Frm().IsOver( aRepaintRect )) &&
+ SwFlyFrm::IsPaint( (SdrObject*)GetFlyFrm()->GetVirtDrawObj(),
+ GetFlyFrm()->GetShell() ))
+ {
+ SwRect aRect( GetFlyFrm()->Frm() );
+ if( !GetFlyFrm()->IsCompletePaint() )
+ aRect._Intersection( aRepaintRect );
+
+
+ // GetFlyFrm() may change the layout mode at the output device.
+ {
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ GetFlyFrm()->Paint( aRect );
+ }
+ ((SwTxtPaintInfo&)rInf).GetRefDev()->SetLayoutMode(
+ rInf.GetOut()->GetLayoutMode() );
+
+ // Es hilft alles nichts, im zeichengebundenen Frame kann wer weiss
+ // was am OutputDevice eingestellt sein, wir muessen unseren Font
+ // wieder hineinselektieren. Dass wir im const stehen, soll uns
+ // daran nicht hindern:
+ ((SwTxtPaintInfo&)rInf).SelectFont();
+
+ // I want to know if this can really happen. So here comes a new
+ ASSERT( ! rInf.GetVsh() || rInf.GetVsh()->GetOut() == rInf.GetOut(),
+ "SwFlyCntPortion::Paint: Outdev has changed" )
+ if( rInf.GetVsh() )
+ ((SwTxtPaintInfo&)rInf).SetOut( rInf.GetVsh()->GetOut() );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwFlyCntPortion::SwFlyCntPortion()
+ *
+ * Es werden die Masze vom pFly->OutRect() eingestellt.
+ * Es erfolgt ein SetBase() !
+ *************************************************************************/
+// OD 29.07.2003 #110978# - use new datatype for parameter <nFlags>
+SwFlyCntPortion::SwFlyCntPortion( const SwTxtFrm& rFrm,
+ SwFlyInCntFrm *pFly, const Point &rBase,
+ long nLnAscent, long nLnDescent,
+ long nFlyAsc, long nFlyDesc,
+ objectpositioning::AsCharFlags nFlags ) :
+ pContact( pFly ),
+ bDraw( sal_False ),
+ bMax( sal_False ),
+ nAlign( 0 )
+{
+ ASSERT( pFly, "SwFlyCntPortion::SwFlyCntPortion: no SwFlyInCntFrm!" );
+ nLineLength = 1;
+ nFlags |= AS_CHAR_ULSPACE | AS_CHAR_INIT;
+ SetBase( rFrm, rBase, nLnAscent, nLnDescent, nFlyAsc, nFlyDesc, nFlags );
+ SetWhichPor( POR_FLYCNT );
+}
+
+// OD 29.07.2003 #110978# - use new datatype for parameter <nFlags>
+SwFlyCntPortion::SwFlyCntPortion( const SwTxtFrm& rFrm,
+ SwDrawContact *pDrawContact, const Point &rBase,
+ long nLnAscent, long nLnDescent,
+ long nFlyAsc, long nFlyDesc,
+ objectpositioning::AsCharFlags nFlags ) :
+ pContact( pDrawContact ),
+ bDraw( sal_True ),
+ bMax( sal_False ),
+ nAlign( 0 )
+{
+ ASSERT( pDrawContact, "SwFlyCntPortion::SwFlyCntPortion: no SwDrawContact!" );
+ if( !pDrawContact->GetAnchorFrm() )
+ {
+ // OD 2004-04-01 #i26791# - no direct positioning needed any more
+ pDrawContact->ConnectToLayout();
+ // --> OD 2005-01-14 #i40333# - follow-up of #i35635#
+ // move object to visible layer
+ pDrawContact->MoveObjToVisibleLayer( pDrawContact->GetMaster() );
+ // <--
+ }
+ nLineLength = 1;
+ nFlags |= AS_CHAR_ULSPACE | AS_CHAR_INIT;
+
+ SetBase( rFrm, rBase, nLnAscent, nLnDescent, nFlyAsc, nFlyDesc, nFlags );
+
+ SetWhichPor( POR_FLYCNT );
+}
+
+
+/*************************************************************************
+ * SwFlyCntPortion::SetBase()
+ *
+ * Nach dem Setzen des RefPoints muss der Ascent neu berechnet werden,
+ * da er von der RelPos abhaengt.
+ * pFly->GetRelPos().Y() bezeichnet die relative Position zur Baseline.
+ * Bei 0 liegt der obere Rand des FlyCnt auf der Baseline der Zeile.
+ *************************************************************************/
+// OD 29.07.2003 #110978# - use new datatype for parameter <nFlags>
+void SwFlyCntPortion::SetBase( const SwTxtFrm& rFrm, const Point &rBase,
+ long nLnAscent, long nLnDescent,
+ long nFlyAsc, long nFlyDesc,
+ objectpositioning::AsCharFlags nFlags )
+{
+ // Note: rBase have to be an absolute value
+
+ // OD 28.10.2003 #113049# - use new class to position object
+ // determine drawing object
+ SdrObject* pSdrObj = 0L;
+ if( bDraw )
+ {
+ // OD 20.06.2003 #108784# - determine drawing object ('master' or 'virtual')
+ // by frame.
+ pSdrObj = GetDrawContact()->GetDrawObjectByAnchorFrm( rFrm );
+ if ( !pSdrObj )
+ {
+ ASSERT( false, "SwFlyCntPortion::SetBase(..) - No drawing object found by <GetDrawContact()->GetDrawObjectByAnchorFrm( rFrm )>" );
+ pSdrObj = GetDrawContact()->GetMaster();
+ }
+ // --> OD 2007-11-29 #i65798#
+ // call <SwAnchoredDrawObject::MakeObjPos()> to assure that flag at
+ // the <DrawFrmFmt> and at the <SwAnchoredDrawObject> instance are
+ // correctly set.
+ if ( pSdrObj )
+ {
+ GetDrawContact()->GetAnchoredObj( pSdrObj )->MakeObjPos();
+ }
+ // <--
+ }
+ else
+ {
+ pSdrObj = GetFlyFrm()->GetVirtDrawObj();
+ }
+
+ // position object
+ objectpositioning::SwAsCharAnchoredObjectPosition aObjPositioning(
+ *pSdrObj,
+ rBase, nFlags,
+ nLnAscent, nLnDescent, nFlyAsc, nFlyDesc );
+
+ // OD 2004-04-13 #i26791# - scope of local variable <aObjPosInProgress>
+ {
+ // OD 2004-04-13 #i26791#
+ SwObjPositioningInProgress aObjPosInProgress( *pSdrObj );
+ aObjPositioning.CalcPosition();
+ }
+
+ SetAlign( aObjPositioning.GetLineAlignment() );
+
+ aRef = aObjPositioning.GetAnchorPos();
+ if( nFlags & AS_CHAR_ROTATE )
+ SvXSize( aObjPositioning.GetObjBoundRectInclSpacing().SSize() );
+ else
+ SvLSize( aObjPositioning.GetObjBoundRectInclSpacing().SSize() );
+ if( Height() )
+ {
+ SwTwips nRelPos = aObjPositioning.GetRelPosY();
+ if ( nRelPos < 0 )
+ {
+ nAscent = static_cast<USHORT>(-nRelPos);
+ if( nAscent > Height() )
+ Height( nAscent );
+ }
+ else
+ {
+ nAscent = 0;
+ Height( Height() + static_cast<USHORT>(nRelPos) );
+ }
+ }
+ else
+ {
+ Height( 1 );
+ nAscent = 0;
+ }
+}
+
+/*************************************************************************
+ * virtual SwFlyCntPortion::GetFlyCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwFlyCntPortion::GetFlyCrsrOfst( const KSHORT nOfst,
+ const Point &rPoint, SwPosition *pPos, SwCrsrMoveState* pCMS ) const
+{
+ // Da die FlyCnt nicht an der Seite haengen, wird ihr
+ // GetCrsrOfst() nicht gerufen. Um die Layoutseite
+ // von unnoetiger Verwaltung zu entlasten, ruft der Absatz
+ // das GetCrsrOfst des FlyFrm, wenn es erforderlich ist.
+ Point aPoint( rPoint );
+ if( !pPos || bDraw || !( GetFlyFrm()->GetCrsrOfst( pPos, aPoint, pCMS ) ) )
+ return SwLinePortion::GetCrsrOfst( nOfst );
+ else
+ return 0;
+}
+
+/*************************************************************************
+ * virtual SwFlyCntPortion::GetCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwFlyCntPortion::GetCrsrOfst( const KSHORT nOfst ) const
+{
+ // ASSERT( !this, "SwFlyCntPortion::GetCrsrOfst: use GetFlyCrsrOfst()" );
+ return SwLinePortion::GetCrsrOfst( nOfst );
+}
+
diff --git a/sw/source/core/text/porfly.hxx b/sw/source/core/text/porfly.hxx
new file mode 100644
index 000000000000..48590ec55100
--- /dev/null
+++ b/sw/source/core/text/porfly.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORFLY_HXX
+#define _PORFLY_HXX
+// OD 28.10.2003 #113049#
+#include <ascharanchoredobjectposition.hxx>
+
+#include "porglue.hxx"
+
+class SwDrawContact;
+class SwFlyInCntFrm;
+class SwTxtFrm;
+struct SwCrsrMoveState;
+
+/*************************************************************************
+ * class SwFlyPortion
+ *************************************************************************/
+
+class SwFlyPortion : public SwFixPortion
+{
+ KSHORT nBlankWidth;
+public:
+ inline SwFlyPortion( const SwRect &rFlyRect )
+ : SwFixPortion(rFlyRect), nBlankWidth( 0 ) { SetWhichPor( POR_FLY ); }
+ inline KSHORT GetBlankWidth( ) const { return nBlankWidth; }
+ inline void SetBlankWidth( const KSHORT nNew ) { nBlankWidth = nNew; }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwFlyCntPortion
+ *************************************************************************/
+
+class SwFlyCntPortion : public SwLinePortion
+{
+ void *pContact; // bDraw ? DrawContact : FlyInCntFrm
+ Point aRef; // Relativ zu diesem Point wird die AbsPos berechnet.
+ sal_Bool bDraw : 1; // DrawContact?
+ sal_Bool bMax : 1; // Zeilenausrichtung und Hoehe == Zeilenhoehe
+ sal_uInt8 nAlign : 3; // Zeilenausrichtung? Nein, oben, mitte, unten
+ virtual xub_StrLen GetCrsrOfst( const KSHORT nOfst ) const;
+
+public:
+ // OD 29.07.2003 #110978# - use new datatype for parameter <nFlags>
+ SwFlyCntPortion( const SwTxtFrm& rFrm, SwFlyInCntFrm *pFly,
+ const Point &rBase,
+ long nAscent, long nDescent, long nFlyAsc, long nFlyDesc,
+ objectpositioning::AsCharFlags nFlags );
+ // OD 29.07.2003 #110978# - use new datatype for parameter <nFlags>
+ SwFlyCntPortion( const SwTxtFrm& rFrm, SwDrawContact *pDrawContact,
+ const Point &rBase,
+ long nAscent, long nDescent, long nFlyAsc, long nFlyDesc,
+ objectpositioning::AsCharFlags nFlags );
+ inline const Point& GetRefPoint() const { return aRef; }
+ inline SwFlyInCntFrm *GetFlyFrm() { return (SwFlyInCntFrm*)pContact; }
+ inline const SwFlyInCntFrm *GetFlyFrm() const
+ { return (SwFlyInCntFrm*)pContact; }
+ inline SwDrawContact *GetDrawContact() { return (SwDrawContact*)pContact; }
+ inline const SwDrawContact* GetDrawContact() const
+ { return (SwDrawContact*)pContact; }
+ inline sal_Bool IsDraw() const { return bDraw; }
+ inline sal_Bool IsMax() const { return bMax; }
+ inline sal_uInt8 GetAlign() const { return nAlign; }
+ inline void SetAlign( sal_uInt8 nNew ) { nAlign = nNew; }
+ inline void SetMax( sal_Bool bNew ) { bMax = bNew; }
+ // OD 29.07.2003 #110978# - use new datatype for parameter <nFlags>
+ void SetBase( const SwTxtFrm& rFrm, const Point &rBase,
+ long nLnAscent, long nLnDescent,
+ long nFlyAscent, long nFlyDescent,
+ objectpositioning::AsCharFlags nFlags );
+ xub_StrLen GetFlyCrsrOfst( const KSHORT nOfst, const Point &rPoint,
+ SwPosition *pPos, SwCrsrMoveState* pCMS ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ OUTPUT_OPERATOR
+};
+
+CLASSIO( SwFlyPortion )
+CLASSIO( SwFlyCntPortion )
+
+
+#endif
diff --git a/sw/source/core/text/porftn.hxx b/sw/source/core/text/porftn.hxx
new file mode 100644
index 000000000000..5590b6f972d3
--- /dev/null
+++ b/sw/source/core/text/porftn.hxx
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORFTN_HXX
+#define _PORFTN_HXX
+
+#include "porfld.hxx"
+
+class SwTxtFrm;
+class SwTxtFtn;
+
+/*************************************************************************
+ * class SwFtnPortion
+ *************************************************************************/
+
+class SwFtnPortion : public SwFldPortion
+{
+ SwTxtFrm *pFrm; // um im Dtor RemoveFtn rufen zu koennen.
+ SwTxtFtn *pFtn;
+ KSHORT nOrigHeight;
+ // --> OD 2009-01-29 #i98418#
+ bool mbPreferredScriptTypeSet;
+ BYTE mnPreferredScriptType;
+ // <--
+public:
+ SwFtnPortion( const XubString &rExpand, SwTxtFrm *pFrm, SwTxtFtn *pFtn,
+ KSHORT nOrig = KSHRT_MAX );
+ inline KSHORT& Orig() { return nOrigHeight; }
+
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+
+ // --> OD 2009-01-29 #i98418#
+ void SetPreferredScriptType( BYTE nPreferredScriptType );
+ // <--
+
+ const SwTxtFtn* GetTxtFtn() const { return pFtn; };
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwFtnNumPortion
+ *************************************************************************/
+
+class SwFtnNumPortion : public SwNumberPortion
+{
+public:
+ inline SwFtnNumPortion( const XubString &rExpand, SwFont *pFntL )
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ : SwNumberPortion( rExpand, pFntL, sal_True, sal_False, 0, false )
+ // <--
+ { SetWhichPor( POR_FTNNUM ); }
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwQuoVadisPortion
+ *************************************************************************/
+
+class SwQuoVadisPortion : public SwFldPortion
+{
+ XubString aErgo;
+public:
+ SwQuoVadisPortion( const XubString &rExp, const XubString& rStr );
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+
+ inline void SetNumber( const XubString& rStr ) { aErgo = rStr; }
+ inline const XubString &GetQuoTxt() const { return aExpand; }
+ inline const XubString &GetContTxt() const { return aErgo; }
+
+ // Felder-Cloner fuer SplitGlue
+ virtual SwFldPortion *Clone( const XubString &rExpand ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwErgoSumPortion
+ *************************************************************************/
+
+class SwErgoSumPortion : public SwFldPortion
+{
+public:
+ SwErgoSumPortion( const XubString &rExp, const XubString& rStr );
+ virtual xub_StrLen GetCrsrOfst( const KSHORT nOfst ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+
+ // Felder-Cloner fuer SplitGlue
+ virtual SwFldPortion *Clone( const XubString &rExpand ) const;
+ OUTPUT_OPERATOR
+};
+
+CLASSIO( SwFtnPortion )
+CLASSIO( SwFtnNumPortion )
+CLASSIO( SwQuoVadisPortion )
+CLASSIO( SwErgoSumPortion )
+
+
+#endif
diff --git a/sw/source/core/text/porglue.cxx b/sw/source/core/text/porglue.cxx
new file mode 100644
index 000000000000..983f5aded904
--- /dev/null
+++ b/sw/source/core/text/porglue.cxx
@@ -0,0 +1,318 @@
+/*************************************************************************
+ *
+ * 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 "swrect.hxx"
+#include "paratr.hxx" // pTabStop, ADJ*
+#include "viewopt.hxx" // SwViewOptions
+#include "errhdl.hxx" // ASSERT
+#include <SwPortionHandler.hxx>
+
+#include "txtcfg.hxx"
+#include "porglue.hxx"
+#include "inftxt.hxx"
+#include "porlay.hxx" // SwParaPortion, SetFull
+#include "porfly.hxx" // SwParaPortion, SetFull
+
+/*************************************************************************
+ * class SwGluePortion
+ *************************************************************************/
+
+SwGluePortion::SwGluePortion( const KSHORT nInitFixWidth )
+ : nFixWidth( nInitFixWidth )
+{
+ PrtWidth( nFixWidth );
+ SetWhichPor( POR_GLUE );
+}
+
+/*************************************************************************
+ * virtual SwGluePortion::GetCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwGluePortion::GetCrsrOfst( const KSHORT nOfst ) const
+{
+ if( !GetLen() || nOfst > GetLen() || !Width() )
+ return SwLinePortion::GetCrsrOfst( nOfst );
+ else
+ return nOfst / (Width() / GetLen());
+}
+
+/*************************************************************************
+ * virtual SwGluePortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwGluePortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
+{
+ if( 1 >= GetLen() || rInf.GetLen() > GetLen() || !Width() || !GetLen() )
+ return SwPosSize(*this);
+ else
+ return SwPosSize( (Width() / GetLen()) * rInf.GetLen(), Height() );
+}
+
+/*************************************************************************
+ * virtual SwGluePortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwGluePortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ if( GetLen() && rInf.OnWin() &&
+ rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() )
+ {
+ rTxt.Fill( GetLen(), CH_BULLET );
+ return sal_True;
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwGluePortion::Paint()
+ *************************************************************************/
+
+void SwGluePortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( !GetLen() )
+ return;
+
+ if( rInf.GetFont()->IsPaintBlank() )
+ {
+ XubString aTxt;
+ aTxt.Fill( GetFixWidth() / GetLen(), ' ' );
+ SwTxtPaintInfo aInf( rInf, aTxt );
+ aInf.DrawText( *this, aTxt.Len(), sal_True );
+ }
+
+ if( rInf.OnWin() && rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() )
+ {
+#ifdef DBG_UTIL
+ const xub_Unicode cChar = rInf.GetChar( rInf.GetIdx() );
+ ASSERT( CH_BLANK == cChar || CH_BULLET == cChar,
+ "SwGluePortion::Paint: blank expected" );
+#endif
+ if( 1 == GetLen() )
+ {
+ String aBullet( CH_BULLET );
+ SwPosSize aBulletSize( rInf.GetTxtSize( aBullet ) );
+ Point aPos( rInf.GetPos() );
+ aPos.X() += (Width()/2) - (aBulletSize.Width()/2);
+ SwTxtPaintInfo aInf( rInf, aBullet );
+ aInf.SetPos( aPos );
+ SwTxtPortion aBulletPor;
+ aBulletPor.Width( aBulletSize.Width() );
+ aBulletPor.Height( aBulletSize.Height() );
+ aBulletPor.SetAscent( GetAscent() );
+ aInf.DrawText( aBulletPor, aBullet.Len(), sal_True );
+ }
+ else
+ {
+ SwTxtSlot aSlot( &rInf, this, true, false );
+ rInf.DrawText( *this, rInf.GetLen(), sal_True );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwGluePortion::MoveGlue()
+ *************************************************************************/
+
+void SwGluePortion::MoveGlue( SwGluePortion *pTarget, const short nPrtGlue )
+{
+ short nPrt = Min( nPrtGlue, GetPrtGlue() );
+ if( 0 < nPrt )
+ {
+ pTarget->AddPrtWidth( nPrt );
+ SubPrtWidth( nPrt );
+ }
+}
+
+/*************************************************************************
+ * void SwGluePortion::Join()
+ *************************************************************************/
+
+void SwGluePortion::Join( SwGluePortion *pVictim )
+{
+ // Die GluePortion wird ausgesogen und weggespuelt ...
+ AddPrtWidth( pVictim->PrtWidth() );
+ SetLen( pVictim->GetLen() + GetLen() );
+ if( Height() < pVictim->Height() )
+ Height( pVictim->Height() );
+
+ AdjFixWidth();
+ Cut( pVictim );
+ delete pVictim;
+}
+
+/*************************************************************************
+ * class SwFixPortion
+ *************************************************************************/
+
+// Wir erwarten ein framelokales SwRect !
+SwFixPortion::SwFixPortion( const SwRect &rRect )
+ :SwGluePortion( KSHORT(rRect.Width()) ), nFix( KSHORT(rRect.Left()) )
+{
+ Height( KSHORT(rRect.Height()) );
+ SetWhichPor( POR_FIX );
+}
+
+SwFixPortion::SwFixPortion(const KSHORT nFixedWidth, const KSHORT nFixedPos)
+ : SwGluePortion(nFixedWidth), nFix(nFixedPos)
+{
+ SetWhichPor( POR_FIX );
+}
+
+/*************************************************************************
+ * class SwMarginPortion
+ *************************************************************************/
+
+SwMarginPortion::SwMarginPortion( const KSHORT nFixedWidth )
+ :SwGluePortion( nFixedWidth )
+{
+ SetWhichPor( POR_MARGIN );
+}
+
+/*************************************************************************
+ * SwMarginPortion::AdjustRight()
+ *
+ * In der umschliessenden Schleife werden alle Portions durchsucht,
+ * dabei werden erst die am Ende liegenden GluePortions verarbeitet.
+ * Das Ende wird nach jeder Schleife nach vorne verlegt, bis keine
+ * GluePortions mehr vorhanden sind.
+ * Es werden immer GluePortion-Paare betrachtet (pLeft und pRight),
+ * wobei Textportions zwischen pLeft und pRight hinter pRight verschoben
+ * werden, wenn pRight genuegend Glue besitzt. Bei jeder Verschiebung
+ * wandert ein Teil des Glues von pRight nach pLeft.
+ * Im naechsten Schleifendurchlauf ist pLeft das pRight und das Spiel
+ * beginnt von vorne.
+ *************************************************************************/
+
+void SwMarginPortion::AdjustRight( const SwLineLayout *pCurr )
+{
+ SwGluePortion *pRight = 0;
+ BOOL bNoMove = 0 != pCurr->GetpKanaComp();
+ while( pRight != this )
+ {
+
+ // 1) Wir suchen den linken Glue
+ SwLinePortion *pPos = (SwLinePortion*)this;
+ SwGluePortion *pLeft = 0;
+ while( pPos )
+ {
+ DBG_LOOP;
+ if( pPos->InFixMargGrp() )
+ pLeft = (SwGluePortion*)pPos;
+ pPos = pPos->GetPortion();
+ if( pPos == pRight)
+ pPos = 0;
+ }
+
+ // Zwei nebeneinander liegende FlyPortions verschmelzen
+ if( pRight && pLeft->GetPortion() == pRight )
+ {
+ pRight->MoveAllGlue( pLeft );
+ pRight = 0;
+ }
+ KSHORT nRightGlue = pRight && 0 < pRight->GetPrtGlue()
+ ? KSHORT(pRight->GetPrtGlue()) : 0;
+ // 2) linken und rechten Glue ausgleichen
+ // Bei Tabs haengen wir nix um ...
+ if( pLeft && nRightGlue && !pRight->InTabGrp() )
+ {
+ // pPrev ist die Portion, die unmittelbar vor pRight liegt.
+ SwLinePortion *pPrev = pRight->FindPrevPortion( pLeft );
+
+ if ( pRight->IsFlyPortion() && pRight->GetLen() )
+ {
+ SwFlyPortion *pFly = (SwFlyPortion *)pRight;
+ if ( pFly->GetBlankWidth() < nRightGlue )
+ {
+ // Hier entsteht eine neue TxtPortion, die dass zuvor
+ // vom Fly verschluckte Blank reaktiviert.
+ nRightGlue = nRightGlue - pFly->GetBlankWidth();
+ pFly->SubPrtWidth( pFly->GetBlankWidth() );
+ pFly->SetLen( 0 );
+ SwTxtPortion *pNewPor = new SwTxtPortion;
+ pNewPor->SetLen( 1 );
+ pNewPor->Height( pFly->Height() );
+ pNewPor->Width( pFly->GetBlankWidth() );
+ pFly->Insert( pNewPor );
+ }
+ else
+ pPrev = pLeft;
+ }
+ while( pPrev != pLeft )
+ {
+ DBG_LOOP;
+
+ if( bNoMove || pPrev->PrtWidth() >= nRightGlue ||
+ pPrev->InHyphGrp() || pPrev->IsKernPortion() )
+ {
+ // Die Portion, die vor pRight liegt kann nicht
+ // verschoben werden, weil kein Glue mehr vorhanden ist.
+ // Wir fuehren die Abbruchbedingung herbei:
+ pPrev = pLeft;
+ }
+ else
+ {
+ nRightGlue = nRightGlue - pPrev->PrtWidth();
+ // pPrev wird hinter pRight verschoben.
+ // Dazu wird der Gluewert zwischen pRight und pLeft
+ // ausgeglichen.
+ pRight->MoveGlue( pLeft, short( pPrev->PrtWidth() ) );
+ // Jetzt wird die Verkettung gerichtet.
+ SwLinePortion *pPrevPrev = pPrev->FindPrevPortion( pLeft );
+ pPrevPrev->SetPortion( pRight );
+ pPrev->SetPortion( pRight->GetPortion() );
+ pRight->SetPortion( pPrev );
+ if ( pPrev->GetPortion() && pPrev->InTxtGrp()
+ && pPrev->GetPortion()->IsHolePortion() )
+ {
+ SwHolePortion *pHolePor =
+ (SwHolePortion*)pPrev->GetPortion();
+ if ( !pHolePor->GetPortion() ||
+ !pHolePor->GetPortion()->InFixMargGrp() )
+ {
+ pPrev->AddPrtWidth( pHolePor->GetBlankWidth() );
+ pPrev->SetLen( pPrev->GetLen() + 1 );
+ pPrev->SetPortion( pHolePor->GetPortion() );
+ delete pHolePor;
+ }
+ }
+ pPrev = pPrevPrev;
+ }
+ }
+ }
+ // Wenn es keinen linken Glue mehr gibt, wird die Abbruchbedingung
+ // herbeigefuehrt.
+ pRight = pLeft ? pLeft : (SwGluePortion*)this;
+ }
+}
+
+
+
diff --git a/sw/source/core/text/porglue.hxx b/sw/source/core/text/porglue.hxx
new file mode 100644
index 000000000000..010b3488be52
--- /dev/null
+++ b/sw/source/core/text/porglue.hxx
@@ -0,0 +1,134 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORGLUE_HXX
+#define _PORGLUE_HXX
+
+//#include <stdlib.h>
+
+#include "porlin.hxx"
+
+class SwRect;
+class SwLineLayout;
+
+/*************************************************************************
+ * class SwGluePortion
+ *************************************************************************/
+
+class SwGluePortion : public SwLinePortion
+{
+private:
+ KSHORT nFixWidth;
+public:
+ SwGluePortion( const KSHORT nInitFixWidth );
+
+ void Join( SwGluePortion *pVictim );
+
+ inline short GetPrtGlue() const;
+ inline KSHORT GetFixWidth() const { return nFixWidth; }
+ inline void SetFixWidth( const KSHORT nNew ) { nFixWidth = nNew; }
+ void MoveGlue( SwGluePortion *pTarget, const short nPrtGlue );
+ inline void MoveAllGlue( SwGluePortion *pTarget );
+ inline void MoveHalfGlue( SwGluePortion *pTarget );
+ inline void AdjFixWidth();
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual xub_StrLen GetCrsrOfst( const KSHORT nOfst ) const;
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwFixPortion
+ *************************************************************************/
+
+class SwFixPortion : public SwGluePortion
+{
+ KSHORT nFix; // der Width-Offset in der Zeile
+public:
+ SwFixPortion( const SwRect &rFlyRect );
+ SwFixPortion( const KSHORT nFixWidth, const KSHORT nFixPos );
+ inline void Fix( const KSHORT nNewFix ) { nFix = nNewFix; }
+ inline KSHORT Fix() const { return nFix; }
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwMarginPortion
+ *************************************************************************/
+
+class SwMarginPortion : public SwGluePortion
+{
+public:
+ SwMarginPortion( const KSHORT nFixWidth );
+ void AdjustRight( const SwLineLayout* pCurr );
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * inline SwGluePortion::GetPrtGlue()
+ *************************************************************************/
+
+inline short SwGluePortion::GetPrtGlue() const
+{ return Width() - nFixWidth; }
+
+/*************************************************************************
+ * inline SwGluePortion::AdjFixWidth()
+ * Die FixWidth darf niemals groesser sein als die Gesamtbreite !
+ *************************************************************************/
+
+inline void SwGluePortion::AdjFixWidth()
+{
+ if( nFixWidth > PrtWidth() )
+ nFixWidth = PrtWidth();
+}
+
+/*************************************************************************
+ * inline SwGluePortion::MoveGlue()
+ *************************************************************************/
+
+inline void SwGluePortion::MoveAllGlue( SwGluePortion *pTarget )
+{
+ MoveGlue( pTarget, GetPrtGlue() );
+}
+
+/*************************************************************************
+ * inline SwGluePortion::MoveHalfGlue()
+ *************************************************************************/
+
+inline void SwGluePortion::MoveHalfGlue( SwGluePortion *pTarget )
+{
+ MoveGlue( pTarget, GetPrtGlue() / 2 );
+}
+
+CLASSIO( SwGluePortion )
+CLASSIO( SwFixPortion )
+CLASSIO( SwMarginPortion )
+
+
+#endif
+
diff --git a/sw/source/core/text/porhyph.hxx b/sw/source/core/text/porhyph.hxx
new file mode 100644
index 000000000000..5d8f2c8007e8
--- /dev/null
+++ b/sw/source/core/text/porhyph.hxx
@@ -0,0 +1,119 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORHYPH_HXX
+#define _PORHYPH_HXX
+
+#include "porexp.hxx"
+
+/*************************************************************************
+ * class SwHyphPortion
+ *************************************************************************/
+
+class SwHyphPortion : public SwExpandPortion
+{
+public:
+ inline SwHyphPortion( ) { SetWhichPor( POR_HYPH ); }
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwHyphStrPortion
+ *************************************************************************/
+
+class SwHyphStrPortion : public SwHyphPortion
+{
+ XubString aExpand;
+public:
+ inline SwHyphStrPortion( const XubString &rStr );
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwSoftHyphPortion
+ *************************************************************************/
+
+class SwSoftHyphPortion : public SwHyphPortion
+{
+ sal_Bool bExpand;
+ KSHORT nViewWidth;
+ KSHORT nHyphWidth;
+
+public:
+ SwSoftHyphPortion();
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual SwLinePortion *Compress();
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+ inline void SetExpand( const sal_Bool bNew ) { bExpand = bNew; }
+ sal_Bool IsExpand() const { return bExpand; }
+
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwSoftHyphStrPortion
+ *************************************************************************/
+
+class SwSoftHyphStrPortion : public SwHyphStrPortion
+{
+public:
+ SwSoftHyphStrPortion( const XubString &rStr );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ OUTPUT_OPERATOR
+};
+
+inline SwHyphStrPortion::SwHyphStrPortion( const XubString &rStr )
+ : aExpand( rStr )
+{
+ aExpand += '-';
+ SetWhichPor( POR_HYPHSTR );
+}
+
+CLASSIO( SwHyphPortion )
+CLASSIO( SwHyphStrPortion )
+CLASSIO( SwSoftHyphPortion )
+CLASSIO( SwSoftHyphStrPortion )
+
+
+#endif
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
new file mode 100644
index 000000000000..0d34140d4058
--- /dev/null
+++ b/sw/source/core/text/porlay.cxx
@@ -0,0 +1,2465 @@
+/*************************************************************************
+ *
+ * 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 "errhdl.hxx" // ASSERT
+
+#include "txtcfg.hxx"
+#include "porlay.hxx"
+#include "itrform2.hxx"
+#include "porglue.hxx"
+#include "porexp.hxx" // SwQuoVadisPortion
+#include "blink.hxx" // pBlink
+#include "redlnitr.hxx" // SwRedlineItr
+#include "porfly.hxx" // SwFlyCntPortion
+#include <porrst.hxx> // SwHangingPortion
+#include <pormulti.hxx> // SwMultiPortion
+#include <breakit.hxx>
+#include <unicode/uchar.h>
+#include <com/sun/star/i18n/ScriptType.hdl>
+#include <com/sun/star/i18n/CTLScriptType.hdl>
+#include <com/sun/star/i18n/WordType.hdl>
+#include <paratr.hxx>
+#include <editeng/adjitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/charhiddenitem.hxx>
+#include <vcl/outdev.hxx>
+#include <editeng/blnkitem.hxx>
+#include <tools/multisel.hxx>
+#include <unotools/charclass.hxx>
+#include <i18npool/mslangid.hxx>
+#include <charfmt.hxx>
+#include <fchrfmt.hxx>
+#include <docary.hxx> // SwRedlineTbl
+#include <redline.hxx> // SwRedline
+
+// --> FME 2004-06-08 #i12836# enhanced pdf export
+#include <section.hxx>
+// <--
+
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentContentOperations.hxx>
+
+using namespace ::com::sun::star;
+using namespace i18n::ScriptType;
+
+//#ifdef BIDI
+#include <unicode/ubidi.h>
+#include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType
+
+sal_Bool isAlefChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x622 || cCh == 0x623 || cCh == 0x625 || cCh == 0x627 ||
+ cCh == 0x622 || cCh == 0x671 || cCh == 0x672 || cCh == 0x673 || cCh == 0x675 );
+}
+
+sal_Bool isWawChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x624 || cCh == 0x648 || cCh == 0x676 || cCh == 0x677 ||
+ ( cCh >= 0x6C4 && cCh <= 0x6CB ) || cCh == 0x6CF );
+}
+
+sal_Bool isDalChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x62F || cCh == 0x630 || cCh == 0x688 || cCh == 0x689 || cCh == 0x690 );
+}
+
+sal_Bool isRehChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x631 || cCh == 0x632 || ( cCh >= 0x691 && cCh <= 0x699 ));
+}
+
+sal_Bool isTehMarbutaChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x629 || cCh == 0x6C0 );
+}
+
+sal_Bool isBaaChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x628 || cCh == 0x62A || cCh == 0x62B || cCh == 0x679 || cCh == 0x680 );
+}
+
+sal_Bool isYehChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x626 || cCh == 0x649 || cCh == 0x64A || cCh == 0x678 || cCh == 0x6CC ||
+ cCh == 0x6CE || cCh == 0x6D0 || cCh == 0x6D1 );
+}
+
+sal_Bool isSeenOrSadChar ( xub_Unicode cCh )
+{
+ return ( ( cCh >= 0x633 && cCh <= 0x636 ) || ( cCh >= 0x69A && cCh <= 0x69E )
+ || cCh == 0x6FA || cCh == 0x6FB );
+}
+
+sal_Bool isHahChar ( xub_Unicode cCh )
+{
+ return ( ( cCh >= 0x62C && cCh <= 0x62E ) || ( cCh >= 0x681 && cCh <= 0x687 )
+ || cCh == 0x6BF );
+}
+
+sal_Bool isTahChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x637 || cCh == 0x638 || cCh == 0x69F );
+}
+
+sal_Bool isAinChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x639 || cCh == 0x63A || cCh == 0x6A0 || cCh == 0x6FC );
+}
+
+sal_Bool isKafChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x643 || ( cCh >= 0x6AC && cCh <= 0x6AE ) );
+}
+
+sal_Bool isLamChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x644 || ( cCh >= 0x6B5 && cCh <= 0x6B8 ) );
+}
+
+sal_Bool isGafChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x6A9 || cCh == 0x6AB ||( cCh >= 0x6AF && cCh <= 0x6B4 ) );
+}
+
+sal_Bool isQafChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x642 || cCh == 0x6A7 || cCh == 0x6A8 );
+}
+
+sal_Bool isFeChar ( xub_Unicode cCh )
+{
+ return ( cCh == 0x641 || ( cCh >= 0x6A1 && cCh <= 0x6A6 ) );
+}
+sal_Bool isTransparentChar ( xub_Unicode cCh )
+{
+ return ( ( cCh >= 0x610 && cCh <= 0x61A ) ||
+ ( cCh >= 0x64B && cCh <= 0x65E ) ||
+ ( cCh == 0x670 ) ||
+ ( cCh >= 0x6D6 && cCh <= 0x6DC ) ||
+ ( cCh >= 0x6DF && cCh <= 0x6E4 ) ||
+ ( cCh >= 0x6E7 && cCh <= 0x6E8 ) ||
+ ( cCh >= 0x6EA && cCh <= 0x6ED ));
+}
+
+/*************************************************************************
+ * lcl_IsLigature
+ *
+ * Checks if cCh + cNectCh builds a ligature (used for Kashidas)
+ *************************************************************************/
+
+sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh )
+{
+ // Lam + Alef
+ return ( isLamChar ( cCh ) && isAlefChar ( cNextCh ));
+}
+
+/*************************************************************************
+ * lcl_ConnectToPrev
+ *
+ * Checks if cCh is connectable to cPrevCh (used for Kashidas)
+ *************************************************************************/
+
+sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh )
+{
+ // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left
+ // Uh, there seem to be some more characters that are not connectable
+ // to the left. So we look for the characters that are actually connectable
+ // to the left. Here is the complete list of WH:
+
+ // (hennerdrewes):
+ // added lam forms 0x06B5..0x06B8
+ // added 0x6FA..0x6FC, according to unicode documentation, although not present in my fonts
+ // added heh goal 0x6C1
+ sal_Bool bRet = 0x628 == cPrevCh ||
+ ( 0x62A <= cPrevCh && cPrevCh <= 0x62E ) ||
+ ( 0x633 <= cPrevCh && cPrevCh <= 0x647 ) ||
+ 0x649 == cPrevCh || // Alef Maksura does connect !!!
+ 0x64A == cPrevCh ||
+ ( 0x678 <= cPrevCh && cPrevCh <= 0x687 ) ||
+ ( 0x69A <= cPrevCh && cPrevCh <= 0x6C1 ) ||
+ ( 0x6C3 <= cPrevCh && cPrevCh <= 0x6D3 ) ||
+ ( 0x6FA <= cPrevCh && cPrevCh <= 0x6FC ) ;
+
+ // check for ligatures cPrevChar + cChar
+ if( bRet )
+ bRet = !lcl_IsLigature( cPrevCh, cCh );
+ return bRet;
+}
+
+/*************************************************************************
+ * lcl_HasStrongLTR
+ *************************************************************************/
+ bool lcl_HasStrongLTR ( const String& rTxt, xub_StrLen nStart, xub_StrLen nEnd )
+ {
+ for ( xub_StrLen nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx )
+ {
+ const UCharDirection nCharDir = u_charDirection ( rTxt.GetChar ( nCharIdx ));
+ if ( nCharDir == U_LEFT_TO_RIGHT ||
+ nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
+ nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
+ return true;
+ }
+ return false;
+ }
+
+/*************************************************************************
+ * SwLineLayout::~SwLineLayout()
+ *
+ * class SwLineLayout: Das Layout einer einzelnen Zeile. Dazu
+ * gehoeren vor allen Dingen die Dimension, die Anzahl der
+ * Character und der Wortzwischenraeume in der Zeile.
+ * Zeilenobjekte werden in einem eigenen Pool verwaltet, um zu
+ * erreichen, dass sie im Speicher moeglichst beeinander liegen
+ * (d.h. zusammen gepaged werden und den Speicher nicht
+ * fragmentieren).
+ *************************************************************************/
+
+SwLineLayout::~SwLineLayout()
+{
+ Truncate();
+ if( GetNext() )
+ delete GetNext();
+ if( pBlink )
+ pBlink->Delete( this );
+ delete pLLSpaceAdd;
+ if ( pKanaComp )
+ delete pKanaComp;
+}
+
+/*************************************************************************
+ * virtual SwLineLayout::Insert()
+ *************************************************************************/
+
+SwLinePortion *SwLineLayout::Insert( SwLinePortion *pIns )
+{
+ // Erster Attributwechsel, Masse und Laengen
+ // aus *pCurr in die erste Textportion kopieren.
+ if( !pPortion )
+ {
+ if( GetLen() )
+ {
+ pPortion = new SwTxtPortion( *(SwLinePortion*)this );
+ if( IsBlinking() && pBlink )
+ {
+ SetBlinking( sal_False );
+ pBlink->Replace( this, pPortion );
+ }
+ }
+ else
+ {
+ SetPortion( pIns );
+ return pIns;
+ }
+ }
+ // mit Skope aufrufen, sonst Rekursion !
+ return pPortion->SwLinePortion::Insert( pIns );
+}
+
+/*************************************************************************
+ * virtual SwLineLayout::Append()
+ *************************************************************************/
+
+SwLinePortion *SwLineLayout::Append( SwLinePortion *pIns )
+{
+ // Erster Attributwechsel, Masse und Laengen
+ // aus *pCurr in die erste Textportion kopieren.
+ if( !pPortion )
+ pPortion = new SwTxtPortion( *(SwLinePortion*)this );
+ // mit Skope aufrufen, sonst Rekursion !
+ return pPortion->SwLinePortion::Append( pIns );
+}
+
+/*************************************************************************
+ * virtual SwLineLayout::Format()
+ *************************************************************************/
+
+// fuer die Sonderbehandlung bei leeren Zeilen
+
+sal_Bool SwLineLayout::Format( SwTxtFormatInfo &rInf )
+{
+ if( GetLen() )
+ return SwTxtPortion::Format( rInf );
+ else
+ {
+ Height( rInf.GetTxtHeight() );
+ return sal_True;
+ }
+}
+
+/*************************************************************************
+ * SwLineLayout::CalcLeftMargin()
+ *
+ * Wir sammeln alle FlyPortions am Anfang der Zeile zu einer MarginPortion.
+ *************************************************************************/
+
+SwMarginPortion *SwLineLayout::CalcLeftMargin()
+{
+ SwMarginPortion *pLeft = (GetPortion() && GetPortion()->IsMarginPortion()) ?
+ (SwMarginPortion *)GetPortion() : 0;
+ if( !GetPortion() )
+ SetPortion( new SwTxtPortion( *(SwLinePortion*)this ) );
+ if( !pLeft )
+ {
+ pLeft = new SwMarginPortion( 0 );
+ pLeft->SetPortion( GetPortion() );
+ SetPortion( pLeft );
+ }
+ else
+ {
+ pLeft->Height( 0 );
+ pLeft->Width( 0 );
+ pLeft->SetLen( 0 );
+ pLeft->SetAscent( 0 );
+ pLeft->SetPortion( NULL );
+ pLeft->SetFixWidth(0);
+ }
+
+ SwLinePortion *pPos = pLeft->GetPortion();
+ while( pPos )
+ {
+ DBG_LOOP;
+ if( pPos->IsFlyPortion() )
+ {
+ // Die FlyPortion wird ausgesogen ...
+ pLeft->Join( (SwGluePortion*)pPos );
+ pPos = pLeft->GetPortion();
+ if( GetpKanaComp() )
+ GetKanaComp().Remove( 0, 1 );
+ }
+ else
+ pPos = 0;
+ }
+ return pLeft;
+}
+
+/*************************************************************************
+ * SwLineLayout::InitSpaceAdd()
+ *************************************************************************/
+
+void SwLineLayout::InitSpaceAdd()
+{
+ if ( !pLLSpaceAdd )
+ CreateSpaceAdd();
+ else
+ SetLLSpaceAdd( 0, 0 );
+}
+
+/*************************************************************************
+ * SwLineLayout::CreateSpaceAdd()
+ *************************************************************************/
+
+void SwLineLayout::CreateSpaceAdd( const long nInit )
+{
+ pLLSpaceAdd = new std::vector<long>;
+ SetLLSpaceAdd( nInit, 0 );
+}
+
+/*************************************************************************
+ * Local helper function. Returns true if there are only blanks
+ * in [nStt, nEnd[
+ *************************************************************************/
+
+bool lcl_HasOnlyBlanks( const XubString& rTxt, xub_StrLen nStt, xub_StrLen nEnd )
+{
+ bool bBlankOnly = true;
+ while ( nStt < nEnd )
+ {
+ const xub_Unicode cChar = rTxt.GetChar( nStt++ );
+ if ( ' ' != cChar && 0x3000 != cChar )
+ {
+ bBlankOnly = false;
+ break;
+ }
+ }
+ return bBlankOnly;
+}
+
+/*************************************************************************
+ * SwLineLayout::CalcLine()
+ *
+ * Aus FormatLine() ausgelagert.
+ *************************************************************************/
+
+void SwLineLayout::CalcLine( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
+{
+ const KSHORT nLineWidth = rInf.RealWidth();
+
+ KSHORT nFlyAscent = 0;
+ KSHORT nFlyHeight = 0;
+ KSHORT nFlyDescent = 0;
+ sal_Bool bOnlyPostIts = sal_True;
+ SetHanging( sal_False );
+
+ sal_Bool bTmpDummy = ( 0 == GetLen() );
+ SwFlyCntPortion* pFlyCnt = 0;
+ if( bTmpDummy )
+ {
+ nFlyAscent = 0;
+ nFlyHeight = 0;
+ nFlyDescent = 0;
+ }
+
+ // --> FME 2006-03-01 #i3952#
+ const bool bIgnoreBlanksAndTabsForLineHeightCalculation =
+ rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION);
+
+ bool bHasBlankPortion = false;
+ bool bHasOnlyBlankPortions = true;
+ // <--
+
+ if( pPortion )
+ {
+ SetCntnt( sal_False );
+ if( pPortion->IsBreakPortion() )
+ {
+ SetLen( pPortion->GetLen() );
+ if( GetLen() )
+ bTmpDummy = sal_False;
+ }
+ else
+ {
+ Init( GetPortion() );
+ SwLinePortion *pPos = pPortion;
+ SwLinePortion *pLast = this;
+ KSHORT nMaxDescent = 0;
+
+ // Eine Gruppe ist ein Abschnitt in der Portion-Kette von
+ // pCurr oder einer Fix-Portion bis zum Ende bzw. zur naechsten
+ // Fix-Portion.
+ while( pPos )
+ {
+ DBG_LOOP;
+ ASSERT( POR_LIN != pPos->GetWhichPor(),
+ "SwLineLayout::CalcLine: don't use SwLinePortions !" );
+
+ // Null-Portions werden eliminiert. Sie koennen entstehen,
+ // wenn zwei FlyFrms ueberlappen.
+ if( !pPos->Compress() )
+ {
+ // 8110: Hoehe und Ascent nur uebernehmen, wenn sonst in der
+ // Zeile nichts mehr los ist.
+ if( !pPos->GetPortion() )
+ {
+ if( !Height() )
+ Height( pPos->Height() );
+ if( !GetAscent() )
+ SetAscent( pPos->GetAscent() );
+ }
+ delete pLast->Cut( pPos );
+ pPos = pLast->GetPortion();
+ continue;
+ }
+
+ const xub_StrLen nPorSttIdx = rInf.GetLineStart() + nLineLength;
+ nLineLength = nLineLength + pPos->GetLen();
+ AddPrtWidth( pPos->Width() );
+
+ // --> FME 2006-03-01 #i3952#
+ if ( bIgnoreBlanksAndTabsForLineHeightCalculation )
+ {
+ if ( pPos->InTabGrp() || pPos->IsHolePortion() ||
+ ( pPos->IsTextPortion() &&
+ lcl_HasOnlyBlanks( rInf.GetTxt(), nPorSttIdx, nPorSttIdx + pPos->GetLen() ) ) )
+ {
+ pLast = pPos;
+ pPos = pPos->GetPortion();
+ bHasBlankPortion = true;
+ continue;
+ }
+ }
+ // <--
+
+ bHasOnlyBlankPortions = false;
+
+ // Es gab Attributwechsel: Laengen und Masse aufaddieren;
+ // bzw.Maxima bilden.
+
+ KSHORT nPosHeight = pPos->Height();
+ KSHORT nPosAscent = pPos->GetAscent();
+
+ ASSERT( nPosHeight >= nPosAscent,
+ "SwLineLayout::CalcLine: bad ascent or height" );
+
+ if( pPos->IsHangingPortion() )
+ {
+ SetHanging( sal_True );
+ rInf.GetParaPortion()->SetMargin( sal_True );
+ }
+
+ // Damit ein Paragraphende-Zeichen nicht durch ein Descent zu einer
+ // geaenderten Zeilenhoehe und zum Umformatieren fuehrt.
+ if ( !pPos->IsBreakPortion() || !Height() )
+ {
+ bOnlyPostIts &= pPos->IsPostItsPortion();
+
+ if( bTmpDummy && !nLineLength )
+ {
+ if( pPos->IsFlyPortion() )
+ {
+ if( nFlyHeight < nPosHeight )
+ nFlyHeight = nPosHeight;
+ if( nFlyAscent < nPosAscent )
+ nFlyAscent = nPosAscent;
+ if( nFlyDescent < nPosHeight - nPosAscent )
+ nFlyDescent = nPosHeight - nPosAscent;
+ }
+ else
+ {
+ if( pPos->InNumberGrp() )
+ {
+ KSHORT nTmp = rInf.GetFont()->GetAscent(
+ rInf.GetVsh(), *rInf.GetOut() );
+ if( nTmp > nPosAscent )
+ {
+ nPosHeight += nTmp - nPosAscent;
+ nPosAscent = nTmp;
+ }
+ nTmp = rInf.GetFont()->GetHeight( rInf.GetVsh(),
+ *rInf.GetOut() );
+ if( nTmp > nPosHeight )
+ nPosHeight = nTmp;
+ }
+ Height( nPosHeight );
+ nAscent = nPosAscent;
+ nMaxDescent = nPosHeight - nPosAscent;
+ }
+ }
+ else if( !pPos->IsFlyPortion() )
+ {
+ if( Height() < nPosHeight )
+ Height( nPosHeight );
+ if( pPos->IsFlyCntPortion() || ( pPos->IsMultiPortion()
+ && ((SwMultiPortion*)pPos)->HasFlyInCntnt() ) )
+ rLine.SetFlyInCntBase();
+ if( pPos->IsFlyCntPortion() &&
+ ((SwFlyCntPortion*)pPos)->GetAlign() )
+ {
+ ((SwFlyCntPortion*)pPos)->SetMax( sal_False );
+ if( !pFlyCnt || pPos->Height() > pFlyCnt->Height() )
+ pFlyCnt = (SwFlyCntPortion*)pPos;
+ }
+ else
+ {
+ if( nAscent < nPosAscent )
+ nAscent = nPosAscent;
+ if( nMaxDescent < nPosHeight - nPosAscent )
+ nMaxDescent = nPosHeight - nPosAscent;
+ }
+ }
+ }
+ else if( pPos->GetLen() )
+ bTmpDummy = sal_False;
+
+ if( !HasCntnt() && !pPos->InNumberGrp() )
+ {
+ if ( pPos->InExpGrp() )
+ {
+ XubString aTxt;
+ if( pPos->GetExpTxt( rInf, aTxt ) && aTxt.Len() )
+ SetCntnt( sal_True );
+ }
+ else if( ( pPos->InTxtGrp() || pPos->IsMultiPortion() ) &&
+ pPos->GetLen() )
+ SetCntnt( sal_True );
+ }
+
+ bTmpDummy = bTmpDummy && !HasCntnt() &&
+ ( !pPos->Width() || pPos->IsFlyPortion() );
+
+ pLast = pPos;
+ pPos = pPos->GetPortion();
+ }
+
+ if( pFlyCnt )
+ {
+ if( pFlyCnt->Height() == Height() )
+ {
+ pFlyCnt->SetMax( sal_True );
+ if( Height() > nMaxDescent + nAscent )
+ {
+ if( 3 == pFlyCnt->GetAlign() ) // Bottom
+ nAscent = Height() - nMaxDescent;
+ else if( 2 == pFlyCnt->GetAlign() ) // Center
+ nAscent = ( Height() + nAscent - nMaxDescent ) / 2;
+ }
+ pFlyCnt->SetAscent( nAscent );
+ }
+ }
+
+ if( bTmpDummy && nFlyHeight )
+ {
+ nAscent = nFlyAscent;
+ if( nFlyDescent > nFlyHeight - nFlyAscent )
+ Height( nFlyHeight + nFlyDescent );
+ else
+ Height( nFlyHeight );
+ }
+ else if( nMaxDescent > Height() - nAscent )
+ Height( nMaxDescent + nAscent );
+
+ if( bOnlyPostIts && !( bHasBlankPortion && bHasOnlyBlankPortions ) )
+ {
+ Height( rInf.GetFont()->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
+ nAscent = rInf.GetFont()->GetAscent( rInf.GetVsh(), *rInf.GetOut() );
+ }
+ }
+ }
+ else
+ {
+ SetCntnt( !bTmpDummy );
+
+ // --> FME 2006-03-01 #i3952#
+ if ( bIgnoreBlanksAndTabsForLineHeightCalculation &&
+ lcl_HasOnlyBlanks( rInf.GetTxt(), rInf.GetLineStart(), rInf.GetLineStart() + GetLen() ) )
+ {
+ bHasBlankPortion = true;
+ }
+ // <--
+ }
+
+ // --> FME 2006-03-01 #i3952#
+ if ( bHasBlankPortion && bHasOnlyBlankPortions )
+ {
+ USHORT nTmpAscent = GetAscent();
+ USHORT nTmpHeight = Height();
+ rLine.GetAttrHandler().GetDefaultAscentAndHeight( rInf.GetVsh(), *rInf.GetOut(), nTmpAscent, nTmpHeight );
+ SetAscent( nTmpAscent );
+ Height( nTmpHeight );
+ }
+ // <--
+
+ // Robust:
+ if( nLineWidth < Width() )
+ Width( nLineWidth );
+ ASSERT( nLineWidth >= Width(), "SwLineLayout::CalcLine: line is bursting" );
+ SetDummy( bTmpDummy );
+ SetRedline( rLine.GetRedln() &&
+ rLine.GetRedln()->CheckLine( rLine.GetStart(), rLine.GetEnd() ) );
+}
+
+// --> OD 2005-05-20 #i47162# - add optional parameter <_bNoFlyCntPorAndLinePor>
+// to control, if the fly content portions and line portion are considered.
+void SwLineLayout::MaxAscentDescent( SwTwips& _orAscent,
+ SwTwips& _orDescent,
+ SwTwips& _orObjAscent,
+ SwTwips& _orObjDescent,
+ const SwLinePortion* _pDontConsiderPortion,
+ const bool _bNoFlyCntPorAndLinePor ) const
+{
+ _orAscent = 0;
+ _orDescent = 0;
+ _orObjAscent = 0;
+ _orObjDescent = 0;
+
+ const SwLinePortion* pTmpPortion = this;
+ if ( !pTmpPortion->GetLen() && pTmpPortion->GetPortion() )
+ {
+ pTmpPortion = pTmpPortion->GetPortion();
+ }
+
+ while ( pTmpPortion )
+ {
+ if ( !pTmpPortion->IsBreakPortion() && !pTmpPortion->IsFlyPortion() &&
+ ( !_bNoFlyCntPorAndLinePor ||
+ ( !pTmpPortion->IsFlyCntPortion() &&
+ !(pTmpPortion == this && pTmpPortion->GetPortion() ) ) ) )
+ {
+ SwTwips nPortionAsc = static_cast<SwTwips>(pTmpPortion->GetAscent());
+ SwTwips nPortionDesc = static_cast<SwTwips>(pTmpPortion->Height()) -
+ nPortionAsc;
+
+ const sal_Bool bFlyCmp = pTmpPortion->IsFlyCntPortion() ?
+ static_cast<const SwFlyCntPortion*>(pTmpPortion)->IsMax() :
+ !( pTmpPortion == _pDontConsiderPortion );
+
+ if ( bFlyCmp )
+ {
+ _orObjAscent = Max( _orObjAscent, nPortionAsc );
+ _orObjDescent = Max( _orObjDescent, nPortionDesc );
+ }
+
+ if ( !pTmpPortion->IsFlyCntPortion() && !pTmpPortion->IsGrfNumPortion() )
+ {
+ _orAscent = Max( _orAscent, nPortionAsc );
+ _orDescent = Max( _orDescent, nPortionDesc );
+ }
+ }
+ pTmpPortion = pTmpPortion->GetPortion();
+ }
+}
+
+/*************************************************************************
+ * class SwCharRange
+ *************************************************************************/
+
+SwCharRange &SwCharRange::operator+=(const SwCharRange &rRange)
+{
+ if(0 != rRange.nLen ) {
+ if(0 == nLen) {
+ nStart = rRange.nStart;
+ nLen = rRange.nLen ;
+ }
+ else {
+ if(rRange.nStart + rRange.nLen > nStart + nLen) {
+ nLen = rRange.nStart + rRange.nLen - nStart;
+ }
+ if(rRange.nStart < nStart) {
+ nLen += nStart - rRange.nStart;
+ nStart = rRange.nStart;
+ }
+ }
+ }
+ return *this;
+}
+
+/*************************************************************************
+ * SwScriptInfo::SwScriptInfo()
+ *************************************************************************/
+SwScriptInfo::SwScriptInfo() :
+ nInvalidityPos( 0 ),
+ nDefaultDir( 0 )
+{
+};
+
+/*************************************************************************
+ * SwScriptInfo::~SwScriptInfo()
+ *************************************************************************/
+SwScriptInfo::~SwScriptInfo()
+{
+}
+
+/*************************************************************************
+ * SwScriptInfo::WhichFont()
+ *
+ * Converts i18n Script Type (LATIN, ASIAN, COMPLEX, WEAK) to
+ * Sw Script Types (SW_LATIN, SW_CJK, SW_CTL), used to identify the font
+ *************************************************************************/
+BYTE SwScriptInfo::WhichFont( xub_StrLen nIdx, const String* pTxt, const SwScriptInfo* pSI )
+{
+ ASSERT( pTxt || pSI,"How should I determine the script type?" );
+ USHORT nScript;
+
+ // First we try to use our SwScriptInfo
+ if ( pSI )
+ nScript = pSI->ScriptType( nIdx );
+ else
+ // Ok, we have to ask the break iterator
+ nScript = pBreakIt->GetRealScriptOfText( *pTxt, nIdx );
+
+ switch ( nScript ) {
+ case i18n::ScriptType::LATIN : return SW_LATIN;
+ case i18n::ScriptType::ASIAN : return SW_CJK;
+ case i18n::ScriptType::COMPLEX : return SW_CTL;
+ }
+
+ ASSERT( sal_False, "Somebody tells lies about the script type!" );
+ return SW_LATIN;
+}
+
+/*************************************************************************
+ * SwScriptInfo::InitScriptInfo()
+ *
+ * searches for script changes in rTxt and stores them
+ *************************************************************************/
+
+void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode )
+{
+ InitScriptInfo( rNode, nDefaultDir == UBIDI_RTL );
+}
+
+void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL )
+{
+ if( !pBreakIt->GetBreakIter().is() )
+ return;
+
+ const String& rTxt = rNode.GetTxt();
+
+ //
+ // HIDDEN TEXT INFORMATION
+ //
+ Range aRange( 0, rTxt.Len() ? rTxt.Len() - 1 : 0 );
+ MultiSelection aHiddenMulti( aRange );
+ CalcHiddenRanges( rNode, aHiddenMulti );
+
+ aHiddenChg.Remove( 0, aHiddenChg.Count() );
+ USHORT nHiddenIdx = 0;
+ USHORT i = 0;
+ for( i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
+ {
+ const Range& rRange = aHiddenMulti.GetRange( i );
+ const xub_StrLen nStart = (xub_StrLen)rRange.Min();
+ const xub_StrLen nEnd = (xub_StrLen)rRange.Max() + 1;
+
+ aHiddenChg.Insert( nStart, nHiddenIdx++ );
+ aHiddenChg.Insert( nEnd, nHiddenIdx++ );
+ }
+
+ //
+ // SCRIPT AND SCRIPT RELATED INFORMATION
+ //
+
+ xub_StrLen nChg = nInvalidityPos;
+
+ // STRING_LEN means the data structure is up to date
+ nInvalidityPos = STRING_LEN;
+
+ // this is the default direction
+ nDefaultDir = static_cast<BYTE>(bRTL ? UBIDI_RTL : UBIDI_LTR);
+
+ // counter for script info arrays
+ USHORT nCnt = 0;
+ // counter for compression information arrays
+ USHORT nCntComp = 0;
+ // counter for kashida array
+ USHORT nCntKash = 0;
+
+ BYTE nScript = i18n::ScriptType::LATIN;
+
+ // compression type
+ const SwCharCompressType aCompEnum = rNode.getIDocumentSettingAccess()->getCharacterCompressionType();
+
+ // justification type
+ const sal_Bool bAdjustBlock = SVX_ADJUST_BLOCK ==
+ rNode.GetSwAttrSet().GetAdjust().GetAdjust();
+
+ //
+ // FIND INVALID RANGES IN SCRIPT INFO ARRAYS:
+ //
+
+ if( nChg )
+ {
+ // if change position = 0 we do not use any data from the arrays
+ // because by deleting all characters of the first group at the beginning
+ // of a paragraph nScript is set to a wrong value
+ ASSERT( CountScriptChg(), "Where're my changes of script?" );
+ while( nCnt < CountScriptChg() )
+ {
+ if ( nChg > GetScriptChg( nCnt ) )
+ nCnt++;
+ else
+ {
+ nScript = GetScriptType( nCnt );
+ break;
+ }
+ }
+ if( CHARCOMPRESS_NONE != aCompEnum )
+ {
+ while( nCntComp < CountCompChg() )
+ {
+ if ( nChg > GetCompStart( nCntComp ) )
+ nCntComp++;
+ else
+ break;
+ }
+ }
+ if ( bAdjustBlock )
+ {
+ while( nCntKash < CountKashida() )
+ {
+ if ( nChg > GetKashida( nCntKash ) )
+ nCntKash++;
+ else
+ break;
+ }
+ }
+ }
+
+ //
+ // ADJUST nChg VALUE:
+ //
+
+ // by stepping back one position we know that we are inside a group
+ // declared as an nScript group
+ if ( nChg )
+ --nChg;
+
+ const xub_StrLen nGrpStart = nCnt ? GetScriptChg( nCnt - 1 ) : 0;
+
+ // we go back in our group until we reach the first character of
+ // type nScript
+ while ( nChg > nGrpStart &&
+ nScript != pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg ) )
+ --nChg;
+
+ // If we are at the start of a group, we do not trust nScript,
+ // we better get nScript from the breakiterator:
+ if ( nChg == nGrpStart )
+ nScript = (BYTE)pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg );
+
+ //
+ // INVALID DATA FROM THE SCRIPT INFO ARRAYS HAS TO BE DELETED:
+ //
+
+ // remove invalid entries from script information arrays
+ const USHORT nScriptRemove = aScriptChg.Count() - nCnt;
+ aScriptChg.Remove( nCnt, nScriptRemove );
+ aScriptType.Remove( nCnt, nScriptRemove );
+
+ // get the start of the last compression group
+ USHORT nLastCompression = nChg;
+ if( nCntComp )
+ {
+ --nCntComp;
+ nLastCompression = GetCompStart( nCntComp );
+ if( nChg >= nLastCompression + GetCompLen( nCntComp ) )
+ {
+ nLastCompression = nChg;
+ ++nCntComp;
+ }
+ }
+
+ // remove invalid entries from compression information arrays
+ const USHORT nCompRemove = aCompChg.Count() - nCntComp;
+ aCompChg.Remove( nCntComp, nCompRemove );
+ aCompLen.Remove( nCntComp, nCompRemove );
+ aCompType.Remove( nCntComp, nCompRemove );
+
+ // get the start of the last kashida group
+ USHORT nLastKashida = nChg;
+ if( nCntKash && i18n::ScriptType::COMPLEX == nScript )
+ {
+ --nCntKash;
+ nLastKashida = GetKashida( nCntKash );
+ }
+
+ // remove invalid entries from kashida array
+ aKashida.Remove( nCntKash, aKashida.Count() - nCntKash );
+
+ //
+ // TAKE CARE OF WEAK CHARACTERS: WE MUST FIND AN APPROPRIATE
+ // SCRIPT FOR WEAK CHARACTERS AT THE BEGINNING OF A PARAGRAPH
+ //
+
+ if( WEAK == pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg ) )
+ {
+ // If the beginning of the current group is weak, this means that
+ // all of the characters in this grounp are weak. We have to assign
+ // the scripts to these characters depending on the fonts which are
+ // set for these characters to display them.
+ xub_StrLen nEnd =
+ (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rTxt, nChg, WEAK );
+
+ if( nEnd > rTxt.Len() )
+ nEnd = rTxt.Len();
+
+ nScript = (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
+
+ ASSERT( i18n::ScriptType::LATIN == nScript ||
+ i18n::ScriptType::ASIAN == nScript ||
+ i18n::ScriptType::COMPLEX == nScript, "Wrong default language" );
+
+ nChg = nEnd;
+
+ // Get next script type or set to weak in order to exit
+ BYTE nNextScript = ( nEnd < rTxt.Len() ) ?
+ (BYTE)pBreakIt->GetBreakIter()->getScriptType( rTxt, nEnd ) :
+ (BYTE)WEAK;
+
+ if ( nScript != nNextScript )
+ {
+ aScriptChg.Insert( nEnd, nCnt );
+ aScriptType.Insert( nScript, nCnt++ );
+ nScript = nNextScript;
+ }
+ }
+
+ //
+ // UPDATE THE SCRIPT INFO ARRAYS:
+ //
+
+ while ( nChg < rTxt.Len() || ( !aScriptChg.Count() && !rTxt.Len() ) )
+ {
+ ASSERT( i18n::ScriptType::WEAK != nScript,
+ "Inserting WEAK into SwScriptInfo structure" );
+ ASSERT( STRING_LEN != nChg, "65K? Strange length of script section" );
+
+ xub_StrLen nSearchStt = nChg;
+ nChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rTxt, nSearchStt, nScript );
+
+ if ( nChg > rTxt.Len() )
+ nChg = rTxt.Len();
+
+ // --> FME 2008-09-17 #i28203#
+ // for 'complex' portions, we make sure that a portion does not contain more
+ // than one script:
+ if( i18n::ScriptType::COMPLEX == nScript && pBreakIt->GetScriptTypeDetector().is() )
+ {
+ const short nScriptType = pBreakIt->GetScriptTypeDetector()->getCTLScriptType( rTxt, nSearchStt );
+ xub_StrLen nNextCTLScriptStart = nSearchStt;
+ short nCurrentScriptType = nScriptType;
+ while( com::sun::star::i18n::CTLScriptType::CTL_UNKNOWN == nCurrentScriptType || nScriptType == nCurrentScriptType )
+ {
+ nNextCTLScriptStart = (xub_StrLen)pBreakIt->GetScriptTypeDetector()->endOfCTLScriptType( rTxt, nNextCTLScriptStart );
+ if( nNextCTLScriptStart < rTxt.Len() && nNextCTLScriptStart < nChg )
+ nCurrentScriptType = pBreakIt->GetScriptTypeDetector()->getCTLScriptType( rTxt, nNextCTLScriptStart );
+ else
+ break;
+ }
+ nChg = Min( nChg, nNextCTLScriptStart );
+ }
+ // <--
+
+ // special case for dotted circle since it can be used with complex
+ // before a mark, so we want it associated with the mark's script
+ if (nChg < rTxt.Len() && nChg > 0 && (i18n::ScriptType::WEAK ==
+ pBreakIt->GetBreakIter()->getScriptType(rTxt,nChg - 1)))
+ {
+ int8_t nType = u_charType(rTxt.GetChar(nChg) );
+ if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
+ nType == U_COMBINING_SPACING_MARK )
+ {
+ aScriptChg.Insert( nChg - 1, nCnt );
+ }
+ else
+ {
+ aScriptChg.Insert( nChg, nCnt );
+ }
+ }
+ else
+ {
+ aScriptChg.Insert( nChg, nCnt );
+ }
+ aScriptType.Insert( nScript, nCnt++ );
+
+ // if current script is asian, we search for compressable characters
+ // in this range
+ if ( CHARCOMPRESS_NONE != aCompEnum &&
+ i18n::ScriptType::ASIAN == nScript )
+ {
+ BYTE ePrevState = NONE;
+ BYTE eState;
+ USHORT nPrevChg = nLastCompression;
+
+ while ( nLastCompression < nChg )
+ {
+ xub_Unicode cChar = rTxt.GetChar( nLastCompression );
+
+ // examine current character
+ switch ( cChar )
+ {
+ // Left punctuation found
+ case 0x3008: case 0x300A: case 0x300C: case 0x300E:
+ case 0x3010: case 0x3014: case 0x3016: case 0x3018:
+ case 0x301A: case 0x301D:
+ eState = SPECIAL_LEFT;
+ break;
+ // Right punctuation found
+ case 0x3001: case 0x3002: case 0x3009: case 0x300B:
+ case 0x300D: case 0x300F: case 0x3011: case 0x3015:
+ case 0x3017: case 0x3019: case 0x301B: case 0x301E:
+ case 0x301F:
+ eState = SPECIAL_RIGHT;
+ break;
+ default:
+ eState = static_cast<BYTE>( ( 0x3040 <= cChar && 0x3100 > cChar ) ? KANA : NONE );
+ }
+
+ // insert range of compressable characters
+ if( ePrevState != eState )
+ {
+ if ( ePrevState != NONE )
+ {
+ // insert start and type
+ if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
+ ePrevState != KANA )
+ {
+ aCompChg.Insert( nPrevChg, nCntComp );
+ BYTE nTmpType = ePrevState;
+ aCompType.Insert( nTmpType, nCntComp );
+ aCompLen.Insert( nLastCompression - nPrevChg, nCntComp++ );
+ }
+ }
+
+ ePrevState = eState;
+ nPrevChg = nLastCompression;
+ }
+
+ nLastCompression++;
+ }
+
+ // we still have to examine last entry
+ if ( ePrevState != NONE )
+ {
+ // insert start and type
+ if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
+ ePrevState != KANA )
+ {
+ aCompChg.Insert( nPrevChg, nCntComp );
+ BYTE nTmpType = ePrevState;
+ aCompType.Insert( nTmpType, nCntComp );
+ aCompLen.Insert( nLastCompression - nPrevChg, nCntComp++ );
+ }
+ }
+ }
+
+ // we search for connecting opportunities (kashida)
+ else if ( bAdjustBlock && i18n::ScriptType::COMPLEX == nScript )
+ {
+ SwScanner aScanner( rNode, rNode.GetTxt(), 0, 0,
+ i18n::WordType::DICTIONARY_WORD,
+ nLastKashida, nChg );
+
+ // the search has to be performed on a per word base
+ while ( aScanner.NextWord() )
+ {
+ const XubString& rWord = aScanner.GetWord();
+
+ xub_StrLen nIdx = 0;
+ xub_StrLen nKashidaPos = STRING_LEN;
+ xub_Unicode cCh;
+ xub_Unicode cPrevCh = 0;
+
+ USHORT nPriorityLevel = 7; // 0..6 = level found
+ // 7 not found
+
+ xub_StrLen nWordLen = rWord.Len();
+
+ // ignore trailing vowel chars
+ while( nWordLen && isTransparentChar( rWord.GetChar( nWordLen - 1 )))
+ --nWordLen;
+
+ while (nIdx < nWordLen)
+ {
+ cCh = rWord.GetChar( nIdx );
+
+ // 1. Priority:
+ // after user inserted kashida
+ if ( 0x640 == cCh )
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx;
+ nPriorityLevel = 0;
+ }
+
+ // 2. Priority:
+ // after a Seen or Sad
+ if (nPriorityLevel >= 1 && nIdx < nWordLen - 1)
+ {
+ if( isSeenOrSadChar( cCh )
+ && (rWord.GetChar( nIdx+1 ) != 0x200C) ) // #i98410#: prevent ZWNJ expansion
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx;
+ nPriorityLevel = 1;
+ }
+ }
+
+ // 3. Priority:
+ // before final form of Teh Marbuta, Hah, Dal
+ if ( nPriorityLevel >= 2 && nIdx > 0 )
+ {
+ if ( isTehMarbutaChar ( cCh ) || // Teh Marbuta (right joining)
+ isDalChar ( cCh ) || // Dal (right joining) final form may appear in the middle of word
+ ( isHahChar ( cCh ) && nIdx == nWordLen - 1)) // Hah (dual joining) only at end of word
+ {
+
+ ASSERT( 0 != cPrevCh, "No previous character" )
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx - 1;
+ nPriorityLevel = 2;
+ }
+ }
+ }
+
+ // 4. Priority:
+ // before final form of Alef, Lam or Kaf
+ if ( nPriorityLevel >= 3 && nIdx > 0 )
+ {
+ if ( isAlefChar ( cCh ) || // Alef (right joining) final form may appear in the middle of word
+ (( isLamChar ( cCh ) || // Lam
+ isKafChar ( cCh ) || // Kaf (both dual joining)
+ isGafChar ( cCh ) )
+ && nIdx == nWordLen - 1)) // only at end of word
+ {
+ ASSERT( 0 != cPrevCh, "No previous character" )
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx - 1;
+ nPriorityLevel = 3;
+ }
+ }
+ }
+
+ // 5. Priority:
+ // before media Bah
+ if ( nPriorityLevel >= 4 && nIdx > 0 && nIdx < nWordLen - 1 )
+ {
+ if ( isBaaChar ( cCh )) // Bah
+ {
+ // check if next character is Reh, Yeh or Alef Maksura
+ xub_Unicode cNextCh = rWord.GetChar( nIdx + 1 );
+ if ( isRehChar ( cNextCh ) || isYehChar ( cNextCh ))
+ {
+ ASSERT( 0 != cPrevCh, "No previous character" )
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx - 1;
+ nPriorityLevel = 4;
+ }
+ }
+ }
+ }
+
+ // 6. Priority:
+ // before the final form of Waw, Ain, Qaf and Fa
+ if ( nPriorityLevel >= 5 && nIdx > 0 )
+ {
+ if ( isWawChar ( cCh ) || // Wav (right joining)
+ // final form may appear in the middle of word
+ (( isAinChar ( cCh ) || // Ain (dual joining)
+ isQafChar ( cCh ) || // Qaf (dual joining)
+ isFeChar ( cCh ) ) // Feh (dual joining)
+ && nIdx == nWordLen - 1)) // only at end of word
+ {
+ ASSERT( 0 != cPrevCh, "No previous character" )
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx - 1;
+ nPriorityLevel = 5;
+ }
+ }
+ }
+
+ // other connecting possibilities
+ if ( nPriorityLevel >= 6 && nIdx > 0 )
+ {
+ // remaining right joiners
+ // Reh, Zain, Thal,
+ if ( isRehChar ( cCh ) || // Reh Zain (right joining)
+ // final form may appear in the middle of word
+ ( 0x60C <= cCh && 0x6FE >= cCh // all others
+ && nIdx == nWordLen - 1)) // only at end of word
+ {
+ ASSERT( 0 != cPrevCh, "No previous character" )
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aScanner.GetBegin() + nIdx - 1;
+ nPriorityLevel = 6;
+ }
+ }
+ }
+
+ // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
+ // Damma, Kasra, Shadda and Sukun when checking if
+ // a character can be connected to previous character.
+ if ( !isTransparentChar ( cCh) )
+ cPrevCh = cCh;
+
+ ++nIdx;
+ } // end of current word
+
+ if ( STRING_LEN != nKashidaPos )
+ aKashida.Insert( nKashidaPos, nCntKash++ );
+ } // end of kashida search
+ }
+
+ if ( nChg < rTxt.Len() )
+ nScript = (BYTE)pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg );
+
+ nLastCompression = nChg;
+ nLastKashida = nChg;
+ };
+
+#ifdef DBG_UTIL
+ // check kashida data
+ long nTmpKashidaPos = -1;
+ sal_Bool bWrongKash = sal_False;
+ for (i = 0; i < aKashida.Count(); ++i )
+ {
+ long nCurrKashidaPos = GetKashida( i );
+ if ( nCurrKashidaPos <= nTmpKashidaPos )
+ {
+ bWrongKash = sal_True;
+ break;
+ }
+ nTmpKashidaPos = nCurrKashidaPos;
+ }
+ ASSERT( ! bWrongKash, "Kashida array contains wrong data" )
+#endif
+
+ // remove invalid entries from direction information arrays
+ const USHORT nDirRemove = aDirChg.Count();
+ aDirChg.Remove( 0, nDirRemove );
+ aDirType.Remove( 0, nDirRemove );
+
+ // Perform Unicode Bidi Algorithm for text direction information
+ bool bPerformUBA = UBIDI_LTR != nDefaultDir;
+ nCnt = 0;
+ while( !bPerformUBA && nCnt < CountScriptChg() )
+ {
+ if ( i18n::ScriptType::COMPLEX == GetScriptType( nCnt++ ) )
+ bPerformUBA = true;
+ }
+
+ // do not call the unicode bidi algorithm if not required
+ if ( bPerformUBA )
+ {
+ UpdateBidiInfo( rTxt );
+
+ // #i16354# Change script type for RTL text to CTL:
+ // 1. All text in RTL runs will use the CTL font
+ // #i89825# change the script type also to CTL (hennerdrewes)
+ // 2. Text in embedded LTR runs that does not have any strong LTR characters (numbers!)
+ for ( USHORT nDirIdx = 0; nDirIdx < aDirChg.Count(); ++nDirIdx )
+ {
+ const BYTE nCurrDirType = GetDirType( nDirIdx );
+ // nStart ist start of RTL run:
+ const xub_StrLen nStart = nDirIdx > 0 ? GetDirChg( nDirIdx - 1 ) : 0;
+ // nEnd is end of RTL run:
+ const xub_StrLen nEnd = GetDirChg( nDirIdx );
+
+ if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run
+ ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( rTxt, nStart, nEnd ) ) ) // non-strong text in embedded LTR run
+ {
+ // nScriptIdx points into the ScriptArrays:
+ USHORT nScriptIdx = 0;
+
+ // Skip entries in ScriptArray which are not inside the RTL run:
+ // Make nScriptIdx become the index of the script group with
+ // 1. nStartPosOfGroup <= nStart and
+ // 2. nEndPosOfGroup > nStart
+ while ( GetScriptChg( nScriptIdx ) <= nStart )
+ ++nScriptIdx;
+
+ const xub_StrLen nStartPosOfGroup = nScriptIdx ? GetScriptChg( nScriptIdx - 1 ) : 0;
+ const BYTE nScriptTypeOfGroup = GetScriptType( nScriptIdx );
+
+ ASSERT( nStartPosOfGroup <= nStart && GetScriptChg( nScriptIdx ) > nStart,
+ "Script override with CTL font trouble" )
+
+ // Check if we have to insert a new script change at
+ // position nStart. If nStartPosOfGroup < nStart,
+ // we have to insert a new script change:
+ if ( nStart > 0 && nStartPosOfGroup < nStart )
+ {
+ aScriptChg.Insert( nStart, nScriptIdx );
+ aScriptType.Insert( nScriptTypeOfGroup, nScriptIdx );
+ ++nScriptIdx;
+ }
+
+ // Remove entries in ScriptArray which end inside the RTL run:
+ while ( nScriptIdx < aScriptChg.Count() && GetScriptChg( nScriptIdx ) <= nEnd )
+ {
+ aScriptChg.Remove( nScriptIdx, 1 );
+ aScriptType.Remove( nScriptIdx, 1 );
+ }
+
+ // Insert a new entry in ScriptArray for the end of the RTL run:
+ aScriptChg.Insert( nEnd, nScriptIdx );
+ aScriptType.Insert( i18n::ScriptType::COMPLEX, nScriptIdx );
+
+#if OSL_DEBUG_LEVEL > 1
+ BYTE nScriptType;
+ BYTE nLastScriptType = i18n::ScriptType::WEAK;
+ xub_StrLen nScriptChg;
+ xub_StrLen nLastScriptChg = 0;
+ (void) nLastScriptChg;
+ (void) nLastScriptType;
+
+ for ( USHORT i2 = 0; i2 < aScriptChg.Count(); ++i2 )
+ {
+ nScriptChg = GetScriptChg( i2 );
+ nScriptType = GetScriptType( i2 );
+ ASSERT( nLastScriptType != nScriptType &&
+ nLastScriptChg < nScriptChg,
+ "Heavy InitScriptType() confusion" )
+ }
+#endif
+ }
+ }
+ }
+}
+
+void SwScriptInfo::UpdateBidiInfo( const String& rTxt )
+{
+ // remove invalid entries from direction information arrays
+ const USHORT nDirRemove = aDirChg.Count();
+ aDirChg.Remove( 0, nDirRemove );
+ aDirType.Remove( 0, nDirRemove );
+
+ //
+ // Bidi functions from icu 2.0
+ //
+ UErrorCode nError = U_ZERO_ERROR;
+ UBiDi* pBidi = ubidi_openSized( rTxt.Len(), 0, &nError );
+ nError = U_ZERO_ERROR;
+
+ ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(rTxt.GetBuffer()), rTxt.Len(), // UChar != sal_Unicode in MinGW
+ nDefaultDir, NULL, &nError );
+ nError = U_ZERO_ERROR;
+ long nCount = ubidi_countRuns( pBidi, &nError );
+ int32_t nStart = 0;
+ int32_t nEnd;
+ UBiDiLevel nCurrDir;
+ // counter for direction information arrays
+ USHORT nCntDir = 0;
+
+ for ( USHORT nIdx = 0; nIdx < nCount; ++nIdx )
+ {
+ ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir );
+ aDirChg.Insert( (USHORT)nEnd, nCntDir );
+ aDirType.Insert( (BYTE)nCurrDir, nCntDir++ );
+ nStart = nEnd;
+ }
+
+ ubidi_close( pBidi );
+}
+
+
+/*************************************************************************
+ * SwScriptInfo::NextScriptChg(..)
+ * returns the position of the next character which belongs to another script
+ * than the character of the actual (input) position.
+ * If there's no script change until the end of the paragraph, it will return
+ * STRING_LEN.
+ * Scripts are Asian (Chinese, Japanese, Korean),
+ * Latin ( English etc.)
+ * and Complex ( Hebrew, Arabian )
+ *************************************************************************/
+
+xub_StrLen SwScriptInfo::NextScriptChg( const xub_StrLen nPos ) const
+{
+ USHORT nEnd = CountScriptChg();
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ if( nPos < GetScriptChg( nX ) )
+ return GetScriptChg( nX );
+ }
+
+ return STRING_LEN;
+}
+
+/*************************************************************************
+ * SwScriptInfo::ScriptType(..)
+ * returns the script of the character at the input position
+ *************************************************************************/
+
+BYTE SwScriptInfo::ScriptType( const xub_StrLen nPos ) const
+{
+ USHORT nEnd = CountScriptChg();
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ if( nPos < GetScriptChg( nX ) )
+ return GetScriptType( nX );
+ }
+
+ // the default is the application language script
+ return (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
+}
+
+xub_StrLen SwScriptInfo::NextDirChg( const xub_StrLen nPos,
+ const BYTE* pLevel ) const
+{
+ BYTE nCurrDir = pLevel ? *pLevel : 62;
+ USHORT nEnd = CountDirChg();
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ if( nPos < GetDirChg( nX ) &&
+ ( nX + 1 == nEnd || GetDirType( nX + 1 ) <= nCurrDir ) )
+ return GetDirChg( nX );
+ }
+
+ return STRING_LEN;
+}
+
+BYTE SwScriptInfo::DirType( const xub_StrLen nPos ) const
+{
+ USHORT nEnd = CountDirChg();
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ if( nPos < GetDirChg( nX ) )
+ return GetDirType( nX );
+ }
+
+ return 0;
+}
+
+/*************************************************************************
+ * SwScriptInfo::MaskHiddenRanges(..)
+ * Takes a string and replaced the hidden ranges with cChar.
+ **************************************************************************/
+
+USHORT SwScriptInfo::MaskHiddenRanges( const SwTxtNode& rNode, XubString& rText,
+ const xub_StrLen nStt, const xub_StrLen nEnd,
+ const xub_Unicode cChar )
+{
+ ASSERT( rNode.GetTxt().Len() == rText.Len(), "MaskHiddenRanges, string len mismatch" )
+
+ PositionList aList;
+ xub_StrLen nHiddenStart;
+ xub_StrLen nHiddenEnd;
+ USHORT nNumOfHiddenChars = 0;
+ GetBoundsOfHiddenRange( rNode, 0, nHiddenStart, nHiddenEnd, &aList );
+ PositionList::const_reverse_iterator rFirst( aList.end() );
+ PositionList::const_reverse_iterator rLast( aList.begin() );
+ while ( rFirst != rLast )
+ {
+ nHiddenEnd = *(rFirst++);
+ nHiddenStart = *(rFirst++);
+
+ if ( nHiddenEnd < nStt || nHiddenStart > nEnd )
+ continue;
+
+ while ( nHiddenStart < nHiddenEnd && nHiddenStart < nEnd )
+ {
+ if ( nHiddenStart >= nStt && nHiddenStart < nEnd )
+ {
+ rText.SetChar( nHiddenStart, cChar );
+ ++nNumOfHiddenChars;
+ }
+ ++nHiddenStart;
+ }
+ }
+
+ return nNumOfHiddenChars;
+}
+
+/*************************************************************************
+ * SwScriptInfo::DeleteHiddenRanges(..)
+ * Takes a SwTxtNode and deletes the hidden ranges from the node.
+ **************************************************************************/
+
+void SwScriptInfo::DeleteHiddenRanges( SwTxtNode& rNode )
+{
+ PositionList aList;
+ xub_StrLen nHiddenStart;
+ xub_StrLen nHiddenEnd;
+ GetBoundsOfHiddenRange( rNode, 0, nHiddenStart, nHiddenEnd, &aList );
+ PositionList::const_reverse_iterator rFirst( aList.end() );
+ PositionList::const_reverse_iterator rLast( aList.begin() );
+ while ( rFirst != rLast )
+ {
+ nHiddenEnd = *(rFirst++);
+ nHiddenStart = *(rFirst++);
+
+ SwPaM aPam( rNode, nHiddenStart, rNode, nHiddenEnd );
+ rNode.getIDocumentContentOperations()->DeleteRange( aPam );
+ }
+}
+
+/*************************************************************************
+ * SwScriptInfo::GetBoundsOfHiddenRange(..)
+ * static version
+ **************************************************************************/
+
+bool SwScriptInfo::GetBoundsOfHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos,
+ xub_StrLen& rnStartPos, xub_StrLen& rnEndPos,
+ PositionList* pList )
+{
+ rnStartPos = STRING_LEN;
+ rnEndPos = 0;
+
+ bool bNewContainsHiddenChars = false;
+
+ //
+ // Optimization: First examine the flags at the text node:
+ //
+ if ( !rNode.IsCalcHiddenCharFlags() )
+ {
+ bool bWholePara = rNode.HasHiddenCharAttribute( true );
+ bool bContainsHiddenChars = rNode.HasHiddenCharAttribute( false );
+ if ( !bContainsHiddenChars )
+ return false;
+
+ if ( bWholePara )
+ {
+ if ( pList )
+ {
+ pList->push_back( 0 );
+ pList->push_back( rNode.GetTxt().Len() );
+ }
+
+ rnStartPos = 0;
+ rnEndPos = rNode.GetTxt().Len();
+ return true;
+ }
+ }
+
+ const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rNode );
+ if ( pSI )
+ {
+ //
+ // Check first, if we have a valid SwScriptInfo object for this text node:
+ //
+ bNewContainsHiddenChars = pSI->GetBoundsOfHiddenRange( nPos, rnStartPos, rnEndPos, pList );
+ const bool bNewHiddenCharsHidePara = ( rnStartPos == 0 && rnEndPos >= rNode.GetTxt().Len() );
+ rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
+ }
+ else
+ {
+ //
+ // No valid SwScriptInfo Object, we have to do it the hard way:
+ //
+ Range aRange( 0, rNode.GetTxt().Len() ? rNode.GetTxt().Len() - 1 : 0 );
+ MultiSelection aHiddenMulti( aRange );
+ SwScriptInfo::CalcHiddenRanges( rNode, aHiddenMulti );
+ for( USHORT i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
+ {
+ const Range& rRange = aHiddenMulti.GetRange( i );
+ const xub_StrLen nHiddenStart = (xub_StrLen)rRange.Min();
+ const xub_StrLen nHiddenEnd = (xub_StrLen)rRange.Max() + 1;
+
+ if ( nHiddenStart > nPos )
+ break;
+ else if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
+ {
+ rnStartPos = nHiddenStart;
+ rnEndPos = Min( nHiddenEnd, rNode.GetTxt().Len() );
+ break;
+ }
+ }
+
+ if ( pList )
+ {
+ for( USHORT i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
+ {
+ const Range& rRange = aHiddenMulti.GetRange( i );
+ pList->push_back( (xub_StrLen)rRange.Min() );
+ pList->push_back( (xub_StrLen)rRange.Max() + 1 );
+ }
+ }
+
+ bNewContainsHiddenChars = aHiddenMulti.GetRangeCount() > 0;
+ }
+
+ return bNewContainsHiddenChars;
+}
+
+/*************************************************************************
+ * SwScriptInfo::GetBoundsOfHiddenRange(..)
+ * non-static version
+ **************************************************************************/
+
+bool SwScriptInfo::GetBoundsOfHiddenRange( xub_StrLen nPos, xub_StrLen& rnStartPos,
+ xub_StrLen& rnEndPos, PositionList* pList ) const
+{
+ rnStartPos = STRING_LEN;
+ rnEndPos = 0;
+
+ USHORT nEnd = CountHiddenChg();
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ const xub_StrLen nHiddenStart = GetHiddenChg( nX++ );
+ const xub_StrLen nHiddenEnd = GetHiddenChg( nX );
+
+ if ( nHiddenStart > nPos )
+ break;
+ else if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
+ {
+ rnStartPos = nHiddenStart;
+ rnEndPos = nHiddenEnd;
+ break;
+ }
+ }
+
+ if ( pList )
+ {
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ pList->push_back( GetHiddenChg( nX++ ) );
+ pList->push_back( GetHiddenChg( nX ) );
+ }
+ }
+
+ return CountHiddenChg() > 0;
+}
+
+/*************************************************************************
+ * SwScriptInfo::IsInHiddenRange()
+ **************************************************************************/
+
+bool SwScriptInfo::IsInHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos )
+{
+ xub_StrLen nStartPos;
+ xub_StrLen nEndPos;
+ SwScriptInfo::GetBoundsOfHiddenRange( rNode, nPos, nStartPos, nEndPos );
+ return nStartPos != STRING_LEN;
+}
+
+
+#if OSL_DEBUG_LEVEL > 1
+/*************************************************************************
+ * SwScriptInfo::CompType(..)
+ * returns the type of the compressed character
+ *************************************************************************/
+
+BYTE SwScriptInfo::CompType( const xub_StrLen nPos ) const
+{
+ USHORT nEnd = CountCompChg();
+ for( USHORT nX = 0; nX < nEnd; ++nX )
+ {
+ xub_StrLen nChg = GetCompStart( nX );
+
+ if ( nPos < nChg )
+ return NONE;
+
+ if( nPos < nChg + GetCompLen( nX ) )
+ return GetCompType( nX );
+ }
+ return NONE;
+}
+#endif
+
+/*************************************************************************
+ * SwScriptInfo::HasKana()
+ * returns, if there are compressable kanas or specials
+ * betwenn nStart and nEnd
+ *************************************************************************/
+
+USHORT SwScriptInfo::HasKana( xub_StrLen nStart, const xub_StrLen nLen ) const
+{
+ USHORT nCnt = CountCompChg();
+ xub_StrLen nEnd = nStart + nLen;
+
+ for( USHORT nX = 0; nX < nCnt; ++nX )
+ {
+ xub_StrLen nKanaStart = GetCompStart( nX );
+ xub_StrLen nKanaEnd = nKanaStart + GetCompLen( nX );
+
+ if ( nKanaStart >= nEnd )
+ return USHRT_MAX;
+
+ if ( nStart < nKanaEnd )
+ return nX;
+ }
+
+ return USHRT_MAX;
+}
+
+/*************************************************************************
+ * SwScriptInfo::Compress()
+ *************************************************************************/
+
+long SwScriptInfo::Compress( sal_Int32* pKernArray, xub_StrLen nIdx, xub_StrLen nLen,
+ const USHORT nCompress, const USHORT nFontHeight,
+ Point* pPoint ) const
+{
+ ASSERT( nCompress, "Compression without compression?!" );
+ ASSERT( nLen, "Compression without text?!" );
+ USHORT nCompCount = CountCompChg();
+
+ // In asian typography, there are full width and half width characters.
+ // Full width punctuation characters can be compressed by 50 %
+ // to determine this, we compare the font width with 75 % of its height
+ USHORT nMinWidth = ( 3 * nFontHeight ) / 4;
+
+ USHORT nCompIdx = HasKana( nIdx, nLen );
+
+ if ( USHRT_MAX == nCompIdx )
+ return 0;
+
+ xub_StrLen nChg = GetCompStart( nCompIdx );
+ xub_StrLen nCompLen = GetCompLen( nCompIdx );
+ USHORT nI = 0;
+ nLen = nLen + nIdx;
+
+ if( nChg > nIdx )
+ {
+ nI = nChg - nIdx;
+ nIdx = nChg;
+ }
+ else if( nIdx < nChg + nCompLen )
+ nCompLen -= nIdx - nChg;
+
+ if( nIdx > nLen || nCompIdx >= nCompCount )
+ return 0;
+
+ long nSub = 0;
+ long nLast = nI ? pKernArray[ nI - 1 ] : 0;
+ do
+ {
+ USHORT nType = GetCompType( nCompIdx );
+#if OSL_DEBUG_LEVEL > 1
+ ASSERT( nType == CompType( nIdx ), "Gimme the right type!" );
+#endif
+ nCompLen = nCompLen + nIdx;
+ if( nCompLen > nLen )
+ nCompLen = nLen;
+
+ // are we allowed to compress the character?
+ if ( pKernArray[ nI ] - nLast < nMinWidth )
+ {
+ nIdx++; nI++;
+ }
+ else
+ {
+ while( nIdx < nCompLen )
+ {
+ ASSERT( SwScriptInfo::NONE != nType, "None compression?!" );
+
+ // nLast is width of current character
+ nLast -= pKernArray[ nI ];
+
+ nLast *= nCompress;
+ long nMove = 0;
+ if( SwScriptInfo::KANA != nType )
+ {
+ nLast /= 20000;
+ if( pPoint && SwScriptInfo::SPECIAL_LEFT == nType )
+ {
+ if( nI )
+ nMove = nLast;
+ else
+ {
+ pPoint->X() += nLast;
+ nLast = 0;
+ }
+ }
+ }
+ else
+ nLast /= 100000;
+ nSub -= nLast;
+ nLast = pKernArray[ nI ];
+ if( nMove )
+ pKernArray[ nI - 1 ] += nMove;
+ pKernArray[ nI++ ] -= nSub;
+ ++nIdx;
+ }
+ }
+
+ if( nIdx < nLen )
+ {
+ xub_StrLen nTmpChg;
+ if( ++nCompIdx < nCompCount )
+ {
+ nTmpChg = GetCompStart( nCompIdx );
+ if( nTmpChg > nLen )
+ nTmpChg = nLen;
+ nCompLen = GetCompLen( nCompIdx );
+ }
+ else
+ nTmpChg = nLen;
+ while( nIdx < nTmpChg )
+ {
+ nLast = pKernArray[ nI ];
+ pKernArray[ nI++ ] -= nSub;
+ ++nIdx;
+ }
+ }
+ else
+ break;
+ } while( nIdx < nLen );
+ return nSub;
+}
+
+/*************************************************************************
+ * SwScriptInfo::KashidaJustify()
+ *************************************************************************/
+
+// Note on calling KashidaJustify():
+// Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
+// total number of kashida positions, or the number of kashida positions after some positions
+// have been dropped, depending on the state of the aKashidaInvalid array.
+
+USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray,
+ sal_Int32* pScrArray,
+ xub_StrLen nStt,
+ xub_StrLen nLen,
+ long nSpaceAdd ) const
+{
+ ASSERT( nLen, "Kashida justification without text?!" )
+
+ if( !IsKashidaLine(nStt))
+ return STRING_LEN;
+
+ // evaluate kashida informatin in collected in SwScriptInfo
+
+ USHORT nCntKash = 0;
+ while( nCntKash < CountKashida() )
+ {
+ if ( nStt <= GetKashida( nCntKash ) )
+ break;
+ else
+ nCntKash++;
+ }
+
+ const xub_StrLen nEnd = nStt + nLen;
+
+ USHORT nCntKashEnd = nCntKash;
+ while ( nCntKashEnd < CountKashida() )
+ {
+ if ( nEnd <= GetKashida( nCntKashEnd ) )
+ break;
+ else
+ nCntKashEnd++;
+ }
+
+ USHORT nActualKashCount = nCntKashEnd - nCntKash;
+ for ( USHORT i = nCntKash; i < nCntKashEnd; ++i )
+ {
+ if ( nActualKashCount && !IsKashidaValid ( i ) )
+ --nActualKashCount;
+ }
+
+ if ( !pKernArray )
+ return nActualKashCount;
+
+ // do nothing if there is no more kashida
+ if ( nCntKash < CountKashida() )
+ {
+ // skip any invalid kashidas
+ while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd )
+ ++nCntKash;
+
+ xub_StrLen nKashidaPos = GetKashida( nCntKash );
+ xub_StrLen nIdx = nKashidaPos;
+ long nKashAdd = nSpaceAdd;
+
+ while ( nIdx < nEnd )
+ {
+ USHORT nArrayPos = nIdx - nStt;
+
+ // next kashida position
+ ++nCntKash;
+ while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd )
+ ++nCntKash;
+
+ nIdx = nCntKash < CountKashida() && IsKashidaValid ( nCntKash ) ? GetKashida( nCntKash ) : nEnd;
+ if ( nIdx > nEnd )
+ nIdx = nEnd;
+
+ const USHORT nArrayEnd = nIdx - nStt;
+
+ while ( nArrayPos < nArrayEnd )
+ {
+ pKernArray[ nArrayPos ] += nKashAdd;
+ if ( pScrArray )
+ pScrArray[ nArrayPos ] += nKashAdd;
+ ++nArrayPos;
+ }
+ nKashAdd += nSpaceAdd;
+ }
+ }
+
+ return 0;
+}
+
+/*************************************************************************
+ * SwScriptInfo::IsArabicText()
+ *
+ * Checks if the current text is 'Arabic' text. Note that only the first
+ * character has to be checked because a ctl portion only contains one
+ * script, see NewTxtPortion
+ *************************************************************************/
+sal_Bool SwScriptInfo::IsArabicText( const XubString& rTxt, xub_StrLen nStt, xub_StrLen nLen )
+{
+ using namespace ::com::sun::star::i18n;
+ static ScriptTypeList typeList[] = {
+ { UnicodeScript_kArabic, UnicodeScript_kArabic, UnicodeScript_kArabic }, // 11,
+ { UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, UnicodeScript_kScriptCount } // 88
+ };
+
+ // go forward if current position does not hold a regular character:
+ const CharClass& rCC = GetAppCharClass();
+ sal_Int32 nIdx = nStt;
+ const xub_StrLen nEnd = nStt + nLen;
+ while ( nIdx < nEnd && !rCC.isLetterNumeric( rTxt, (xub_StrLen)nIdx ) )
+ {
+ ++nIdx;
+ }
+
+ if( nIdx == nEnd )
+ {
+ // no regular character found in this portion. Go backward:
+ --nIdx;
+ while ( nIdx >= 0 && !rCC.isLetterNumeric( rTxt, (xub_StrLen)nIdx ) )
+ {
+ --nIdx;
+ }
+ }
+
+ if( nIdx >= 0 )
+ {
+ const xub_Unicode cCh = rTxt.GetChar( (xub_StrLen)nIdx );
+ const sal_Int16 type = unicode::getUnicodeScriptType( cCh, typeList, UnicodeScript_kScriptCount );
+ return type == UnicodeScript_kArabic;
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwScriptInfo::IsKashidaValid()
+ *************************************************************************/
+
+sal_Bool SwScriptInfo::IsKashidaValid ( xub_StrLen nKashPos ) const
+{
+ for ( xub_StrLen i = 0; i < aKashidaInvalid.Count(); ++i )
+ {
+ if ( aKashidaInvalid [ i ] == nKashPos )
+ return false;
+ }
+ return true;
+}
+
+/*************************************************************************
+ * SwScriptInfo::ClearKashidaInvalid()
+ *************************************************************************/
+
+void SwScriptInfo::ClearKashidaInvalid ( xub_StrLen nKashPos )
+{
+ for ( xub_StrLen i = 0; i < aKashidaInvalid.Count(); ++i )
+ {
+ if ( aKashidaInvalid [ i ] == nKashPos )
+ {
+ aKashidaInvalid.Remove (i, 1);
+ return;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwScriptInfo::MarkOrClearKashidaInvalid()
+ *************************************************************************/
+// bMark == true:
+// marks the first valid kashida in the given text range as invalid
+
+// bMark == false:
+// clears all kashida invalid flags in the given text range
+
+bool SwScriptInfo::MarkOrClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount )
+{
+ USHORT nCntKash = 0;
+ while( nCntKash < CountKashida() )
+ {
+ if ( nStt <= GetKashida( nCntKash ) )
+ break;
+ else
+ nCntKash++;
+ }
+
+ const xub_StrLen nEnd = nStt + nLen;
+
+ while ( nCntKash < CountKashida() )
+ {
+ if ( nEnd <= GetKashida( nCntKash ) )
+ break;
+ else
+ {
+ if(bMark)
+ {
+ if ( IsKashidaValid ( nCntKash ) )
+ {
+ MarkKashidaInvalid ( nCntKash );
+ --nMarkCount;
+ if(!nMarkCount)
+ return true;
+ }
+ }
+ else
+ {
+ ClearKashidaInvalid ( nCntKash );
+ }
+ nCntKash++;
+ }
+ }
+ return false;
+}
+
+void SwScriptInfo::MarkKashidaInvalid ( xub_StrLen nKashPos )
+{
+ aKashidaInvalid.Insert( nKashPos, aKashidaInvalid.Count() );
+}
+
+/*************************************************************************
+ * SwScriptInfo::GetKashidaPositions()
+ *************************************************************************/
+// retrieve the kashida positions in the given text range
+USHORT SwScriptInfo::GetKashidaPositions ( xub_StrLen nStt, xub_StrLen nLen,
+ xub_StrLen* pKashidaPosition )
+{
+ USHORT nCntKash = 0;
+ while( nCntKash < CountKashida() )
+ {
+ if ( nStt <= GetKashida( nCntKash ) )
+ break;
+ else
+ nCntKash++;
+ }
+
+ const xub_StrLen nEnd = nStt + nLen;
+
+ USHORT nCntKashEnd = nCntKash;
+ while ( nCntKashEnd < CountKashida() )
+ {
+ if ( nEnd <= GetKashida( nCntKashEnd ) )
+ break;
+ else
+ {
+ pKashidaPosition [ nCntKashEnd - nCntKash ] = GetKashida ( nCntKashEnd );
+ nCntKashEnd++;
+ }
+ }
+ return nCntKashEnd - nCntKash;
+}
+
+void SwScriptInfo::SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen )
+{
+ aNoKashidaLine.Insert( nStt, aNoKashidaLine.Count());
+ aNoKashidaLineEnd.Insert( nStt+nLen, aNoKashidaLineEnd.Count());
+}
+
+/*************************************************************************
+ * SwScriptInfo::IsKashidaLine()
+ *************************************************************************/
+// determines if the line uses kashida justification
+
+bool SwScriptInfo::IsKashidaLine ( xub_StrLen nCharIdx ) const
+{
+ for( xub_StrLen i = 0; i < aNoKashidaLine.Count(); ++i )
+ {
+ if( nCharIdx >= aNoKashidaLine[ i ] && nCharIdx < aNoKashidaLineEnd[ i ])
+ return false;
+ }
+ return true;
+}
+/*************************************************************************
+ * SwScriptInfo::ClearKashidaLine()
+ *************************************************************************/
+
+void SwScriptInfo::ClearNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen )
+{
+ xub_StrLen i = 0;
+ while( i < aNoKashidaLine.Count())
+ {
+ if( nStt + nLen >= aNoKashidaLine[ i ] && nStt < aNoKashidaLineEnd [ i ] )
+ {
+ aNoKashidaLine.Remove(i, 1);
+ aNoKashidaLineEnd.Remove(i, 1);
+ }
+ else
+ ++i;
+ }
+}
+
+/*************************************************************************
+ * SwScriptInfo::MarkKashidasInvalid()
+ *************************************************************************/
+// mark the given character indices as invalid kashida positions
+bool SwScriptInfo::MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen* pKashidaPositions )
+{
+ ASSERT( pKashidaPositions && nCnt > 0, "Where are kashidas?" )
+
+ USHORT nCntKash = 0;
+ xub_StrLen nKashidaPosIdx = 0;
+
+ while ( nCntKash < CountKashida() && nKashidaPosIdx < nCnt )
+ {
+ if ( pKashidaPositions [nKashidaPosIdx] > GetKashida( nCntKash ) )
+ {
+ nCntKash++;
+ continue;
+ }
+
+ if ( pKashidaPositions [nKashidaPosIdx] == GetKashida( nCntKash ) && IsKashidaValid ( nCntKash ) )
+ {
+ MarkKashidaInvalid ( nCntKash );
+ }
+ else
+ return false; // something is wrong
+ nKashidaPosIdx++;
+ }
+ return true;
+}
+
+/*************************************************************************
+ * SwScriptInfo::ThaiJustify()
+ *************************************************************************/
+
+USHORT SwScriptInfo::ThaiJustify( const XubString& rTxt, sal_Int32* pKernArray,
+ sal_Int32* pScrArray, xub_StrLen nStt,
+ xub_StrLen nLen, xub_StrLen nNumberOfBlanks,
+ long nSpaceAdd )
+{
+ ASSERT( nStt + nLen <= rTxt.Len(), "String in ThaiJustify too small" )
+
+ SwTwips nNumOfTwipsToDistribute = nSpaceAdd * nNumberOfBlanks /
+ SPACING_PRECISION_FACTOR;
+
+ long nSpaceSum = 0;
+ USHORT nCnt = 0;
+
+ for ( USHORT nI = 0; nI < nLen; ++nI )
+ {
+ const xub_Unicode cCh = rTxt.GetChar( nStt + nI );
+
+ // check if character is not above or below base
+ if ( ( 0xE34 > cCh || cCh > 0xE3A ) &&
+ ( 0xE47 > cCh || cCh > 0xE4E ) && cCh != 0xE31 )
+ {
+ if ( nNumberOfBlanks > 0 )
+ {
+ nSpaceAdd = nNumOfTwipsToDistribute / nNumberOfBlanks;
+ --nNumberOfBlanks;
+ nNumOfTwipsToDistribute -= nSpaceAdd;
+ }
+ nSpaceSum += nSpaceAdd;
+ ++nCnt;
+ }
+
+ if ( pKernArray ) pKernArray[ nI ] += nSpaceSum;
+ if ( pScrArray ) pScrArray[ nI ] += nSpaceSum;
+ }
+
+ return nCnt;
+}
+
+/*************************************************************************
+ * SwScriptInfo::GetScriptInfo()
+ *************************************************************************/
+
+SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTxtNode& rTNd,
+ sal_Bool bAllowInvalid )
+{
+ SwClientIter aClientIter( (SwTxtNode&)rTNd );
+ SwClient* pLast = aClientIter.GoStart();
+ SwScriptInfo* pScriptInfo = 0;
+
+ while( pLast )
+ {
+ if ( pLast->ISA( SwTxtFrm ) )
+ {
+ pScriptInfo = (SwScriptInfo*)((SwTxtFrm*)pLast)->GetScriptInfo();
+ if ( pScriptInfo )
+ {
+ if ( !bAllowInvalid && STRING_LEN != pScriptInfo->GetInvalidity() )
+ pScriptInfo = 0;
+ else break;
+ }
+ }
+ pLast = ++aClientIter;
+ }
+
+ return pScriptInfo;
+}
+
+/*************************************************************************
+ * SwParaPortion::SwParaPortion()
+ *************************************************************************/
+SwParaPortion::SwParaPortion()
+{
+ FormatReset();
+ bFlys = bFtnNum = bMargin = sal_False;
+ SetWhichPor( POR_PARA );
+}
+
+/*************************************************************************
+ * SwParaPortion::~SwParaPortion()
+ *************************************************************************/
+SwParaPortion::~SwParaPortion()
+{
+}
+
+/*************************************************************************
+ * SwParaPortion::GetParLen()
+ *************************************************************************/
+xub_StrLen SwParaPortion::GetParLen() const
+{
+ xub_StrLen nLen = 0;
+ const SwLineLayout *pLay = this;
+ while( pLay )
+ {
+ DBG_LOOP;
+ nLen = nLen + pLay->GetLen();
+ pLay = pLay->GetNext();
+ }
+ return nLen;
+}
+
+/*************************************************************************
+ * SwParaPortion::FindDropPortion()
+ *************************************************************************/
+
+const SwDropPortion *SwParaPortion::FindDropPortion() const
+{
+ const SwLineLayout *pLay = this;
+ while( pLay && pLay->IsDummy() )
+ pLay = pLay->GetNext();
+ while( pLay )
+ {
+ const SwLinePortion *pPos = pLay->GetPortion();
+ while ( pPos && !pPos->GetLen() )
+ pPos = pPos->GetPortion();
+ if( pPos && pPos->IsDropPortion() )
+ return (SwDropPortion *)pPos;
+ pLay = pLay->GetLen() ? NULL : pLay->GetNext();
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ * SwLineLayout::Init()
+ *************************************************************************/
+
+void SwLineLayout::Init( SwLinePortion* pNextPortion )
+{
+ Height( 0 );
+ Width( 0 );
+ SetLen( 0 );
+ SetAscent( 0 );
+ SetRealHeight( 0 );
+ SetPortion( pNextPortion );
+}
+
+/*-----------------16.11.00 11:04-------------------
+ * HangingMargin()
+ * looks for hanging punctuation portions in the paragraph
+ * and return the maximum right offset of them.
+ * If no such portion is found, the Margin/Hanging-flags will be atualized.
+ * --------------------------------------------------*/
+
+SwTwips SwLineLayout::_GetHangingMargin() const
+{
+ SwLinePortion* pPor = GetPortion();
+ BOOL bFound = sal_False;
+ SwTwips nDiff = 0;
+ while( pPor)
+ {
+ if( pPor->IsHangingPortion() )
+ {
+ nDiff = ((SwHangingPortion*)pPor)->GetInnerWidth() - pPor->Width();
+ if( nDiff )
+ bFound = sal_True;
+ }
+ // the last post its portion
+ else if ( pPor->IsPostItsPortion() && ! pPor->GetPortion() )
+ nDiff = nAscent;
+
+ pPor = pPor->GetPortion();
+ }
+ if( !bFound ) // actualize the hanging-flag
+ ((SwLineLayout*)this)->SetHanging( sal_False );
+ return nDiff;
+}
+
+SwTwips SwTxtFrm::HangingMargin() const
+{
+ ASSERT( HasPara(), "Don't call me without a paraportion" );
+ if( !GetPara()->IsMargin() )
+ return 0;
+ const SwLineLayout* pLine = GetPara();
+ SwTwips nRet = 0;
+ do
+ {
+ SwTwips nDiff = pLine->GetHangingMargin();
+ if( nDiff > nRet )
+ nRet = nDiff;
+ pLine = pLine->GetNext();
+ } while ( pLine );
+ if( !nRet ) // actualize the margin-flag
+ ((SwParaPortion*)GetPara())->SetMargin( sal_False );
+ return nRet;
+}
+
+
+/*************************************************************************
+ * SwScriptInfo::CalcHiddenRanges()
+ *
+ * Returns a MultiSection indicating the hidden ranges.
+ *************************************************************************/
+
+void SwScriptInfo::CalcHiddenRanges( const SwTxtNode& rNode, MultiSelection& rHiddenMulti )
+{
+ const SfxPoolItem* pItem = 0;
+ if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState( RES_CHRATR_HIDDEN, TRUE, &pItem ) &&
+ ((SvxCharHiddenItem*)pItem)->GetValue() )
+ {
+ rHiddenMulti.SelectAll();
+ }
+
+ const SwpHints* pHints = rNode.GetpSwpHints();
+ const SwTxtAttr* pTxtAttr = 0;
+
+ if( pHints )
+ {
+ MSHORT nTmp = 0;
+
+ while( nTmp < pHints->GetStartCount() )
+ {
+ pTxtAttr = pHints->GetStart( nTmp++ );
+ const SvxCharHiddenItem* pHiddenItem = static_cast<const SvxCharHiddenItem*>( CharFmt::GetItem( *pTxtAttr, RES_CHRATR_HIDDEN ) );
+ if( pHiddenItem )
+ {
+ xub_StrLen nSt = *pTxtAttr->GetStart();
+ xub_StrLen nEnd = *pTxtAttr->GetEnd();
+ if( nEnd > nSt )
+ {
+ Range aTmp( nSt, nEnd - 1 );
+ rHiddenMulti.Select( aTmp, pHiddenItem->GetValue() );
+ }
+ }
+ }
+ }
+
+ // If there are any hidden ranges in the current text node, we have
+ // to unhide the redlining ranges:
+ const IDocumentRedlineAccess& rIDRA = *rNode.getIDocumentRedlineAccess();
+ if ( rHiddenMulti.GetRangeCount() && IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineMode() ) )
+ {
+ USHORT nAct = rIDRA.GetRedlinePos( rNode, USHRT_MAX );
+
+ for ( ; nAct < rIDRA.GetRedlineTbl().Count(); nAct++ )
+ {
+ const SwRedline* pRed = rIDRA.GetRedlineTbl()[ nAct ];
+
+ if ( pRed->Start()->nNode > rNode.GetIndex() )
+ break;
+
+ xub_StrLen nRedlStart;
+ xub_StrLen nRedlnEnd;
+ pRed->CalcStartEnd( rNode.GetIndex(), nRedlStart, nRedlnEnd );
+ if ( nRedlnEnd > nRedlStart )
+ {
+ Range aTmp( nRedlStart, nRedlnEnd - 1 );
+ rHiddenMulti.Select( aTmp, false );
+ }
+ }
+ }
+
+ //
+ // We calculated a lot of stuff. Finally we can update the flags at the text node.
+ //
+ const bool bNewContainsHiddenChars = rHiddenMulti.GetRangeCount() > 0;
+ bool bNewHiddenCharsHidePara = false;
+ if ( bNewContainsHiddenChars )
+ {
+ const Range& rRange = rHiddenMulti.GetRange( 0 );
+ const xub_StrLen nHiddenStart = (xub_StrLen)rRange.Min();
+ const xub_StrLen nHiddenEnd = (xub_StrLen)rRange.Max() + 1;
+ bNewHiddenCharsHidePara = ( nHiddenStart == 0 && nHiddenEnd >= rNode.GetTxt().Len() );
+ }
+ rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
+}
+
diff --git a/sw/source/core/text/porlay.hxx b/sw/source/core/text/porlay.hxx
new file mode 100644
index 000000000000..f8a7deb9fe29
--- /dev/null
+++ b/sw/source/core/text/porlay.hxx
@@ -0,0 +1,427 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORLAY_HXX
+#define _PORLAY_HXX
+
+#include <tools/string.hxx>
+#include <tools/fract.hxx>
+#include <scriptinfo.hxx>
+
+#include "swrect.hxx" // SwRepaint
+#include "portxt.hxx"
+#include "swfont.hxx"
+
+#include <vector>
+
+class SwMarginPortion;
+class SwDropPortion;
+class SvStream;
+class SwTxtFormatter;
+
+/*************************************************************************
+ * class SwCharRange
+ *************************************************************************/
+
+class SwCharRange
+{
+ xub_StrLen nStart, nLen;
+public:
+ inline SwCharRange( const xub_StrLen nInitStart = 0,
+ const xub_StrLen nInitLen = 0): nStart( nInitStart ), nLen(nInitLen) {}
+ inline xub_StrLen &Start() { return nStart; }
+ inline const xub_StrLen &Start() const { return nStart; }
+ inline void LeftMove( xub_StrLen nNew )
+ { if ( nNew < nStart ) { nLen += nStart-nNew; nStart = nNew; } }
+ inline xub_StrLen End() const
+ { return nStart + nLen; }
+ inline xub_StrLen &Len() { return nLen; }
+ inline const xub_StrLen &Len() const { return nLen; }
+ inline sal_Bool operator<(const SwCharRange &rRange) const
+ { return nStart < rRange.nStart; }
+ inline sal_Bool operator>(const SwCharRange &rRange) const
+ { return nStart + nLen > rRange.nStart + rRange.nLen; }
+ inline sal_Bool operator!=(const SwCharRange &rRange) const
+ { return *this < rRange || *this > rRange; }
+ SwCharRange &operator+=(const SwCharRange &rRange);
+};
+
+/*************************************************************************
+ * class SwRepaint
+ *************************************************************************/
+
+// SwRepaint ist ein dokumentglobales SwRect mit einem nOfst der angibt,
+// ab wo in der ersten Zeile gepaintet werden soll
+// und einem nRightOfst, der den rechten Rand bestimmt
+class SwRepaint : public SwRect
+{
+ SwTwips nOfst;
+ SwTwips nRightOfst;
+public:
+ SwRepaint() : SwRect(), nOfst( 0 ), nRightOfst( 0 ) {}
+ SwRepaint( const SwRepaint& rRep ) : SwRect( rRep ), nOfst( rRep.nOfst ),
+ nRightOfst( rRep.nRightOfst ) {}
+
+ SwTwips GetOfst() const { return nOfst; }
+ void SetOfst( const SwTwips nNew ) { nOfst = nNew; }
+ SwTwips GetRightOfst() const { return nRightOfst; }
+ void SetRightOfst( const SwTwips nNew ) { nRightOfst = nNew; }
+};
+
+/*************************************************************************
+ * class SwLineLayout
+ *************************************************************************/
+
+class SwLineLayout : public SwTxtPortion
+{
+private:
+ SwLineLayout *pNext; // Die naechste Zeile.
+ std::vector<long>* pLLSpaceAdd; // Used for justified alignment.
+ SvUShorts* pKanaComp; // Used for Kana compression.
+ KSHORT nRealHeight; // Die aus Zeilenabstand/Register resultierende Hoehe.
+ sal_Bool bFormatAdj : 1;
+ sal_Bool bDummy : 1;
+ sal_Bool bFntChg : 1;
+ sal_Bool bEndHyph : 1;
+ sal_Bool bMidHyph : 1;
+ sal_Bool bTab : 1;
+ sal_Bool bFly : 1;
+ sal_Bool bRest : 1;
+ sal_Bool bBlinking : 1;
+ sal_Bool bClipping : 1; // Clipping erforderlich wg. exakter Zeilenhoehe
+ sal_Bool bContent : 1; // enthaelt Text, fuer Zeilennumerierung
+ sal_Bool bRedline : 1; // enthaelt Redlining
+ sal_Bool bForcedLeftMargin : 1; // vom Fly verschobener linker Einzug
+ sal_Bool bHanging : 1; // contents a hanging portion in the margin
+ sal_Bool bUnderscore : 1;
+
+ SwTwips _GetHangingMargin() const;
+
+public:
+ // von SwLinePortion
+ virtual SwLinePortion *Insert( SwLinePortion *pPortion );
+ virtual SwLinePortion *Append( SwLinePortion *pPortion );
+ inline SwLinePortion *GetFirstPortion() const;
+
+ // Flags
+ inline void ResetFlags();
+ inline void SetFormatAdj( const sal_Bool bNew ) { bFormatAdj = bNew; }
+ inline sal_Bool IsFormatAdj() const { return bFormatAdj; }
+ inline void SetFntChg( const sal_Bool bNew ) { bFntChg = bNew; }
+ inline sal_Bool IsFntChg() const { return bFntChg; }
+ inline void SetEndHyph( const sal_Bool bNew ) { bEndHyph = bNew; }
+ inline sal_Bool IsEndHyph() const { return bEndHyph; }
+ inline void SetMidHyph( const sal_Bool bNew ) { bMidHyph = bNew; }
+ inline sal_Bool IsMidHyph() const { return bMidHyph; }
+ inline void SetTab( const sal_Bool bNew ) { bTab = bNew; }
+ inline sal_Bool IsTab() const { return bTab; }
+ inline void SetFly( const sal_Bool bNew ) { bFly = bNew; }
+ inline sal_Bool IsFly() const { return bFly; }
+ inline void SetRest( const sal_Bool bNew ) { bRest = bNew; }
+ inline sal_Bool IsRest() const { return bRest; }
+ inline void SetBlinking( const sal_Bool bNew = sal_True ) { bBlinking = bNew; }
+ inline sal_Bool IsBlinking() const { return bBlinking; }
+ inline void SetCntnt( const sal_Bool bNew = sal_True ) { bContent = bNew; }
+ inline sal_Bool HasCntnt() const { return bContent; }
+ inline void SetRedline( const sal_Bool bNew = sal_True ) { bRedline = bNew; }
+ inline sal_Bool HasRedline() const { return bRedline; }
+ inline void SetForcedLeftMargin( const sal_Bool bNew = sal_True ) { bForcedLeftMargin = bNew; }
+ inline sal_Bool HasForcedLeftMargin() const { return bForcedLeftMargin; }
+ inline void SetHanging( const sal_Bool bNew = sal_True ) { bHanging = bNew; }
+ inline sal_Bool IsHanging() const { return bHanging; }
+ inline void SetUnderscore( const sal_Bool bNew = sal_True ) { bUnderscore = bNew; }
+ inline sal_Bool HasUnderscore() const { return bUnderscore; }
+
+ // Beruecksichtigung von Dummyleerzeilen
+ // 4147, 8221:
+ inline void SetDummy( const sal_Bool bNew ) { bDummy = bNew; }
+ inline sal_Bool IsDummy() const { return bDummy; }
+
+ inline void SetClipping( const sal_Bool bNew ) { bClipping = bNew; }
+ inline sal_Bool IsClipping() const { return bClipping; }
+
+ inline SwLineLayout();
+ virtual ~SwLineLayout();
+
+ inline SwLineLayout *GetNext() { return pNext; }
+ inline const SwLineLayout *GetNext() const { return pNext; }
+ inline void SetNext( SwLineLayout *pNew ) { pNext = pNew; }
+
+ void Init( SwLinePortion *pNextPortion = NULL);
+
+ // Sammelt die Daten fuer die Zeile.
+ void CalcLine( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf );
+
+ inline void SetRealHeight( KSHORT nNew ) { nRealHeight = nNew; }
+ inline KSHORT GetRealHeight() const { return nRealHeight; }
+
+ // Erstellt bei kurzen Zeilen die Glue-Kette.
+ SwMarginPortion *CalcLeftMargin();
+
+ inline SwTwips GetHangingMargin() const
+ { return _GetHangingMargin(); }
+
+ // fuer die Sonderbehandlung bei leeren Zeilen
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+
+ //
+ // STUFF FOR JUSTIFIED ALIGNMENT
+ //
+ inline sal_Bool IsSpaceAdd() { return pLLSpaceAdd != NULL; }
+ void InitSpaceAdd(); // Creates pLLSpaceAdd if necessary
+ void CreateSpaceAdd( const long nInit = 0 );
+ inline void FinishSpaceAdd() { delete pLLSpaceAdd; pLLSpaceAdd = NULL; }
+ inline USHORT GetLLSpaceAddCount() const { return sal::static_int_cast< USHORT >(pLLSpaceAdd->size()); }
+ inline void SetLLSpaceAdd( long nNew, USHORT nIdx )
+ {
+ if ( nIdx == GetLLSpaceAddCount() )
+ pLLSpaceAdd->push_back( nNew );
+ else
+ (*pLLSpaceAdd)[ nIdx ] = nNew;
+ }
+ inline long GetLLSpaceAdd( USHORT nIdx ) { return (*pLLSpaceAdd)[ nIdx ]; }
+ inline void RemoveFirstLLSpaceAdd() { pLLSpaceAdd->erase( pLLSpaceAdd->begin() ); }
+ inline std::vector<long>* GetpLLSpaceAdd() const { return pLLSpaceAdd; }
+
+ //
+ // STUFF FOR KANA COMPRESSION
+ //
+ inline void SetKanaComp( SvUShorts* pNew ){ pKanaComp = pNew; }
+ inline void FinishKanaComp() { delete pKanaComp; pKanaComp = NULL; }
+ inline SvUShorts* GetpKanaComp() const { return pKanaComp; }
+ inline SvUShorts& GetKanaComp() { return *pKanaComp; }
+
+ /** determine ascent and descent for positioning of as-character anchored
+ object
+
+ OD 07.01.2004 #i11859# - previously local method <lcl_MaxAscDescent>
+ Method calculates maximum ascents and descents of the line layout.
+ One value considering as-character anchored objects, one without these
+ objects.
+ Portions for other anchored objects aren't considered.
+ OD 2005-05-20 #i47162# - add optional parameter <_bNoFlyCntPorAndLinePor>
+ to control, if the fly content portions and line portion are considered.
+
+ @param _orAscent
+ output parameter - maximum ascent without as-character anchored objects
+
+ @param _orDescent
+ output parameter - maximum descent without as-character anchored objects
+
+ @param _orObjAscent
+ output parameter - maximum ascent with as-character anchored objects
+
+ @param _orObjDescent
+ output parameter - maximum descent with as-character anchored objects
+
+ @param _pDontConsiderPortion
+ input parameter - portion, which isn't considered for calculating
+ <_orObjAscent> and <_orObjDescent>, if it isn't a portion for a
+ as-character anchored object or it isn't as high as the line.
+
+ @param _bNoFlyCntPorAndLinePor
+ optional input parameter - boolean, indicating that fly content portions
+ and the line portion are considered or not.
+
+ @author OD
+ */
+ void MaxAscentDescent( SwTwips& _orAscent,
+ SwTwips& _orDescent,
+ SwTwips& _orObjAscent,
+ SwTwips& _orObjDescent,
+ const SwLinePortion* _pDontConsiderPortion = NULL,
+ const bool _bNoFlyCntPorAndLinePor = false ) const;
+
+#ifdef DBG_UTIL
+ void DebugPortions( SvStream &rOs, const XubString &rTxt,
+ const xub_StrLen nStart ); //$ ostream
+#endif
+
+ OUTPUT_OPERATOR
+ DECL_FIXEDMEMPOOL_NEWDEL(SwLineLayout)
+};
+
+class SwParaPortion : public SwLineLayout
+{
+ // neu zu paintender Bereich
+ SwRepaint aRepaint;
+ // neu zu formatierender Bereich
+ SwCharRange aReformat;
+ SwScriptInfo aScriptInfo;
+// Fraction aZoom;
+ long nDelta;
+
+ // Wenn ein SwTxtFrm gelocked ist, werden keine Veraenderungen an den
+ // Formatierungsdaten (unter pLine) vorgenommen (vgl. ORPHANS)
+ sal_Bool bFlys : 1; // Ueberlappen Flys ?
+ sal_Bool bPrep : 1; // PREP_*
+ sal_Bool bPrepWidows : 1; // PREP_WIDOWS
+ sal_Bool bPrepAdjust : 1; // PREP_ADJUST_FRM
+ sal_Bool bPrepMustFit : 1; // PREP_MUST_FIT
+ sal_Bool bFollowField : 1; // Es steht noch ein Feldrest fuer den Follow an.
+
+ sal_Bool bFixLineHeight : 1; // Feste Zeilenhoehe
+ sal_Bool bFtnNum : 1; // contents a footnotenumberportion
+ sal_Bool bMargin : 1; // contents a hanging punctuation in the margin
+
+ sal_Bool bFlag00 : 1; //
+ sal_Bool bFlag11 : 1; //
+ sal_Bool bFlag12 : 1; //
+ sal_Bool bFlag13 : 1; //
+ sal_Bool bFlag14 : 1; //
+ sal_Bool bFlag15 : 1; //
+ sal_Bool bFlag16 : 1; //
+
+public:
+ SwParaPortion();
+ virtual ~SwParaPortion();
+
+ // setzt alle Formatinformationen zurueck (ausser bFlys wg. 9916)
+ inline void FormatReset();
+
+ // Setzt die Flags zurueck
+ inline void ResetPreps();
+
+ // Get/Set-Methoden
+ inline SwRepaint *GetRepaint() { return &aRepaint; }
+ inline const SwRepaint *GetRepaint() const { return &aRepaint; }
+ inline SwCharRange *GetReformat() { return &aReformat; }
+ inline const SwCharRange *GetReformat() const { return &aReformat; }
+ inline long *GetDelta() { return &nDelta; }
+ inline const long *GetDelta() const { return &nDelta; }
+ inline SwScriptInfo& GetScriptInfo() { return aScriptInfo; }
+ inline const SwScriptInfo& GetScriptInfo() const { return aScriptInfo; }
+
+ // fuer SwTxtFrm::Format: liefert die aktuelle Laenge des Absatzes
+ xub_StrLen GetParLen() const;
+
+ // fuer Prepare()
+ sal_Bool UpdateQuoVadis( const XubString &rQuo );
+
+ // Flags
+ inline void SetFly( const sal_Bool bNew = sal_True ) { bFlys = bNew; }
+ inline sal_Bool HasFly() const { return bFlys; }
+
+ // Preps
+ inline void SetPrep( const sal_Bool bNew = sal_True ) { bPrep = bNew; }
+ inline sal_Bool IsPrep() const { return bPrep; }
+ inline void SetPrepWidows( const sal_Bool bNew = sal_True ) { bPrepWidows = bNew; }
+ inline sal_Bool IsPrepWidows() const { return bPrepWidows; }
+ inline void SetPrepMustFit( const sal_Bool bNew = sal_True ) { bPrepMustFit = bNew; }
+ inline sal_Bool IsPrepMustFit() const { return bPrepMustFit; }
+ inline void SetPrepAdjust( const sal_Bool bNew = sal_True ) { bPrepAdjust = bNew; }
+ inline sal_Bool IsPrepAdjust() const { return bPrepAdjust; }
+ inline void SetFollowField( const sal_Bool bNew = sal_True ) { bFollowField = bNew; }
+ inline sal_Bool IsFollowField() const { return bFollowField; }
+ inline void SetFixLineHeight( const sal_Bool bNew = sal_True ) { bFixLineHeight = bNew; }
+ inline sal_Bool IsFixLineHeight() const { return bFixLineHeight; }
+
+ inline void SetFtnNum( const sal_Bool bNew = sal_True ) { bFtnNum = bNew; }
+ inline sal_Bool IsFtnNum() const { return bFtnNum; }
+ inline void SetMargin( const sal_Bool bNew = sal_True ) { bMargin = bNew; }
+ inline sal_Bool IsMargin() const { return bMargin; }
+ inline void SetFlag00( const sal_Bool bNew = sal_True ) { bFlag00 = bNew; }
+ inline sal_Bool IsFlag00() const { return bFlag00; }
+ inline void SetFlag11( const sal_Bool bNew = sal_True ) { bFlag11 = bNew; }
+ inline sal_Bool IsFlag11() const { return bFlag11; }
+ inline void SetFlag12( const sal_Bool bNew = sal_True ) { bFlag12 = bNew; }
+ inline sal_Bool IsFlag12() const { return bFlag12; }
+ inline void SetFlag13( const sal_Bool bNew = sal_True ) { bFlag13 = bNew; }
+ inline sal_Bool IsFlag13() const { return bFlag13; }
+ inline void SetFlag14( const sal_Bool bNew = sal_True ) { bFlag14 = bNew; }
+ inline sal_Bool IsFlag14() const { return bFlag14; }
+ inline void SetFlag15( const sal_Bool bNew = sal_True ) { bFlag15 = bNew; }
+ inline sal_Bool IsFlag15() const { return bFlag15; }
+ inline void SetFlag16( const sal_Bool bNew = sal_True ) { bFlag16 = bNew; }
+ inline sal_Bool IsFlag16() const { return bFlag16; }
+
+ // schneller, hoeher, weiter: Read/Write-Methoden fuer den SWG-Filter
+ SvStream &ReadSwg ( SvStream& rStream ); //$ istream
+ SvStream &WriteSwg( SvStream& rStream ); //$ ostream
+
+ // nErgo in der QuoVadisPortion setzen
+ void SetErgoSumNum( const XubString &rErgo );
+
+ const SwDropPortion *FindDropPortion() const;
+
+ OUTPUT_OPERATOR
+ DECL_FIXEDMEMPOOL_NEWDEL(SwParaPortion)
+};
+
+/*************************************************************************
+ * Inline-Implementierungen
+ *************************************************************************/
+
+inline void SwLineLayout::ResetFlags()
+{
+ bFormatAdj = bDummy = bFntChg = bTab = bEndHyph = bMidHyph = bFly
+ = bRest = bBlinking = bClipping = bContent = bRedline
+ = bForcedLeftMargin = bHanging = sal_False;
+}
+
+inline SwLineLayout::SwLineLayout()
+ : pNext( 0 ), pLLSpaceAdd( 0 ), pKanaComp( 0 ), nRealHeight( 0 ),
+ bUnderscore( sal_False )
+{
+ ResetFlags();
+ SetWhichPor( POR_LAY );
+}
+
+inline void SwParaPortion::ResetPreps()
+{
+ bPrep = bPrepWidows = bPrepAdjust = bPrepMustFit = sal_False;
+}
+
+inline void SwParaPortion::FormatReset()
+{
+ nDelta = 0;
+ aReformat = SwCharRange( 0, STRING_LEN );
+// AMA 9916: bFlys muss in SwTxtFrm::_Format() erhalten bleiben, damit
+// leere Absaetze, die Rahmen ohne Umfluss ausweichen mussten, sich
+// neu formatieren, wenn der Rahmen aus dem Bereich verschwindet.
+// bFlys = sal_False;
+ ResetPreps();
+ bFollowField = bFixLineHeight = bMargin = sal_False;
+}
+
+#ifdef UNX
+// C30 ist mit dem ternaeren Ausdruck ueberfordert.
+inline SwLinePortion *SwLineLayout::GetFirstPortion() const
+{
+ SwLinePortion *pTmp = pPortion;
+ if ( !pPortion )
+ pTmp = (SwLinePortion*)this;
+ return( pTmp );
+}
+#else
+inline SwLinePortion *SwLineLayout::GetFirstPortion() const
+{ return( pPortion ? pPortion : (SwLinePortion*)this ); }
+#endif
+
+CLASSIO( SwLineLayout )
+CLASSIO( SwParaPortion )
+
+#endif
diff --git a/sw/source/core/text/porlin.cxx b/sw/source/core/text/porlin.cxx
new file mode 100644
index 000000000000..862b5ce13024
--- /dev/null
+++ b/sw/source/core/text/porlin.cxx
@@ -0,0 +1,426 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+#ifndef _OUTDEV_HXX //autogen
+#include <vcl/outdev.hxx>
+#endif
+#include <SwPortionHandler.hxx>
+
+#include "errhdl.hxx" // ASSERT
+
+#include "txtcfg.hxx"
+#include "porlin.hxx"
+#include "inftxt.hxx"
+#include "portxt.hxx"
+#include "pormulti.hxx"
+#include "porglue.hxx"
+#include "inftxt.hxx"
+#include "blink.hxx"
+#ifdef DBG_UTIL
+
+sal_Bool ChkChain( SwLinePortion *pStart )
+{
+ SwLinePortion *pPor = pStart->GetPortion();
+ MSHORT nCount = 0;
+ while( pPor )
+ {
+ ++nCount;
+ ASSERT( nCount < 200 && pPor != pStart,
+ "ChkChain(): lost in chains" );
+ if( nCount >= 200 || pPor == pStart )
+ {
+ // der Lebensretter
+ pPor = pStart->GetPortion();
+ pStart->SetPortion(0);
+ pPor->Truncate();
+ pStart->SetPortion( pPor );
+ return sal_False;
+ }
+ pPor = pPor->GetPortion();
+ }
+ return sal_True;
+}
+#endif
+
+#if OSL_DEBUG_LEVEL > 1
+const sal_Char *GetPortionName( const MSHORT nType );
+#endif
+
+SwLinePortion::~SwLinePortion()
+{
+ if( pBlink )
+ pBlink->Delete( this );
+}
+
+SwLinePortion *SwLinePortion::Compress()
+{
+ return GetLen() || Width() ? this : 0;
+}
+
+KSHORT SwLinePortion::GetViewWidth( const SwTxtSizeInfo & ) const
+{
+ return 0;
+}
+
+/*************************************************************************
+ * SwLinePortion::SwLinePortion( )
+ *************************************************************************/
+
+SwLinePortion::SwLinePortion( ) :
+ pPortion( NULL ),
+ nLineLength( 0 ),
+ nAscent( 0 )
+{
+}
+
+/*************************************************************************
+ * SwLinePortion::PrePaint()
+ *************************************************************************/
+
+void SwLinePortion::PrePaint( const SwTxtPaintInfo& rInf,
+ const SwLinePortion* pLast ) const
+{
+ ASSERT( rInf.OnWin(), "SwLinePortion::PrePaint: don't prepaint on a printer");
+ ASSERT( !Width(), "SwLinePortion::PrePaint: For Width()==0 only!");
+
+ const KSHORT nViewWidth = GetViewWidth( rInf );
+
+ if( ! nViewWidth )
+ return;
+
+ const KSHORT nHalfView = nViewWidth / 2;
+ USHORT nLastWidth = pLast->Width();
+
+ if ( pLast->InSpaceGrp() && rInf.GetSpaceAdd() )
+ nLastWidth = nLastWidth + (USHORT)pLast->CalcSpacing( rInf.GetSpaceAdd(), rInf );
+
+ KSHORT nPos;
+ SwTxtPaintInfo aInf( rInf );
+
+ const BOOL bBidiPor = ( rInf.GetTxtFrm()->IsRightToLeft() ) !=
+ ( 0 != ( TEXT_LAYOUT_BIDI_RTL & rInf.GetOut()->GetLayoutMode() ) );
+
+ USHORT nDir = bBidiPor ?
+ 1800 :
+ rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
+
+ switch ( nDir )
+ {
+ case 0 :
+ nPos = KSHORT( rInf.X() );
+ if( nLastWidth > nHalfView )
+ nPos += nLastWidth - nHalfView;
+ aInf.X( nPos );
+ break;
+ case 900 :
+ nPos = KSHORT( rInf.Y() );
+ if( nLastWidth > nHalfView )
+ nPos -= nLastWidth + nHalfView;
+ aInf.Y( nPos );
+ break;
+ case 1800 :
+ nPos = KSHORT( rInf.X() );
+ if( nLastWidth > nHalfView )
+ nPos -= nLastWidth + nHalfView;
+ aInf.X( nPos );
+ break;
+ case 2700 :
+ nPos = KSHORT( rInf.Y() );
+ if( nLastWidth > nHalfView )
+ nPos += nLastWidth - nHalfView;
+ aInf.Y( nPos );
+ break;
+ }
+
+ SwLinePortion *pThis = (SwLinePortion*)this;
+ pThis->Width( nViewWidth );
+ Paint( aInf );
+ pThis->Width(0);
+}
+
+/*************************************************************************
+ * SwLinePortion::CalcTxtSize()
+ *************************************************************************/
+
+void SwLinePortion::CalcTxtSize( const SwTxtSizeInfo &rInf )
+{
+ if( GetLen() == rInf.GetLen() )
+ *((SwPosSize*)this) = GetTxtSize( rInf );
+ else
+ {
+ SwTxtSizeInfo aInf( rInf );
+ aInf.SetLen( GetLen() );
+ *((SwPosSize*)this) = GetTxtSize( aInf );
+ }
+}
+
+/*************************************************************************
+ * SwLinePortion::Truncate()
+ *
+ * Es werden alle nachfolgenden Portions geloescht.
+ *************************************************************************/
+
+void SwLinePortion::_Truncate()
+{
+ SwLinePortion *pPos = pPortion;
+ do
+ { ASSERT( pPos != this, "SwLinePortion::Truncate: loop" );
+ SwLinePortion *pLast = pPos;
+ pPos = pPos->GetPortion();
+ pLast->SetPortion( 0 );
+ delete pLast;
+
+ } while( pPos );
+
+ pPortion = 0;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::Insert()
+ *
+ * Es wird immer hinter uns eingefuegt.
+ *************************************************************************/
+
+SwLinePortion *SwLinePortion::Insert( SwLinePortion *pIns )
+{
+ pIns->FindLastPortion()->SetPortion( pPortion );
+ SetPortion( pIns );
+#ifdef DBG_UTIL
+ ChkChain( this );
+#endif
+ return pIns;
+}
+
+/*************************************************************************
+ * SwLinePortion::FindLastPortion()
+ *************************************************************************/
+
+SwLinePortion *SwLinePortion::FindLastPortion()
+{
+ SwLinePortion *pPos = this;
+ // An das Ende wandern und pLinPortion an den letzten haengen ...
+ while( pPos->GetPortion() )
+ {
+ DBG_LOOP;
+ pPos = pPos->GetPortion();
+ }
+ return pPos;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::Append()
+ *************************************************************************/
+
+SwLinePortion *SwLinePortion::Append( SwLinePortion *pIns )
+{
+ SwLinePortion *pPos = FindLastPortion();
+ pPos->SetPortion( pIns );
+ pIns->SetPortion( 0 );
+#ifdef DBG_UTIL
+ ChkChain( this );
+#endif
+ return pIns;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::Cut()
+ *************************************************************************/
+
+SwLinePortion *SwLinePortion::Cut( SwLinePortion *pVictim )
+{
+ SwLinePortion *pPrev = pVictim->FindPrevPortion( this );
+ ASSERT( pPrev, "SwLinePortion::Cut(): can't cut" );
+ pPrev->SetPortion( pVictim->GetPortion() );
+ pVictim->SetPortion(0);
+ return pVictim;
+}
+
+/*************************************************************************
+ * SwLinePortion::FindPrevPortion()
+ *************************************************************************/
+
+SwLinePortion *SwLinePortion::FindPrevPortion( const SwLinePortion *pRoot )
+{
+ ASSERT( pRoot != this, "SwLinePortion::FindPrevPortion(): invalid root" );
+ SwLinePortion *pPos = (SwLinePortion*)pRoot;
+ while( pPos->GetPortion() && pPos->GetPortion() != this )
+ {
+ DBG_LOOP;
+ pPos = pPos->GetPortion();
+ }
+ ASSERT( pPos->GetPortion(),
+ "SwLinePortion::FindPrevPortion: blowing in the wind");
+ return pPos;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::GetCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwLinePortion::GetCrsrOfst( const KSHORT nOfst ) const
+{
+ if( nOfst > ( PrtWidth() / 2 ) )
+ return GetLen();
+ else
+ return 0;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwLinePortion::GetTxtSize( const SwTxtSizeInfo & ) const
+{
+ ASSERT( !this, "SwLinePortion::GetTxtSize: don't ask me about sizes, "
+ "I'm only a stupid SwLinePortion" );
+ return SwPosSize();
+}
+
+#ifdef DBG_UTIL
+
+/*************************************************************************
+ * virtual SwLinePortion::Check()
+ *************************************************************************/
+
+sal_Bool SwLinePortion::Check( SvStream &, SwTxtSizeInfo & ) //$ ostream
+{
+ return sal_True;
+}
+#endif
+
+/*************************************************************************
+ * virtual SwLinePortion::Format()
+ *************************************************************************/
+
+sal_Bool SwLinePortion::Format( SwTxtFormatInfo &rInf )
+{
+ if( rInf.X() > rInf.Width() )
+ {
+ Truncate();
+ rInf.SetUnderFlow( this );
+ return sal_True;
+ }
+
+ const SwLinePortion *pLast = rInf.GetLast();
+ Height( pLast->Height() );
+ SetAscent( pLast->GetAscent() );
+ const KSHORT nNewWidth = static_cast<USHORT>(rInf.X() + PrtWidth());
+ // Nur Portions mit echter Breite koennen ein sal_True zurueckliefern
+ // Notizen beispielsweise setzen niemals bFull==sal_True
+ if( rInf.Width() <= nNewWidth && PrtWidth() && ! IsKernPortion() )
+ {
+ Truncate();
+ if( nNewWidth > rInf.Width() )
+ PrtWidth( nNewWidth - rInf.Width() );
+ rInf.GetLast()->FormatEOL( rInf );
+ return sal_True;
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::FormatEOL()
+ *************************************************************************/
+
+// Format end of line
+
+void SwLinePortion::FormatEOL( SwTxtFormatInfo & )
+{ }
+
+/*************************************************************************
+ * SwLinePortion::Move()
+ *************************************************************************/
+
+void SwLinePortion::Move( SwTxtPaintInfo &rInf )
+{
+ BOOL bB2T = rInf.GetDirection() == DIR_BOTTOM2TOP;
+ const BOOL bFrmDir = rInf.GetTxtFrm()->IsRightToLeft();
+ BOOL bCounterDir = ( ! bFrmDir && DIR_RIGHT2LEFT == rInf.GetDirection() ) ||
+ ( bFrmDir && DIR_LEFT2RIGHT == rInf.GetDirection() );
+
+ if ( InSpaceGrp() && rInf.GetSpaceAdd() )
+ {
+ SwTwips nTmp = PrtWidth() + CalcSpacing( rInf.GetSpaceAdd(), rInf );
+ if( rInf.IsRotated() )
+ rInf.Y( rInf.Y() + ( bB2T ? -nTmp : nTmp ) );
+ else if ( bCounterDir )
+ rInf.X( rInf.X() - nTmp );
+ else
+ rInf.X( rInf.X() + nTmp );
+ }
+ else
+ {
+ if( InFixMargGrp() && !IsMarginPortion() )
+ {
+ rInf.IncSpaceIdx();
+ rInf.IncKanaIdx();
+ }
+ if( rInf.IsRotated() )
+ rInf.Y( rInf.Y() + ( bB2T ? -PrtWidth() : PrtWidth() ) );
+ else if ( bCounterDir )
+ rInf.X( rInf.X() - PrtWidth() );
+ else
+ rInf.X( rInf.X() + PrtWidth() );
+ }
+ if( IsMultiPortion() && ((SwMultiPortion*)this)->HasTabulator() )
+ rInf.IncSpaceIdx();
+
+ rInf.SetIdx( rInf.GetIdx() + GetLen() );
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::CalcSpacing()
+ *************************************************************************/
+
+long SwLinePortion::CalcSpacing( long , const SwTxtSizeInfo & ) const
+{
+ return 0;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwLinePortion::GetExpTxt( const SwTxtSizeInfo &, XubString & ) const
+{
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwLinePortion::HandlePortion()
+ *************************************************************************/
+
+void SwLinePortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString;
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
diff --git a/sw/source/core/text/porlin.hxx b/sw/source/core/text/porlin.hxx
new file mode 100644
index 000000000000..8301d397659e
--- /dev/null
+++ b/sw/source/core/text/porlin.hxx
@@ -0,0 +1,251 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORLIN_HXX
+#define _PORLIN_HXX
+
+#include "possiz.hxx" // SwPosSize
+
+class XubString;
+class SwTxtSizeInfo;
+class SwTxtPaintInfo;
+class SwTxtFormatInfo;
+class SwPortionHandler;
+
+// Die Ausgabeoperatoren der Portions sind virtuelle Methoden der Portion.
+// Das CLASSIO-Makro implementiert die 'freischwebende' Funktion.
+// Auf diese Weise erhaelt man beide Vorteile: virtuelle Ausgabeoperatoren
+// und allgemeine Verwendbarkeit.
+#ifdef DBG_UTIL
+#define OUTPUT_OPERATOR virtual SvStream &operator<<( SvStream & aOs ) const;
+#else
+#define OUTPUT_OPERATOR
+#endif
+
+// Portiongruppen
+#define PORGRP_TXT 0x8000
+#define PORGRP_EXP 0x4000
+#define PORGRP_FLD 0x2000
+#define PORGRP_HYPH 0x1000
+#define PORGRP_NUMBER 0x0800
+#define PORGRP_GLUE 0x0400
+#define PORGRP_FIX 0x0200
+#define PORGRP_TAB 0x0100
+#define PORGRP_NOTRECY 0x0080
+// kleine Spezialgruppen
+#define PORGRP_FIXMARG 0x0040
+//#define PORGRP_? 0x0020
+#define PORGRP_TABNOTLFT 0x0010
+#define PORGRP_TOXREF 0x0008
+
+/*************************************************************************
+ * class SwLinePortion
+ *************************************************************************/
+
+class SwLinePortion: public SwPosSize
+{
+protected:
+ // Hier gibt es Bereiche mit unterschiedlichen Attributen.
+ SwLinePortion *pPortion;
+ // Anzahl der Zeichen und Spaces auf der Zeile
+ xub_StrLen nLineLength;
+ KSHORT nAscent; // Maximaler Ascender
+
+ SwLinePortion();
+private:
+ MSHORT nWhichPor; // Who's who?
+
+ void _Truncate();
+
+public:
+ inline SwLinePortion(const SwLinePortion &rPortion);
+ virtual ~SwLinePortion();
+
+ // Zugriffsmethoden
+ inline SwLinePortion *GetPortion() const { return( pPortion ); }
+ inline SwLinePortion &operator=(const SwLinePortion &rPortion);
+ inline sal_Bool operator==( const SwLinePortion &rPortion ) const;
+ inline xub_StrLen GetLen() const { return nLineLength; }
+ inline void SetLen( const xub_StrLen nLen ) { nLineLength = nLen; }
+ inline void SetPortion( SwLinePortion *pNew ){ pPortion = pNew; }
+ inline KSHORT &GetAscent() { return nAscent; }
+ inline KSHORT GetAscent() const { return nAscent; }
+ inline void SetAscent( const KSHORT nNewAsc ) { nAscent = nNewAsc; }
+ inline void PrtWidth( KSHORT nNewWidth ) { Width( nNewWidth ); }
+ inline KSHORT PrtWidth() const { return Width(); }
+ inline void AddPrtWidth( const KSHORT nNew ) { Width( Width() + nNew ); }
+ inline void SubPrtWidth( const KSHORT nNew ) { Width( Width() - nNew ); }
+
+ inline const SwPosSize &PrtSize() const { return *this; }
+
+ // Einfuegeoperationen:
+ virtual SwLinePortion *Insert( SwLinePortion *pPortion );
+ virtual SwLinePortion *Append( SwLinePortion *pPortion );
+ SwLinePortion *Cut( SwLinePortion *pVictim );
+ inline void Truncate();
+
+ // liefert 0 zurueck, wenn keine Nutzdaten enthalten sind.
+ virtual SwLinePortion *Compress();
+
+ inline void SetWhichPor( const MSHORT nNew ) { nWhichPor = nNew; }
+ inline MSHORT GetWhichPor( ) const { return nWhichPor; }
+
+// Gruppenabfragen:
+ inline sal_Bool InTxtGrp( ) const { return nWhichPor & PORGRP_TXT ? sal_True : sal_False; }
+ inline sal_Bool InGlueGrp( ) const { return nWhichPor & PORGRP_GLUE ? sal_True : sal_False;}
+ inline sal_Bool InTabGrp( ) const { return nWhichPor & PORGRP_TAB ? sal_True : sal_False; }
+ inline sal_Bool InHyphGrp( ) const { return nWhichPor & PORGRP_HYPH ? sal_True : sal_False;}
+ inline sal_Bool InNumberGrp( )const { return nWhichPor & PORGRP_NUMBER ? sal_True : sal_False;}
+ inline sal_Bool InFixGrp( ) const { return nWhichPor & PORGRP_FIX ? sal_True : sal_False; }
+ inline sal_Bool InFldGrp( ) const { return nWhichPor & PORGRP_FLD ? sal_True : sal_False; }
+ inline sal_Bool InToxRefGrp( ) const { return nWhichPor & PORGRP_TOXREF ? sal_True : sal_False; }
+ inline sal_Bool InToxRefOrFldGrp( ) const { return nWhichPor &
+ ( PORGRP_FLD | PORGRP_TOXREF ) ? sal_True : sal_False; }
+ inline sal_Bool InExpGrp( ) const { return nWhichPor & PORGRP_EXP ? sal_True : sal_False; }
+ inline sal_Bool InTabnLftGrp( ) const
+ { return nWhichPor & PORGRP_TABNOTLFT ? sal_True : sal_False; }
+ inline sal_Bool InFixMargGrp( )const
+ { return nWhichPor & PORGRP_FIXMARG ? sal_True : sal_False; }
+ inline sal_Bool InSpaceGrp( )const
+ { return InTxtGrp() || IsMultiPortion(); }
+// Individuelle Abfragen:
+ inline sal_Bool IsGrfNumPortion( )const{ return nWhichPor == POR_GRFNUM; }
+ inline sal_Bool IsFlyCntPortion( )const{ return nWhichPor == POR_FLYCNT; }
+ inline sal_Bool IsBlankPortion( ) const{ return nWhichPor == POR_BLANK; }
+ inline sal_Bool IsBreakPortion( ) const{ return nWhichPor == POR_BRK; }
+ inline sal_Bool IsErgoSumPortion()const{ return nWhichPor == POR_ERGOSUM;}
+ inline sal_Bool IsQuoVadisPortion()const{ return nWhichPor==POR_QUOVADIS;}
+ inline sal_Bool IsTabCntPortion( )const{ return nWhichPor==POR_TABCENTER;}
+ inline sal_Bool IsTabDecimalPortion() const { return nWhichPor == POR_TABDECIMAL;}
+ inline sal_Bool IsTabLeftPortion()const{ return nWhichPor == POR_TABLEFT;}
+ inline sal_Bool IsFtnNumPortion( )const{ return nWhichPor == POR_FTNNUM; }
+ inline sal_Bool IsFtnPortion( ) const{ return nWhichPor == POR_FTN; }
+ inline sal_Bool IsTmpEndPortion( )const{ return nWhichPor == POR_TMPEND; }
+ inline sal_Bool IsDropPortion( ) const{ return nWhichPor == POR_DROP; }
+ inline sal_Bool IsLayPortion( ) const{ return nWhichPor == POR_LAY; }
+ inline sal_Bool IsParaPortion( ) const{ return nWhichPor == POR_PARA; }
+ inline sal_Bool IsMarginPortion( )const{ return nWhichPor == POR_MARGIN; }
+ inline sal_Bool IsFlyPortion( ) const{ return nWhichPor == POR_FLY; }
+ inline sal_Bool IsHolePortion( ) const{ return nWhichPor == POR_HOLE; }
+ inline sal_Bool IsSoftHyphPortion()const{ return nWhichPor==POR_SOFTHYPH;}
+ inline sal_Bool IsPostItsPortion()const{ return nWhichPor == POR_POSTITS;}
+ inline sal_Bool IsCombinedPortion()const{ return nWhichPor==POR_COMBINED;}
+ inline sal_Bool IsTextPortion( ) const{ return nWhichPor == POR_TXT; }
+ inline sal_Bool IsURLPortion( ) const{ return nWhichPor == POR_URL; }
+ inline sal_Bool IsHangingPortion( ) const{ return nWhichPor == POR_HNG; }
+ inline sal_Bool IsKernPortion( ) const{ return nWhichPor == POR_KERN; }
+ inline sal_Bool IsArrowPortion( ) const{ return nWhichPor == POR_ARROW; }
+ inline sal_Bool IsMultiPortion( ) const{ return nWhichPor == POR_MULTI; }
+ inline sal_Bool IsNumberPortion( ) const{ return nWhichPor == POR_NUMBER; } // #i23726#
+ inline sal_Bool IsControlCharPortion() const { return nWhichPor == POR_CONTROLCHAR; }
+
+ // Positionierung
+ SwLinePortion *FindPrevPortion( const SwLinePortion *pRoot );
+ SwLinePortion *FindLastPortion();
+
+ virtual xub_StrLen GetCrsrOfst( const KSHORT nOfst ) const;
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+ void CalcTxtSize( const SwTxtSizeInfo &rInfo );
+
+ // Ausgabe
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const = 0;
+ void PrePaint( const SwTxtPaintInfo &rInf, const SwLinePortion *pLast ) const;
+
+#ifdef DBG_UTIL
+ virtual sal_Bool Check( SvStream &rOs, SwTxtSizeInfo &rInfo ); //$ ostream
+#endif
+
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ // wird fuer die letzte Portion der Zeile extra gerufen
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+ void Move( SwTxtPaintInfo &rInf );
+
+ // Fuer SwTxtSlot
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+
+ // fuer SwFldPortion, SwSoftHyphPortion
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+
+ // for text- and multi-portions
+ virtual long CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+
+/*************************************************************************
+ * inline - Implementations
+ *************************************************************************/
+
+inline SwLinePortion &SwLinePortion::operator=(const SwLinePortion &rPortion)
+{
+ *(SwPosSize*)this = rPortion;
+ nLineLength = rPortion.nLineLength;
+ nAscent = rPortion.nAscent;
+ nWhichPor = rPortion.nWhichPor;
+ return *this;
+}
+
+inline sal_Bool SwLinePortion::operator==(const SwLinePortion &rPortion ) const
+{
+ return( Height() == rPortion.Height() &&
+ Width() == rPortion.Width() &&
+ nLineLength == rPortion.GetLen() &&
+ nAscent == rPortion.GetAscent() );
+}
+
+inline SwLinePortion::SwLinePortion(const SwLinePortion &rPortion) :
+ SwPosSize( rPortion ),
+ pPortion( 0 ),
+ nLineLength( rPortion.nLineLength ),
+ nAscent( rPortion.nAscent ),
+ nWhichPor( rPortion.nWhichPor )
+{
+}
+
+inline void SwLinePortion::Truncate()
+{
+ if ( pPortion )
+ _Truncate();
+}
+
+
+//$ ostream
+#ifdef DBGTXT
+#define CLASSIO( class ) \
+ inline SvStream &operator<<( SvStream &rOs, const class &rClass ) {\
+ return rClass.operator<<( rOs );\
+ }
+#else
+#define CLASSIO( class )
+#endif
+
+CLASSIO( SwLinePortion )
+
+#endif
diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
new file mode 100644
index 000000000000..f9f86db667b9
--- /dev/null
+++ b/sw/source/core/text/pormulti.cxx
@@ -0,0 +1,2415 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+
+#include <com/sun/star/i18n/ScriptType.hdl>
+#include <editeng/twolinesitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <vcl/outdev.hxx>
+#include <fmtfld.hxx>
+#include <fldbas.hxx> // SwField
+#include <txatbase.hxx>
+#include <fmtruby.hxx> // SwFmtRuby
+#include <txtatr.hxx> // SwTxtRuby
+#include <charfmt.hxx>
+#include <txtinet.hxx>
+#include <fchrfmt.hxx>
+#include <layfrm.hxx> // GetUpper()
+#include <SwPortionHandler.hxx>
+#include <pormulti.hxx> // SwMultiPortion
+#include <inftxt.hxx> // SwTxtSizeInfo
+#include <itrpaint.hxx> // SwTxtPainter
+#include <viewopt.hxx> // SwViewOptions
+#include <itrform2.hxx> // SwTxtFormatter
+#include <porfld.hxx> // SwFldPortion
+#include <porglue.hxx>
+#include <breakit.hxx>
+#include <pagefrm.hxx>
+#include <rowfrm.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <swtable.hxx>
+#include <fmtfsize.hxx>
+
+using namespace ::com::sun::star;
+extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
+
+/*-----------------10.10.00 15:23-------------------
+ * class SwMultiPortion
+ *
+ * A SwMultiPortion is not a simple portion,
+ * it's a container, which contains almost a SwLineLayoutPortion.
+ * This SwLineLayout could be followed by other textportions via pPortion
+ * and by another SwLineLayout via pNext to realize a doubleline portion.
+ * --------------------------------------------------*/
+
+SwMultiPortion::~SwMultiPortion()
+{
+ delete pFldRest;
+}
+
+void SwMultiPortion::Paint( const SwTxtPaintInfo & ) const
+{
+ ASSERT( FALSE,
+ "Don't try SwMultiPortion::Paint, try SwTxtPainter::PaintMultiPortion" );
+}
+
+/*-----------------13.10.00 16:21-------------------
+ * Summarize the internal lines to calculate the (external) size.
+ * The internal line has to calculate first.
+ * --------------------------------------------------*/
+
+void SwMultiPortion::CalcSize( SwTxtFormatter& rLine, SwTxtFormatInfo &rInf )
+{
+ Width( 0 );
+ Height( 0 );
+ SetAscent( 0 );
+ SetFlyInCntnt( sal_False );
+ SwLineLayout *pLay = &GetRoot();
+ do
+ {
+ pLay->CalcLine( rLine, rInf );
+ if( rLine.IsFlyInCntBase() )
+ SetFlyInCntnt( sal_True );
+ if( IsRuby() && ( OnTop() == ( pLay == &GetRoot() ) ) )
+ {
+ // An empty phonetic line don't need an ascent or a height.
+ if( !pLay->Width() )
+ {
+ pLay->SetAscent( 0 );
+ pLay->Height( 0 );
+ }
+ if( OnTop() )
+ SetAscent( GetAscent() + pLay->Height() );
+ }
+ else
+ SetAscent( GetAscent() + pLay->GetAscent() );
+ Height( Height() + pLay->Height() );
+ if( Width() < pLay->Width() )
+ Width( pLay->Width() );
+ pLay = pLay->GetNext();
+ } while ( pLay );
+ if( HasBrackets() )
+ {
+ KSHORT nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nHeight;
+ if( nTmp > Height() )
+ {
+ KSHORT nAdd = ( nTmp - Height() ) / 2;
+ GetRoot().SetAscent( GetRoot().GetAscent() + nAdd );
+ GetRoot().Height( GetRoot().Height() + nAdd );
+ Height( nTmp );
+ }
+ nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nAscent;
+ if( nTmp > GetAscent() )
+ SetAscent( nTmp );
+ }
+}
+
+long SwMultiPortion::CalcSpacing( long , const SwTxtSizeInfo & ) const
+{
+ return 0;
+}
+
+sal_Bool SwMultiPortion::ChgSpaceAdd( SwLineLayout*, long ) const
+{
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwMultiPortion::HandlePortion()
+ *************************************************************************/
+
+void SwMultiPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Text( GetLen(), GetWhichPor() );
+}
+
+/*-----------------01.11.00 14:21-------------------
+ * SwMultiPortion::ActualizeTabulator()
+ * sets the tabulator-flag, if there's any tabulator-portion inside.
+ * --------------------------------------------------*/
+
+void SwMultiPortion::ActualizeTabulator()
+{
+ SwLinePortion* pPor = GetRoot().GetFirstPortion();
+ // First line
+ for( bTab1 = bTab2 = sal_False; pPor; pPor = pPor->GetPortion() )
+ if( pPor->InTabGrp() )
+ SetTab1( sal_True );
+ if( GetRoot().GetNext() )
+ {
+ // Second line
+ pPor = GetRoot().GetNext()->GetFirstPortion();
+ do
+ {
+ if( pPor->InTabGrp() )
+ SetTab2( sal_True );
+ pPor = pPor->GetPortion();
+ } while ( pPor );
+ }
+}
+
+/*-----------------16.02.01 12:07-------------------
+ * SwRotatedPortion::SwRotatedPortion(..)
+ * --------------------------------------------------*/
+
+SwRotatedPortion::SwRotatedPortion( const SwMultiCreator& rCreate,
+ xub_StrLen nEnd, sal_Bool bRTL ) : SwMultiPortion( nEnd )
+{
+ const SvxCharRotateItem* pRot = (SvxCharRotateItem*)rCreate.pItem;
+ if( !pRot )
+ {
+ const SwTxtAttr& rAttr = *rCreate.pAttr;
+ const SfxPoolItem *const pItem =
+ CharFmt::GetItem(rAttr, RES_CHRATR_ROTATE);
+ if ( pItem )
+ {
+ pRot = static_cast<const SvxCharRotateItem*>(pItem);
+ }
+ }
+ if( pRot )
+ {
+ sal_uInt8 nDir;
+ if ( bRTL )
+ nDir = pRot->IsBottomToTop() ? 3 : 1;
+ else
+ nDir = pRot->IsBottomToTop() ? 1 : 3;
+
+ SetDirection( nDir );
+ }
+}
+
+/*---------------------------------------------------
+ * SwBidiPortion::SwBidiPortion(..)
+ * --------------------------------------------------*/
+
+SwBidiPortion::SwBidiPortion( xub_StrLen nEnd, BYTE nLv )
+ : SwMultiPortion( nEnd ), nLevel( nLv )
+{
+ SetBidi();
+
+ if ( nLevel % 2 )
+ SetDirection( DIR_RIGHT2LEFT );
+ else
+ SetDirection( DIR_LEFT2RIGHT );
+}
+
+
+long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo& rInf ) const
+{
+ return HasTabulator() ? 0 : GetSpaceCnt(rInf) * nSpaceAdd / SPACING_PRECISION_FACTOR;
+}
+
+sal_Bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const
+{
+ sal_Bool bRet = sal_False;
+ if( !HasTabulator() && nSpaceAdd > 0 && !pCurr->IsSpaceAdd() )
+ {
+ pCurr->CreateSpaceAdd();
+ pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
+ bRet = sal_True;
+ }
+
+ return bRet;
+}
+
+xub_StrLen SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf ) const
+{
+ // Calculate number of blanks for justified alignment
+ SwLinePortion* pPor = GetRoot().GetFirstPortion();
+ xub_StrLen nTmpStart = rInf.GetIdx();
+ xub_StrLen nNull = 0;
+ xub_StrLen nBlanks;
+
+ for( nBlanks = 0; pPor; pPor = pPor->GetPortion() )
+ {
+ if( pPor->InTxtGrp() )
+ nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
+ else if ( pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->IsBidi() )
+ nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt( rInf );
+
+ ((SwTxtSizeInfo &)rInf).SetIdx( rInf.GetIdx() + pPor->GetLen() );
+ }
+ ((SwTxtSizeInfo &)rInf).SetIdx( nTmpStart );
+ return nBlanks;
+}
+
+/*-----------------01.11.00 14:22-------------------
+ * SwDoubleLinePortion::SwDoubleLinePortion(..)
+ * This constructor is for the continuation of a doubleline portion
+ * in the next line.
+ * It takes the same brackets and if the original has no content except
+ * brackets, these will be deleted.
+ * --------------------------------------------------*/
+
+SwDoubleLinePortion::SwDoubleLinePortion( SwDoubleLinePortion& rDouble,
+ xub_StrLen nEnd ) :
+ SwMultiPortion( nEnd ),
+ pBracket( 0 )
+{
+ SetDirection( rDouble.GetDirection() );
+ SetDouble();
+ if( rDouble.GetBrackets() )
+ {
+ SetBrackets( rDouble );
+ // An empty multiportion needs no brackets.
+ // Notice: GetLen() might be zero, if the multiportion contains
+ // the second part of a field and the width might be zero, if
+ // it contains a note only. In this cases the brackets are okay.
+ // But if the length and the width are both zero, the portion
+ // is really empty.
+ if( rDouble.Width() == rDouble.BracketWidth() )
+ rDouble.ClearBrackets();
+ }
+}
+
+/*-----------------01.11.00 14:22-------------------
+ * SwDoubleLinePortion::SwDoubleLinePortion(..)
+ * This constructor uses the textattribut to get the right brackets.
+ * The textattribut could be a 2-line-attribute or a character- or
+ * internetstyle, which contains the 2-line-attribute.
+ * --------------------------------------------------*/
+
+SwDoubleLinePortion::SwDoubleLinePortion( const SwMultiCreator& rCreate,
+ xub_StrLen nEnd ) : SwMultiPortion( nEnd ), pBracket( new SwBracket() )
+{
+ SetDouble();
+ const SvxTwoLinesItem* pTwo = (SvxTwoLinesItem*)rCreate.pItem;
+ if( pTwo )
+ pBracket->nStart = 0;
+ else
+ {
+ const SwTxtAttr& rAttr = *rCreate.pAttr;
+ pBracket->nStart = *rAttr.GetStart();
+
+ const SfxPoolItem * const pItem =
+ CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
+ if ( pItem )
+ {
+ pTwo = static_cast<const SvxTwoLinesItem*>(pItem);
+ }
+ }
+ if( pTwo )
+ {
+ pBracket->cPre = pTwo->GetStartBracket();
+ pBracket->cPost = pTwo->GetEndBracket();
+ }
+ else
+ {
+ pBracket->cPre = 0;
+ pBracket->cPost = 0;
+ }
+ BYTE nTmp = SW_SCRIPTS;
+ if( pBracket->cPre > 255 )
+ {
+ String aTxt( pBracket->cPre );
+ nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
+ }
+ pBracket->nPreScript = nTmp;
+ nTmp = SW_SCRIPTS;
+ if( pBracket->cPost > 255 )
+ {
+ String aTxt( pBracket->cPost );
+ nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
+ }
+ pBracket->nPostScript = nTmp;
+
+ if( !pBracket->cPre && !pBracket->cPost )
+ {
+ delete pBracket;
+ pBracket = 0;
+ }
+
+ // double line portions have the same direction as the frame directions
+ if ( rCreate.nLevel % 2 )
+ SetDirection( DIR_RIGHT2LEFT );
+ else
+ SetDirection( DIR_LEFT2RIGHT );
+}
+
+
+/*-----------------25.10.00 09:51-------------------
+ * SwMultiPortion::PaintBracket paints the wished bracket,
+ * if the multiportion has surrounding brackets.
+ * The X-position of the SwTxtPaintInfo will be modified:
+ * the open bracket sets position behind itself,
+ * the close bracket in front of itself.
+ * --------------------------------------------------*/
+
+void SwDoubleLinePortion::PaintBracket( SwTxtPaintInfo &rInf,
+ long nSpaceAdd,
+ sal_Bool bOpen ) const
+{
+ sal_Unicode cCh = bOpen ? pBracket->cPre : pBracket->cPost;
+ if( !cCh )
+ return;
+ KSHORT nChWidth = bOpen ? PreWidth() : PostWidth();
+ if( !nChWidth )
+ return;
+ if( !bOpen )
+ rInf.X( rInf.X() + Width() - PostWidth() +
+ ( nSpaceAdd > 0 ? CalcSpacing( nSpaceAdd, rInf ) : 0 ) );
+
+ SwBlankPortion aBlank( cCh, sal_True );
+ aBlank.SetAscent( pBracket->nAscent );
+ aBlank.Width( nChWidth );
+ aBlank.Height( pBracket->nHeight );
+ {
+ SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
+ BYTE nAct = bOpen ? pBracket->nPreScript : pBracket->nPostScript;
+ if( SW_SCRIPTS > nAct )
+ pTmpFnt->SetActual( nAct );
+ pTmpFnt->SetProportion( 100 );
+ SwFontSave aSave( rInf, pTmpFnt );
+ aBlank.Paint( rInf );
+ delete pTmpFnt;
+ }
+ if( bOpen )
+ rInf.X( rInf.X() + PreWidth() );
+}
+
+/*-----------------25.10.00 16:26-------------------
+ * SwDoubleLinePortion::SetBrackets creates the bracket-structur
+ * and fills it, if not both characters are 0x00.
+ * --------------------------------------------------*/
+
+void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion& rDouble )
+{
+ if( rDouble.pBracket )
+ {
+ pBracket = new SwBracket;
+ pBracket->cPre = rDouble.pBracket->cPre;
+ pBracket->cPost = rDouble.pBracket->cPost;
+ pBracket->nPreScript = rDouble.pBracket->nPreScript;
+ pBracket->nPostScript = rDouble.pBracket->nPostScript;
+ pBracket->nStart = rDouble.pBracket->nStart;
+ }
+}
+
+/*-----------------25.10.00 16:29-------------------
+ * SwDoubleLinePortion::FormatBrackets
+ * calculates the size of the brackets => pBracket,
+ * reduces the nMaxWidth-parameter ( minus bracket-width )
+ * and moves the rInf-x-position behind the opening bracket.
+ * --------------------------------------------------*/
+
+void SwDoubleLinePortion::FormatBrackets( SwTxtFormatInfo &rInf, SwTwips& nMaxWidth )
+{
+ nMaxWidth -= rInf.X();
+ SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
+ pTmpFnt->SetProportion( 100 );
+ pBracket->nAscent = 0;
+ pBracket->nHeight = 0;
+ if( pBracket->cPre )
+ {
+ String aStr( pBracket->cPre );
+ BYTE nActualScr = pTmpFnt->GetActual();
+ if( SW_SCRIPTS > pBracket->nPreScript )
+ pTmpFnt->SetActual( pBracket->nPreScript );
+ SwFontSave aSave( rInf, pTmpFnt );
+ SwPosSize aSize = rInf.GetTxtSize( aStr );
+ pBracket->nAscent = rInf.GetAscent();
+ pBracket->nHeight = aSize.Height();
+ pTmpFnt->SetActual( nActualScr );
+ if( nMaxWidth > aSize.Width() )
+ {
+ pBracket->nPreWidth = aSize.Width();
+ nMaxWidth -= aSize.Width();
+ rInf.X( rInf.X() + aSize.Width() );
+ }
+ else
+ {
+ pBracket->nPreWidth = 0;
+ nMaxWidth = 0;
+ }
+ }
+ else
+ pBracket->nPreWidth = 0;
+ if( pBracket->cPost )
+ {
+ String aStr( pBracket->cPost );
+ if( SW_SCRIPTS > pBracket->nPostScript )
+ pTmpFnt->SetActual( pBracket->nPostScript );
+ SwFontSave aSave( rInf, pTmpFnt );
+ SwPosSize aSize = rInf.GetTxtSize( aStr );
+ KSHORT nTmpAsc = rInf.GetAscent();
+ if( nTmpAsc > pBracket->nAscent )
+ {
+ pBracket->nHeight += nTmpAsc - pBracket->nAscent;
+ pBracket->nAscent = nTmpAsc;
+ }
+ if( aSize.Height() > pBracket->nHeight )
+ pBracket->nHeight = aSize.Height();
+ if( nMaxWidth > aSize.Width() )
+ {
+ pBracket->nPostWidth = aSize.Width();
+ nMaxWidth -= aSize.Width();
+ }
+ else
+ {
+ pBracket->nPostWidth = 0;
+ nMaxWidth = 0;
+ }
+ }
+ else
+ pBracket->nPostWidth = 0;
+ nMaxWidth += rInf.X();
+}
+
+/*-----------------26.10.00 10:36-------------------
+ * SwDoubleLinePortion::CalcBlanks
+ * calculates the number of blanks in each line and
+ * the difference of the width of the two lines.
+ * These results are used from the text adjustment.
+ * --------------------------------------------------*/
+
+void SwDoubleLinePortion::CalcBlanks( SwTxtFormatInfo &rInf )
+{
+ SwLinePortion* pPor = GetRoot().GetFirstPortion();
+ xub_StrLen nNull = 0;
+ xub_StrLen nStart = rInf.GetIdx();
+ SetTab1( sal_False );
+ SetTab2( sal_False );
+ for( nBlank1 = 0; pPor; pPor = pPor->GetPortion() )
+ {
+ if( pPor->InTxtGrp() )
+ nBlank1 = nBlank1 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
+ rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
+ if( pPor->InTabGrp() )
+ SetTab1( sal_True );
+ }
+ nLineDiff = GetRoot().Width();
+ if( GetRoot().GetNext() )
+ {
+ pPor = GetRoot().GetNext()->GetFirstPortion();
+ nLineDiff -= GetRoot().GetNext()->Width();
+ }
+ for( nBlank2 = 0; pPor; pPor = pPor->GetPortion() )
+ {
+ if( pPor->InTxtGrp() )
+ nBlank2 = nBlank2 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
+ rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
+ if( pPor->InTabGrp() )
+ SetTab2( sal_True );
+ }
+ rInf.SetIdx( nStart );
+}
+
+long SwDoubleLinePortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo & ) const
+{
+ return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd / SPACING_PRECISION_FACTOR;
+}
+
+/*-----------------01.11.00 14:29-------------------
+ * SwDoubleLinePortion::ChangeSpaceAdd(..)
+ * merges the spaces for text adjustment from the inner and outer part.
+ * Inside the doubleline portion the wider line has no spaceadd-array, the
+ * smaller line has such an array to reach width of the wider line.
+ * If the surrounding line has text adjustment and the doubleline portion
+ * contains no tabulator, it is necessary to create/manipulate the inner
+ * space arrays.
+ * --------------------------------------------------*/
+
+sal_Bool SwDoubleLinePortion::ChgSpaceAdd( SwLineLayout* pCurr,
+ long nSpaceAdd ) const
+{
+ sal_Bool bRet = sal_False;
+ if( !HasTabulator() && nSpaceAdd > 0 )
+ {
+ if( !pCurr->IsSpaceAdd() )
+ {
+ // The wider line gets the spaceadd from the surrounding line direct
+ pCurr->CreateSpaceAdd();
+ pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
+ bRet = sal_True;
+ }
+ else
+ {
+ xub_StrLen nMyBlank = GetSmallerSpaceCnt();
+ xub_StrLen nOther = GetSpaceCnt();
+ SwTwips nMultiSpace = pCurr->GetLLSpaceAdd( 0 ) * nMyBlank + nOther * nSpaceAdd;
+
+ if( nMyBlank )
+ nMultiSpace /= nMyBlank;
+
+ if( nMultiSpace < KSHRT_MAX * SPACING_PRECISION_FACTOR )
+ {
+// pCurr->SetLLSpaceAdd( nMultiSpace, 0 );
+ // --> FME 2006-07-11 #i65711# SetLLSpaceAdd replaces the first value,
+ // instead we want to insert a new first value:
+ std::vector<long>* pVec = pCurr->GetpLLSpaceAdd();
+ pVec->insert( pVec->begin(), nMultiSpace );
+ // <--
+ bRet = sal_True;
+ }
+ }
+ }
+ return bRet;
+}
+/*-----------------01.11.00 14:29-------------------
+ * SwDoubleLinePortion::ResetSpaceAdd(..)
+ * cancels the manipulation from SwDoubleLinePortion::ChangeSpaceAdd(..)
+ * --------------------------------------------------*/
+
+void SwDoubleLinePortion::ResetSpaceAdd( SwLineLayout* pCurr )
+{
+ pCurr->RemoveFirstLLSpaceAdd();;
+ if( !pCurr->GetLLSpaceAddCount() )
+ pCurr->FinishSpaceAdd();
+}
+
+SwDoubleLinePortion::~SwDoubleLinePortion()
+{
+ delete pBracket;
+}
+
+/*-----------------13.11.00 14:50-------------------
+ * SwRubyPortion::SwRubyPortion(..)
+ * constructs a ruby portion, i.e. an additional text is displayed
+ * beside the main text, e.g. phonetic characters.
+ * --------------------------------------------------*/
+
+
+SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, xub_StrLen nEnd ) :
+ SwMultiPortion( nEnd ),
+ nRubyOffset( rRuby.GetRubyOffset() ),
+ nAdjustment( rRuby.GetAdjustment() )
+{
+ SetDirection( rRuby.GetDirection() ),
+ SetTop( rRuby.OnTop() );
+ SetRuby();
+}
+
+/*-----------------13.11.00 14:50-------------------
+ * SwRubyPortion::SwRubyPortion(..)
+ * constructs a ruby portion, i.e. an additional text is displayed
+ * beside the main text, e.g. phonetic characters.
+ * --------------------------------------------------*/
+
+SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt,
+ const IDocumentSettingAccess& rIDocumentSettingAccess,
+ xub_StrLen nEnd, xub_StrLen nOffs,
+ const sal_Bool* pForceRubyPos )
+ : SwMultiPortion( nEnd )
+{
+ SetRuby();
+ ASSERT( SW_MC_RUBY == rCreate.nId, "Ruby expected" );
+ ASSERT( RES_TXTATR_CJK_RUBY == rCreate.pAttr->Which(), "Wrong attribute" );
+ const SwFmtRuby& rRuby = rCreate.pAttr->GetRuby();
+ nAdjustment = rRuby.GetAdjustment();
+ nRubyOffset = nOffs;
+
+ // in grid mode we force the ruby text to the upper or lower line
+ if ( pForceRubyPos )
+ SetTop( *pForceRubyPos );
+ else
+ SetTop( ! rRuby.GetPosition() );
+
+ const SwCharFmt* pFmt = ((SwTxtRuby*)rCreate.pAttr)->GetCharFmt();
+ SwFont *pRubyFont;
+ if( pFmt )
+ {
+ const SwAttrSet& rSet = pFmt->GetAttrSet();
+ pRubyFont = new SwFont( rFnt );
+ pRubyFont->SetDiffFnt( &rSet, &rIDocumentSettingAccess );
+
+ // we do not allow a vertical font for the ruby text
+ pRubyFont->SetVertical( rFnt.GetOrientation() );
+ }
+ else
+ pRubyFont = NULL;
+
+ String aStr( rRuby.GetText(), nOffs, STRING_LEN );
+ SwFldPortion *pFld = new SwFldPortion( aStr, pRubyFont );
+ pFld->SetNextOffset( nOffs );
+ pFld->SetFollow( sal_True );
+
+ if( OnTop() )
+ GetRoot().SetPortion( pFld );
+ else
+ {
+ GetRoot().SetNext( new SwLineLayout() );
+ GetRoot().GetNext()->SetPortion( pFld );
+ }
+
+ // ruby portions have the same direction as the frame directions
+ if ( rCreate.nLevel % 2 )
+ {
+ // switch right and left ruby adjustment in rtl environment
+ if ( 0 == nAdjustment )
+ nAdjustment = 2;
+ else if ( 2 == nAdjustment )
+ nAdjustment = 0;
+
+ SetDirection( DIR_RIGHT2LEFT );
+ }
+ else
+ SetDirection( DIR_LEFT2RIGHT );
+}
+
+/*-----------------13.11.00 14:56-------------------
+ * SwRubyPortion::_Adjust(..)
+ * In ruby portion there are different alignments for
+ * the ruby text and the main text.
+ * Left, right, centered and two possibilities of block adjustment
+ * The block adjustment is realized by spacing between the characteres,
+ * either with a half space or no space in front of the first letter and
+ * a half space at the end of the last letter.
+ * Notice: the smaller line will be manipulated, normally it's the ruby line,
+ * but it could be the main text, too.
+ * If there is a tabulator in smaller line, no adjustment is possible.
+ * --------------------------------------------------*/
+
+void SwRubyPortion::_Adjust( SwTxtFormatInfo &rInf )
+{
+ SwTwips nLineDiff = GetRoot().Width() - GetRoot().GetNext()->Width();
+ xub_StrLen nOldIdx = rInf.GetIdx();
+ if( !nLineDiff )
+ return;
+ SwLineLayout *pCurr;
+ if( nLineDiff < 0 )
+ { // The first line has to be adjusted.
+ if( GetTab1() )
+ return;
+ pCurr = &GetRoot();
+ nLineDiff = -nLineDiff;
+ }
+ else
+ { // The second line has to be adjusted.
+ if( GetTab2() )
+ return;
+ pCurr = GetRoot().GetNext();
+ rInf.SetIdx( nOldIdx + GetRoot().GetLen() );
+ }
+ KSHORT nLeft = 0; // the space in front of the first letter
+ KSHORT nRight = 0; // the space at the end of the last letter
+ USHORT nSub = 0;
+ switch ( nAdjustment )
+ {
+ case 1: nRight = static_cast<USHORT>(nLineDiff / 2); // no break
+ case 2: nLeft = static_cast<USHORT>(nLineDiff - nRight); break;
+ case 3: nSub = 1; // no break
+ case 4:
+ {
+ xub_StrLen nCharCnt = 0;
+ SwLinePortion *pPor;
+ for( pPor = pCurr->GetFirstPortion(); pPor; pPor = pPor->GetPortion() )
+ {
+ if( pPor->InTxtGrp() )
+ ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nCharCnt );
+ rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
+ }
+ if( nCharCnt > nSub )
+ {
+ SwTwips nCalc = nLineDiff / ( nCharCnt - nSub );
+ short nTmp;
+ if( nCalc < SHRT_MAX )
+ nTmp = -short(nCalc);
+ else
+ nTmp = SHRT_MIN;
+
+ pCurr->CreateSpaceAdd( SPACING_PRECISION_FACTOR * nTmp );
+ nLineDiff -= nCalc * ( nCharCnt - 1 );
+ }
+ if( nLineDiff > 1 )
+ {
+ nRight = static_cast<USHORT>(nLineDiff / 2);
+ nLeft = static_cast<USHORT>(nLineDiff - nRight);
+ }
+ break;
+ }
+ default: ASSERT( sal_False, "New ruby adjustment" );
+ }
+ if( nLeft || nRight )
+ {
+ if( !pCurr->GetPortion() )
+ pCurr->SetPortion( new SwTxtPortion( *pCurr ) );
+ SwMarginPortion *pMarg = new SwMarginPortion( 0 );
+ if( nLeft )
+ {
+ pMarg->AddPrtWidth( nLeft );
+ pMarg->SetPortion( pCurr->GetPortion() );
+ pCurr->SetPortion( pMarg );
+ }
+ if( nRight )
+ {
+ pMarg = new SwMarginPortion( 0 );
+ pMarg->AddPrtWidth( nRight );
+ pCurr->FindLastPortion()->Append( pMarg );
+ }
+ }
+
+ pCurr->Width( Width() );
+ rInf.SetIdx( nOldIdx );
+}
+
+/*-----------------08.11.00 14:14-------------------
+ * CalcRubyOffset()
+ * has to change the nRubyOffset, if there's a fieldportion
+ * in the phonetic line.
+ * The nRubyOffset is the position in the rubystring, where the
+ * next SwRubyPortion has start the displaying of the phonetics.
+ * --------------------------------------------------*/
+
+void SwRubyPortion::CalcRubyOffset()
+{
+ const SwLineLayout *pCurr = &GetRoot();
+ if( !OnTop() )
+ {
+ pCurr = pCurr->GetNext();
+ if( !pCurr )
+ return;
+ }
+ const SwLinePortion *pPor = pCurr->GetFirstPortion();
+ const SwFldPortion *pFld = NULL;
+ while( pPor )
+ {
+ if( pPor->InFldGrp() )
+ pFld = (SwFldPortion*)pPor;
+ pPor = pPor->GetPortion();
+ }
+ if( pFld )
+ {
+ if( pFld->HasFollow() )
+ nRubyOffset = pFld->GetNextOffset();
+ else
+ nRubyOffset = STRING_LEN;
+ }
+}
+
+/*-----------------13.10.00 16:22-------------------
+ * SwTxtSizeInfo::GetMultiCreator(..)
+ * If we (e.g. the position rPos) are inside a two-line-attribute or
+ * a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
+ * otherwise the function returns zero.
+ * The rPos parameter is set to the end of the multiportion,
+ * normally this is the end of the attribute,
+ * but sometimes it is the start of another attribute, which finished or
+ * interrupts the first attribute.
+ * E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute
+ * with different brackets interrupts another 2-line-attribute.
+ * --------------------------------------------------*/
+
+/*-----------------13.11.00 15:38-------------------
+ * lcl_Has2Lines(..)
+ * is a little help function for GetMultiCreator(..)
+ * It extracts the 2-line-format from a 2-line-attribute or a character style.
+ * The rValue is set to TRUE, if the 2-line-attribute's value is set and
+ * no 2-line-format reference is passed. If there is a 2-line-format reference,
+ * then the rValue is set only, if the 2-line-attribute's value is set _and_
+ * the 2-line-formats has the same brackets.
+ * --------------------------------------------------*/
+
+sal_Bool lcl_Has2Lines( const SwTxtAttr& rAttr, const SvxTwoLinesItem* &rpRef,
+ sal_Bool &rValue )
+{
+ const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
+ if( pItem )
+ {
+ rValue = ((SvxTwoLinesItem*)pItem)->GetValue();
+ if( !rpRef )
+ rpRef = (SvxTwoLinesItem*)pItem;
+ else if( ((SvxTwoLinesItem*)pItem)->GetEndBracket() !=
+ rpRef->GetEndBracket() ||
+ ((SvxTwoLinesItem*)pItem)->GetStartBracket() !=
+ rpRef->GetStartBracket() )
+ rValue = sal_False;
+ return sal_True;
+ }
+ return sal_False;
+}
+
+/*-----------------16.02.01 16:39-------------------
+ * lcl_HasRotation(..)
+ * is a little help function for GetMultiCreator(..)
+ * It extracts the charrotation from a charrotate-attribute or a character style.
+ * The rValue is set to TRUE, if the charrotate-attribute's value is set and
+ * no charrotate-format reference is passed.
+ * If there is a charrotate-format reference, then the rValue is set only,
+ * if the charrotate-attribute's value is set _and_ identical
+ * to the charrotate-format's value.
+ * --------------------------------------------------*/
+
+sal_Bool lcl_HasRotation( const SwTxtAttr& rAttr,
+ const SvxCharRotateItem* &rpRef, sal_Bool &rValue )
+{
+ const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_ROTATE );
+ if ( pItem )
+ {
+ rValue = 0 != ((SvxCharRotateItem*)pItem)->GetValue();
+ if( !rpRef )
+ rpRef = (SvxCharRotateItem*)pItem;
+ else if( ((SvxCharRotateItem*)pItem)->GetValue() !=
+ rpRef->GetValue() )
+ rValue = sal_False;
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+SwMultiCreator* SwTxtSizeInfo::GetMultiCreator( xub_StrLen &rPos,
+ SwMultiPortion* pMulti ) const
+{
+ SwScriptInfo& rSI = ((SwParaPortion*)GetParaPortion())->GetScriptInfo();
+
+ // get the last embedding level
+ BYTE nCurrLevel;
+ if ( pMulti )
+ {
+ ASSERT( pMulti->IsBidi(), "Nested MultiPortion is not BidiPortion" )
+ // level associated with bidi-portion;
+ nCurrLevel = ((SwBidiPortion*)pMulti)->GetLevel();
+ }
+ else
+ // no nested bidi portion required
+ nCurrLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
+
+ // check if there is a field at rPos:
+ BYTE nNextLevel = nCurrLevel;
+ sal_Bool bFldBidi = sal_False;
+
+ if ( CH_TXTATR_BREAKWORD == GetChar( rPos ) )
+ {
+ bFldBidi = sal_True;
+/*
+ // examining the script of the field text should be sufficient
+ // for 99% of all cases
+ XubString aTxt = GetTxtFrm()->GetTxtNode()->GetExpandTxt( rPos, 1 );
+
+ if ( pBreakIt->GetBreakIter().is() && aTxt.Len() )
+ {
+ sal_Bool bFldDir = ( i18n::ScriptType::COMPLEX ==
+ pBreakIt->GetRealScriptOfText( aTxt, 0 ) );
+ sal_Bool bCurrDir = ( 0 != ( nCurrLevel % 2 ) );
+ if ( bFldDir != bCurrDir )
+ {
+ nNextLevel = nCurrLevel + 1;
+ bFldBidi = sal_True;
+ }
+ }*/
+ }
+ else
+ nNextLevel = rSI.DirType( rPos );
+
+ if ( GetTxt().Len() != rPos && nNextLevel > nCurrLevel )
+ {
+ rPos = bFldBidi ? rPos + 1 : rSI.NextDirChg( rPos, &nCurrLevel );
+ if ( STRING_LEN == rPos )
+ return NULL;
+ SwMultiCreator *pRet = new SwMultiCreator;
+ pRet->pItem = NULL;
+ pRet->pAttr = NULL;
+ pRet->nId = SW_MC_BIDI;
+ pRet->nLevel = nCurrLevel + 1;
+ return pRet;
+ }
+
+ // a bidi portion can only contain other bidi portions
+ if ( pMulti )
+ return NULL;
+
+ const SvxCharRotateItem* pRotate = NULL;
+ const SfxPoolItem* pRotItem;
+ if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
+ GetItemState( RES_CHRATR_ROTATE, TRUE, &pRotItem ) &&
+ ((SvxCharRotateItem*)pRotItem)->GetValue() )
+ pRotate = (SvxCharRotateItem*)pRotItem;
+ else
+ pRotItem = NULL;
+ const SvxTwoLinesItem* p2Lines = NULL;
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
+ GetItemState( RES_CHRATR_TWO_LINES, TRUE, &pItem ) &&
+ ((SvxTwoLinesItem*)pItem)->GetValue() )
+ p2Lines = (SvxTwoLinesItem*)pItem;
+ else
+ pItem = NULL;
+
+ const SwpHints *pHints = pFrm->GetTxtNode()->GetpSwpHints();
+ if( !pHints && !p2Lines && !pRotate )
+ return NULL;
+ const SwTxtAttr *pRuby = NULL;
+ sal_Bool bTwo = sal_False;
+ sal_Bool bRot = sal_False;
+ USHORT n2Lines = USHRT_MAX;
+ USHORT nRotate = USHRT_MAX;
+ USHORT nCount = pHints ? pHints->Count() : 0;
+ USHORT i;
+ for( i = 0; i < nCount; ++i )
+ {
+ const SwTxtAttr *pTmp = (*pHints)[i];
+ xub_StrLen nStart = *pTmp->GetStart();
+ if( rPos < nStart )
+ break;
+ if( *pTmp->GetAnyEnd() > rPos )
+ {
+ if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+ pRuby = pTmp;
+ else
+ {
+ const SvxCharRotateItem* pRoTmp = NULL;
+ if( lcl_HasRotation( *pTmp, pRoTmp, bRot ) )
+ {
+ nRotate = bRot ? i : nCount;
+ pRotate = pRoTmp;
+ }
+ const SvxTwoLinesItem* p2Tmp = NULL;
+ if( lcl_Has2Lines( *pTmp, p2Tmp, bTwo ) )
+ {
+ n2Lines = bTwo ? i : nCount;
+ p2Lines = p2Tmp;
+ }
+ }
+ }
+ }
+ if( pRuby )
+ { // The winner is ... a ruby attribute and so
+ // the end of the multiportion is the end of the ruby attribute.
+ rPos = *pRuby->GetEnd();
+ SwMultiCreator *pRet = new SwMultiCreator;
+ pRet->pItem = NULL;
+ pRet->pAttr = pRuby;
+ pRet->nId = SW_MC_RUBY;
+ pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
+ return pRet;
+ }
+ if( n2Lines < nCount || ( pItem && pItem == p2Lines &&
+ rPos < GetTxt().Len() ) )
+ { // The winner is a 2-line-attribute,
+ // the end of the multiportion depends on the following attributes...
+ SwMultiCreator *pRet = new SwMultiCreator;
+
+ // We note the endpositions of the 2-line attributes in aEnd as stack
+ SvXub_StrLens aEnd;
+
+ // The bOn flag signs the state of the last 2-line attribute in the
+ // aEnd-stack, it is compatible with the winner-attribute or
+ // it interrupts the other attribute.
+ sal_Bool bOn = sal_True;
+
+ if( n2Lines < nCount )
+ {
+ pRet->pItem = NULL;
+ pRet->pAttr = (*pHints)[n2Lines];
+ aEnd.Insert( *pRet->pAttr->GetEnd(), 0 );
+ if( pItem )
+ {
+ aEnd[ 0 ] = GetTxt().Len();
+ bOn = ((SvxTwoLinesItem*)pItem)->GetEndBracket() ==
+ p2Lines->GetEndBracket() &&
+ ((SvxTwoLinesItem*)pItem)->GetStartBracket() ==
+ p2Lines->GetStartBracket();
+ }
+ }
+ else
+ {
+ pRet->pItem = pItem;
+ pRet->pAttr = NULL;
+ aEnd.Insert( GetTxt().Len(), 0 );
+ }
+ pRet->nId = SW_MC_DOUBLE;
+ pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
+
+ // n2Lines is the index of the last 2-line-attribute, which contains
+ // the actual position.
+ i = 0;
+ // At this moment we know that at position rPos the "winner"-attribute
+ // causes a 2-line-portion. The end of the attribute is the end of the
+ // portion, if there's no interrupting attribute.
+ // There are two kinds of interruptors:
+ // - ruby attributes stops the 2-line-attribute, the end of the
+ // multiline is the start of the ruby attribute
+ // - 2-line-attributes with value "Off" or with different brackets,
+ // these attributes may interrupt the winner, but they could be
+ // neutralized by another 2-line-attribute starting at the same
+ // position with the same brackets as the winner-attribute.
+
+ // In the following loop rPos is the critical position and it will be
+ // evaluated, if at rPos starts a interrupting or a maintaining
+ // continuity attribute.
+ while( i < nCount )
+ {
+ const SwTxtAttr *pTmp = (*pHints)[i++];
+ if( *pTmp->GetAnyEnd() <= rPos )
+ continue;
+ if( rPos < *pTmp->GetStart() )
+ {
+ // If bOn is FALSE and the next attribute starts later than rPos
+ // the winner attribute is interrupted at rPos.
+ // If the start of the next atribute is behind the end of
+ // the last attribute on the aEnd-stack, this is the endposition
+ // on the stack is the end of the 2-line portion.
+ if( !bOn || aEnd[ aEnd.Count()-1 ] < *pTmp->GetStart() )
+ break;
+ // At this moment, bOn is TRUE and the next attribute starts
+ // behind rPos, so we could move rPos to the next startpoint
+ rPos = *pTmp->GetStart();
+ // We clean up the aEnd-stack, endpositions equal to rPos are
+ // superfluous.
+ while( aEnd.Count() && aEnd[ aEnd.Count()-1 ] <= rPos )
+ {
+ bOn = !bOn;
+ aEnd.Remove( aEnd.Count()-1, 1 );
+ }
+ // If the endstack is empty, we simulate an attribute with
+ // state TRUE and endposition rPos
+ if( !aEnd.Count() )
+ {
+ aEnd.Insert( rPos, 0 );
+ bOn = sal_True;
+ }
+ }
+ // A ruby attribute stops the 2-line immediately
+ if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+ return pRet;
+ if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
+ { // We have an interesting attribute..
+ if( bTwo == bOn )
+ { // .. with the same state, so the last attribute could
+ // be continued.
+ if( aEnd[ aEnd.Count()-1 ] < *pTmp->GetEnd() )
+ aEnd[ aEnd.Count()-1 ] = *pTmp->GetEnd();
+ }
+ else
+ { // .. with a different state.
+ bOn = bTwo;
+ // If this is smaller than the last on the stack, we put
+ // it on the stack. If it has the same endposition, the last
+ // could be removed.
+ if( aEnd[ aEnd.Count()-1 ] > *pTmp->GetEnd() )
+ aEnd.Insert( *pTmp->GetEnd(), aEnd.Count() );
+ else if( aEnd.Count() > 1 )
+ aEnd.Remove( aEnd.Count()-1, 1 );
+ else
+ aEnd[ aEnd.Count()-1 ] = *pTmp->GetEnd();
+ }
+ }
+ }
+ if( bOn && aEnd.Count() )
+ rPos = aEnd[ aEnd.Count()-1 ];
+ return pRet;
+ }
+ if( nRotate < nCount || ( pRotItem && pRotItem == pRotate &&
+ rPos < GetTxt().Len() ) )
+ { // The winner is a rotate-attribute,
+ // the end of the multiportion depends on the following attributes...
+ SwMultiCreator *pRet = new SwMultiCreator;
+ pRet->nId = SW_MC_ROTATE;
+
+ // We note the endpositions of the 2-line attributes in aEnd as stack
+ SvXub_StrLens aEnd;
+
+ // The bOn flag signs the state of the last 2-line attribute in the
+ // aEnd-stack, which could interrupts the winning rotation attribute.
+ sal_Bool bOn = pItem ? sal_True : sal_False;
+ aEnd.Insert( GetTxt().Len(), 0 );
+ // n2Lines is the index of the last 2-line-attribute, which contains
+ // the actual position.
+ i = 0;
+ xub_StrLen n2Start = rPos;
+ while( i < nCount )
+ {
+ const SwTxtAttr *pTmp = (*pHints)[i++];
+ if( *pTmp->GetAnyEnd() <= n2Start )
+ continue;
+ if( n2Start < *pTmp->GetStart() )
+ {
+ if( bOn || aEnd[ aEnd.Count()-1 ] < *pTmp->GetStart() )
+ break;
+ n2Start = *pTmp->GetStart();
+ while( aEnd.Count() && aEnd[ aEnd.Count()-1 ] <= n2Start )
+ {
+ bOn = !bOn;
+ aEnd.Remove( aEnd.Count()-1, 1 );
+ }
+ if( !aEnd.Count() )
+ {
+ aEnd.Insert( n2Start, 0 );
+ bOn = sal_False;
+ }
+ }
+ // A ruby attribute stops immediately
+ if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+ {
+ bOn = sal_True;
+ break;
+ }
+ p2Lines = NULL;
+ if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
+ {
+ if( bTwo == bOn )
+ {
+ if( aEnd[ aEnd.Count()-1 ] < *pTmp->GetEnd() )
+ aEnd[ aEnd.Count()-1 ] = *pTmp->GetEnd();
+ }
+ else
+ {
+ bOn = bTwo;
+ if( aEnd[ aEnd.Count()-1 ] > *pTmp->GetEnd() )
+ aEnd.Insert( *pTmp->GetEnd(), aEnd.Count() );
+ else if( aEnd.Count() > 1 )
+ aEnd.Remove( aEnd.Count()-1, 1 );
+ else
+ aEnd[ aEnd.Count()-1 ] = *pTmp->GetEnd();
+ }
+ }
+ }
+ if( !bOn && aEnd.Count() )
+ n2Start = aEnd[ aEnd.Count()-1 ];
+
+ if( aEnd.Count() )
+ aEnd.Remove( 0, aEnd.Count() );
+
+ bOn = sal_True;
+ if( nRotate < nCount )
+ {
+ pRet->pItem = NULL;
+ pRet->pAttr = (*pHints)[nRotate];
+ aEnd.Insert( *pRet->pAttr->GetEnd(), 0 );
+ if( pRotItem )
+ {
+ aEnd[ 0 ] = GetTxt().Len();
+ bOn = ((SvxCharRotateItem*)pRotItem)->GetValue() ==
+ pRotate->GetValue();
+ }
+ }
+ else
+ {
+ pRet->pItem = pRotItem;
+ pRet->pAttr = NULL;
+ aEnd.Insert( GetTxt().Len(), 0 );
+ }
+ i = 0;
+ while( i < nCount )
+ {
+ const SwTxtAttr *pTmp = (*pHints)[i++];
+ if( *pTmp->GetAnyEnd() <= rPos )
+ continue;
+ if( rPos < *pTmp->GetStart() )
+ {
+ if( !bOn || aEnd[ aEnd.Count()-1 ] < *pTmp->GetStart() )
+ break;
+ rPos = *pTmp->GetStart();
+ while( aEnd.Count() && aEnd[ aEnd.Count()-1 ] <= rPos )
+ {
+ bOn = !bOn;
+ aEnd.Remove( aEnd.Count()-1, 1 );
+ }
+ if( !aEnd.Count() )
+ {
+ aEnd.Insert( rPos, 0 );
+ bOn = sal_True;
+ }
+ }
+ if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+ {
+ bOn = sal_False;
+ break;
+ }
+ if( lcl_HasRotation( *pTmp, pRotate, bTwo ) )
+ {
+ if( bTwo == bOn )
+ {
+ if( aEnd[ aEnd.Count()-1 ] < *pTmp->GetEnd() )
+ aEnd[ aEnd.Count()-1 ] = *pTmp->GetEnd();
+ }
+ else
+ {
+ bOn = bTwo;
+ if( aEnd[ aEnd.Count()-1 ] > *pTmp->GetEnd() )
+ aEnd.Insert( *pTmp->GetEnd(), aEnd.Count() );
+ else if( aEnd.Count() > 1 )
+ aEnd.Remove( aEnd.Count()-1, 1 );
+ else
+ aEnd[ aEnd.Count()-1 ] = *pTmp->GetEnd();
+ }
+ }
+ }
+ if( bOn && aEnd.Count() )
+ rPos = aEnd[ aEnd.Count()-1 ];
+ if( rPos > n2Start )
+ rPos = n2Start;
+ return pRet;
+ }
+ return NULL;
+}
+
+/*-----------------01.11.00 14:52-------------------
+ * SwSpaceManipulator
+ * is a little helper class to manage the spaceadd-arrays of the text adjustment
+ * during a PaintMultiPortion.
+ * The constructor prepares the array for the first line of multiportion,
+ * the SecondLine-function restores the values for the first line and prepares
+ * the second line.
+ * The destructor restores the values of the last manipulation.
+ * --------------------------------------------------*/
+
+class SwSpaceManipulator
+{
+ SwTxtPaintInfo& rInfo;
+ SwMultiPortion& rMulti;
+ std::vector<long>* pOldSpaceAdd;
+ MSHORT nOldSpIdx;
+ long nSpaceAdd;
+ sal_Bool bSpaceChg : 1;
+ sal_uInt8 nOldDir : 2;
+public:
+ SwSpaceManipulator( SwTxtPaintInfo& rInf, SwMultiPortion& rMult );
+ ~SwSpaceManipulator();
+ void SecondLine();
+ inline long GetSpaceAdd() const { return nSpaceAdd; }
+};
+
+SwSpaceManipulator::SwSpaceManipulator( SwTxtPaintInfo& rInf,
+ SwMultiPortion& rMult ) :
+ rInfo( rInf ), rMulti( rMult )
+{
+ pOldSpaceAdd = rInfo.GetpSpaceAdd();
+ nOldSpIdx = rInfo.GetSpaceIdx();
+ nOldDir = rInfo.GetDirection();
+ rInfo.SetDirection( rMulti.GetDirection() );
+ bSpaceChg = sal_False;
+
+ if( rMulti.IsDouble() )
+ {
+ nSpaceAdd = ( pOldSpaceAdd && !rMulti.HasTabulator() ) ?
+ rInfo.GetSpaceAdd() : 0;
+ if( rMulti.GetRoot().IsSpaceAdd() )
+ {
+ rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
+ rInfo.ResetSpaceIdx();
+ bSpaceChg = rMulti.ChgSpaceAdd( &rMulti.GetRoot(), nSpaceAdd );
+ }
+ else if( rMulti.HasTabulator() )
+ rInfo.SetpSpaceAdd( NULL );
+ }
+ else if ( ! rMulti.IsBidi() )
+ {
+ rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
+ rInfo.ResetSpaceIdx();
+ }
+}
+
+void SwSpaceManipulator::SecondLine()
+{
+ if( bSpaceChg )
+ {
+ rInfo.RemoveFirstSpaceAdd();
+ bSpaceChg = sal_False;
+ }
+ SwLineLayout *pLay = rMulti.GetRoot().GetNext();
+ if( pLay->IsSpaceAdd() )
+ {
+ rInfo.SetpSpaceAdd( pLay->GetpLLSpaceAdd() );
+ rInfo.ResetSpaceIdx();
+ bSpaceChg = rMulti.ChgSpaceAdd( pLay, nSpaceAdd );
+ }
+ else
+ {
+ rInfo.SetpSpaceAdd( (!rMulti.IsDouble() || rMulti.HasTabulator() ) ?
+ 0 : pOldSpaceAdd );
+ rInfo.SetSpaceIdx( nOldSpIdx);
+ }
+}
+
+SwSpaceManipulator::~SwSpaceManipulator()
+{
+ if( bSpaceChg )
+ {
+ rInfo.RemoveFirstSpaceAdd();
+ bSpaceChg = sal_False;
+ }
+ rInfo.SetpSpaceAdd( pOldSpaceAdd );
+ rInfo.SetSpaceIdx( nOldSpIdx);
+ rInfo.SetDirection( nOldDir );
+}
+
+/*-----------------13.10.00 16:24-------------------
+ * SwTxtPainter::PaintMultiPortion manages the paint for a SwMultiPortion.
+ * External, for the calling function, it seems to be a normal Paint-function,
+ * internal it is like a SwTxtFrm::Paint with multiple DrawTextLines
+ * --------------------------------------------------*/
+
+void SwTxtPainter::PaintMultiPortion( const SwRect &rPaint,
+ SwMultiPortion& rMulti, const SwMultiPortion* pEnvPor )
+{
+ GETGRID( pFrm->FindPageFrm() )
+ const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
+ USHORT nGridWidth = 0;
+ USHORT nRubyHeight = 0;
+ sal_Bool bRubyTop = sal_False;
+
+ if ( bHasGrid )
+ {
+ nGridWidth = pGrid->GetBaseHeight();
+ nRubyHeight = pGrid->GetRubyHeight();
+ bRubyTop = ! pGrid->GetRubyTextBelow();
+ }
+
+ // do not allow grid mode for first line in ruby portion
+ const sal_Bool bRubyInGrid = bHasGrid && rMulti.IsRuby();
+
+ const USHORT nOldHeight = rMulti.Height();
+ const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
+
+ if ( bRubyInGrid )
+ {
+ GetInfo().SetSnapToGrid( ! bRubyTop );
+ rMulti.Height( pCurr->Height() );
+ }
+
+ SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
+ BYTE nEnvDir = 0;
+ BYTE nThisDir = 0;
+ BYTE nFrmDir = 0;
+ if ( rMulti.IsBidi() )
+ {
+ // these values are needed for the calculation of the x coordinate
+ // and the layout mode
+ ASSERT( ! pEnvPor || pEnvPor->IsBidi(),
+ "Oh no, I expected a BidiPortion" )
+ nFrmDir = GetInfo().GetTxtFrm()->IsRightToLeft() ? 1 : 0;
+ nEnvDir = pEnvPor ? ((SwBidiPortion*)pEnvPor)->GetLevel() % 2 : nFrmDir;
+ nThisDir = ((SwBidiPortion&)rMulti).GetLevel() % 2;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ // only paint first level bidi portions
+ if( rMulti.Width() > 1 && ! pEnvPor )
+ GetInfo().DrawViewOpt( rMulti, POR_FLD );
+#endif
+
+ if ( bRubyInGrid )
+ rMulti.Height( nOldHeight );
+
+ // do we have to repaint a post it portion?
+ if( GetInfo().OnWin() && rMulti.GetPortion() &&
+ ! rMulti.GetPortion()->Width() )
+ rMulti.GetPortion()->PrePaint( GetInfo(), &rMulti );
+
+ // old values must be saved and restored at the end
+ xub_StrLen nOldLen = GetInfo().GetLen();
+ KSHORT nOldX = KSHORT(GetInfo().X());
+ long nOldY = GetInfo().Y();
+ xub_StrLen nOldIdx = GetInfo().GetIdx();
+
+ SwSpaceManipulator aManip( GetInfo(), rMulti );
+
+ SwFontSave *pFontSave;
+ SwFont* pTmpFnt;
+
+ if( rMulti.IsDouble() )
+ {
+ pTmpFnt = new SwFont( *GetInfo().GetFont() );
+ if( rMulti.IsDouble() )
+ {
+ SetPropFont( 50 );
+ pTmpFnt->SetProportion( GetPropFont() );
+ }
+ pFontSave = new SwFontSave( GetInfo(), pTmpFnt, this );
+ }
+ else
+ {
+ pFontSave = NULL;
+ pTmpFnt = NULL;
+ }
+
+ if( rMulti.HasBrackets() )
+ {
+ xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
+ GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
+ SeekAndChg( GetInfo() );
+ ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(), 0, sal_True );
+ GetInfo().SetIdx( nTmpOldIdx );
+ }
+
+ KSHORT nTmpX = KSHORT(GetInfo().X());
+
+ SwLineLayout* pLay = &rMulti.GetRoot();// the first line of the multiportion
+ SwLinePortion* pPor = pLay->GetFirstPortion();//first portion of these line
+ SwTwips nOfst = 0;
+
+ // GetInfo().Y() is the baseline from the surrounding line. We must switch
+ // this temporary to the baseline of the inner lines of the multiportion.
+ if( rMulti.HasRotation() )
+ {
+ if( rMulti.IsRevers() )
+ {
+ GetInfo().Y( nOldY - rMulti.GetAscent() );
+ nOfst = nTmpX + rMulti.Width();
+ }
+ else
+ {
+ GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
+ nOfst = nTmpX;
+ }
+ }
+ else if ( rMulti.IsBidi() )
+ {
+ // does the current bidi portion has the same direction
+ // as its environment?
+ if ( nEnvDir != nThisDir )
+ {
+ // different directions, we have to adjust the x coordinate
+ SwTwips nMultiWidth = rMulti.Width() +
+ rMulti.CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
+
+ if ( nFrmDir == nThisDir )
+ GetInfo().X( GetInfo().X() - nMultiWidth );
+ else
+ GetInfo().X( GetInfo().X() + nMultiWidth );
+ }
+
+ nOfst = nOldY - rMulti.GetAscent();
+
+ // set layout mode
+ aLayoutModeModifier.Modify( nThisDir );
+ }
+ else
+ nOfst = nOldY - rMulti.GetAscent();
+
+ sal_Bool bRest = pLay->IsRest();
+ sal_Bool bFirst = sal_True;
+
+ ASSERT( 0 == GetInfo().GetUnderFnt() || rMulti.IsBidi(),
+ " Only BiDi portions are allowed to use the common underlining font" )
+
+ do
+ {
+ if ( bHasGrid )
+ {
+ if( rMulti.HasRotation() )
+ {
+ const USHORT nAdjustment = ( pLay->Height() - pPor->Height() ) / 2 +
+ pPor->GetAscent();
+ if( rMulti.IsRevers() )
+ GetInfo().X( nOfst - nAdjustment );
+ else
+ GetInfo().X( nOfst + nAdjustment );
+ }
+ else
+ {
+ // special treatment for ruby portions in grid mode
+ SwTwips nAdjustment = 0;
+ if ( rMulti.IsRuby() )
+ {
+ if ( bRubyTop != ( pLay == &rMulti.GetRoot() ) )
+ // adjust base text
+ nAdjustment = ( pCurr->Height() - nRubyHeight - pPor->Height() ) / 2;
+ else if ( bRubyTop )
+ // adjust upper ruby text
+ nAdjustment = nRubyHeight - pPor->Height();
+ // else adjust lower ruby text
+ }
+
+ GetInfo().Y( nOfst + nAdjustment + pPor->GetAscent() );
+ }
+ }
+ else if( rMulti.HasRotation() )
+ {
+ if( rMulti.IsRevers() )
+ GetInfo().X( nOfst - AdjustBaseLine( *pLay, pPor, 0, 0, sal_True ) );
+ else
+ GetInfo().X( nOfst + AdjustBaseLine( *pLay, pPor ) );
+ }
+ else
+ GetInfo().Y( nOfst + AdjustBaseLine( *pLay, pPor ) );
+
+ sal_Bool bSeeked = sal_True;
+ GetInfo().SetLen( pPor->GetLen() );
+
+ if( bRest && pPor->InFldGrp() && !pPor->GetLen() )
+ {
+ if( ((SwFldPortion*)pPor)->HasFont() )
+ bSeeked = sal_False;
+ else
+ SeekAndChgBefore( GetInfo() );
+ }
+ else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
+ SeekAndChg( GetInfo() );
+ else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
+ {
+ if( GetRedln() )
+ SeekAndChg( GetInfo() );
+ else
+ SeekAndChgBefore( GetInfo() );
+ }
+ else
+ bSeeked = sal_False;
+
+ SwLinePortion *pNext = pPor->GetPortion();
+ if(GetInfo().OnWin() && pNext && !pNext->Width() )
+ {
+ if ( !bSeeked )
+ SeekAndChg( GetInfo() );
+ pNext->PrePaint( GetInfo(), pPor );
+ }
+
+ CheckSpecialUnderline( pPor );
+ SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
+ if ( pUnderLineFnt )
+ {
+ if ( rMulti.IsDouble() )
+ pUnderLineFnt->GetFont().SetProportion( 50 );
+ pUnderLineFnt->SetPos( GetInfo().GetPos() );
+ }
+
+ if ( rMulti.IsBidi() )
+ {
+ // we do not allow any rotation inside a bidi portion
+ SwFont* pTmpFont = GetInfo().GetFont();
+ pTmpFont->SetVertical( 0, GetInfo().GetTxtFrm()->IsVertical() );
+ }
+
+ if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() )
+ {
+ // but we do allow nested bidi portions
+ ASSERT( rMulti.IsBidi(), "Only nesting of bidi portions is allowed" )
+ PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor, &rMulti );
+ }
+ else
+ pPor->Paint( GetInfo() );
+
+ if( GetFnt()->IsURL() && pPor->InTxtGrp() )
+ GetInfo().NotifyURL( *pPor );
+
+ bFirst &= !pPor->GetLen();
+ if( pNext || !pPor->IsMarginPortion() )
+ pPor->Move( GetInfo() );
+
+ pPor = pNext;
+
+ // If there's no portion left, we go to the next line
+ if( !pPor && pLay->GetNext() )
+ {
+ pLay = pLay->GetNext();
+ pPor = pLay->GetFirstPortion();
+ bRest = pLay->IsRest();
+ aManip.SecondLine();
+
+ // delete underline font
+ delete GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( 0 );
+
+ if( rMulti.HasRotation() )
+ {
+ if( rMulti.IsRevers() )
+ {
+ nOfst += pLay->Height();
+ GetInfo().Y( nOldY - rMulti.GetAscent() );
+ }
+ else
+ {
+ nOfst -= pLay->Height();
+ GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
+ }
+ }
+ else if ( bHasGrid && rMulti.IsRuby() )
+ {
+ GetInfo().X( nTmpX );
+ if ( bRubyTop )
+ {
+ nOfst += nRubyHeight;
+ GetInfo().SetSnapToGrid( sal_True );
+ }
+ else
+ {
+ nOfst += pCurr->Height() - nRubyHeight;
+ GetInfo().SetSnapToGrid( sal_False );
+ }
+ } else
+ {
+ GetInfo().X( nTmpX );
+ // We switch to the baseline of the next inner line
+ nOfst += rMulti.GetRoot().Height();
+ }
+ }
+ } while( pPor );
+
+ if ( bRubyInGrid )
+ GetInfo().SetSnapToGrid( bOldGridModeAllowed );
+
+ // delete underline font
+ if ( ! rMulti.IsBidi() )
+ {
+ delete GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( 0 );
+ }
+
+ GetInfo().SetIdx( nOldIdx );
+ GetInfo().Y( nOldY );
+
+ if( rMulti.HasBrackets() )
+ {
+ xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
+ GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
+ SeekAndChg( GetInfo() );
+ GetInfo().X( nOldX );
+ ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(),
+ aManip.GetSpaceAdd(), sal_False );
+ GetInfo().SetIdx( nTmpOldIdx );
+ }
+ // Restore the saved values
+ GetInfo().X( nOldX );
+ GetInfo().SetLen( nOldLen );
+ delete pFontSave;
+ delete pTmpFnt;
+ SetPropFont( 0 );
+}
+
+sal_Bool lcl_ExtractFieldFollow( SwLineLayout* pLine, SwLinePortion* &rpFld )
+{
+ SwLinePortion* pLast = pLine;
+ rpFld = pLine->GetPortion();
+ while( rpFld && !rpFld->InFldGrp() )
+ {
+ pLast = rpFld;
+ rpFld = rpFld->GetPortion();
+ }
+ sal_Bool bRet = rpFld != 0;
+ if( bRet )
+ {
+ if( ((SwFldPortion*)rpFld)->IsFollow() )
+ {
+ rpFld->Truncate();
+ pLast->SetPortion( NULL );
+ }
+ else
+ rpFld = NULL;
+ }
+ pLine->Truncate();
+ return bRet;
+}
+
+/*----------------------------------------------------
+ * lcl_TruncateMultiPortion
+ * If a multi portion completely has to go to the
+ * next line, this function is called to trunctate
+ * the rest of the remaining multi portion
+ * --------------------------------------------------*/
+
+void lcl_TruncateMultiPortion( SwMultiPortion& rMulti, SwTxtFormatInfo& rInf,
+ xub_StrLen nStartIdx )
+{
+ rMulti.GetRoot().Truncate();
+ rMulti.GetRoot().SetLen(0);
+ rMulti.GetRoot().Width(0);
+// rMulti.CalcSize( *this, aInf );
+ if ( rMulti.GetRoot().GetNext() )
+ {
+ rMulti.GetRoot().GetNext()->Truncate();
+ rMulti.GetRoot().GetNext()->SetLen( 0 );
+ rMulti.GetRoot().GetNext()->Width( 0 );
+ }
+ rMulti.Width( 0 );
+ rMulti.SetLen(0);
+ rInf.SetIdx( nStartIdx );
+}
+
+/*-----------------------------------------------------------------------------
+ * SwTxtFormatter::BuildMultiPortion
+ * manages the formatting of a SwMultiPortion. External, for the calling
+ * function, it seems to be a normal Format-function, internal it is like a
+ * SwTxtFrm::_Format with multiple BuildPortions
+ *---------------------------------------------------------------------------*/
+
+BOOL SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
+ SwMultiPortion& rMulti )
+{
+ SwTwips nMaxWidth = rInf.Width();
+ KSHORT nOldX = 0;
+
+ if( rMulti.HasBrackets() )
+ {
+ xub_StrLen nOldIdx = rInf.GetIdx();
+ rInf.SetIdx( ((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart );
+ SeekAndChg( rInf );
+ nOldX = KSHORT(GetInfo().X());
+ ((SwDoubleLinePortion&)rMulti).FormatBrackets( rInf, nMaxWidth );
+ rInf.SetIdx( nOldIdx );
+ }
+
+ SeekAndChg( rInf );
+ SwFontSave *pFontSave;
+ if( rMulti.IsDouble() )
+ {
+ SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
+ if( rMulti.IsDouble() )
+ {
+ SetPropFont( 50 );
+ pTmpFnt->SetProportion( GetPropFont() );
+ }
+ pFontSave = new SwFontSave( rInf, pTmpFnt, this );
+ }
+ else
+ pFontSave = NULL;
+
+ SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
+ if ( rMulti.IsBidi() )
+ {
+ // set layout mode
+ aLayoutModeModifier.Modify( ! rInf.GetTxtFrm()->IsRightToLeft() );
+ }
+
+ SwTwips nTmpX = 0;
+
+ if( rMulti.HasRotation() )
+ {
+ // For nMaxWidth we take the height of the body frame.
+ // #i25067#: If the current frame is inside a table, we restrict
+ // nMaxWidth to the current frame height, unless the frame size
+ // attribute is set to variable size:
+
+ // We set nTmpX (which is used for portion calculating) to the
+ // current Y value
+ const SwPageFrm* pPage = pFrm->FindPageFrm();
+ ASSERT( pPage, "No page in frame!");
+ const SwLayoutFrm* pUpperFrm = pPage;
+
+ if ( pFrm->IsInTab() )
+ {
+ pUpperFrm = pFrm->GetUpper();
+ while ( pUpperFrm && !pUpperFrm->IsCellFrm() )
+ pUpperFrm = pUpperFrm->GetUpper();
+ ASSERT( pUpperFrm, "pFrm is in table but does not have an upper cell frame" )
+ const SwTableLine* pLine = ((SwRowFrm*)pUpperFrm->GetUpper())->GetTabLine();
+ const SwFmtFrmSize& rFrmFmtSize = pLine->GetFrmFmt()->GetFrmSize();
+ if ( ATT_VAR_SIZE == rFrmFmtSize.GetHeightSizeType() )
+ pUpperFrm = pPage;
+ }
+ if ( pUpperFrm == pPage && !pFrm->IsInFtn() )
+ pUpperFrm = pPage->FindBodyCont();
+
+ nMaxWidth = pUpperFrm ?
+ ( rInf.GetTxtFrm()->IsVertical() ?
+ pUpperFrm->Prt().Width() :
+ pUpperFrm->Prt().Height() ) :
+ USHRT_MAX;
+ }
+ else
+ nTmpX = rInf.X();
+
+ SwMultiPortion* pOldMulti = pMulti;
+
+ pMulti = &rMulti;
+ SwLineLayout *pOldCurr = pCurr;
+ xub_StrLen nOldStart = GetStart();
+ SwTwips nMinWidth = nTmpX + 1;
+ SwTwips nActWidth = nMaxWidth;
+ const xub_StrLen nStartIdx = rInf.GetIdx();
+ xub_StrLen nMultiLen = rMulti.GetLen();
+
+ SwLinePortion *pFirstRest;
+ SwLinePortion *pSecondRest;
+ if( rMulti.IsFormatted() )
+ {
+ if( !lcl_ExtractFieldFollow( &rMulti.GetRoot(), pFirstRest )
+ && rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
+ lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pFirstRest );
+ if( !rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
+ lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pSecondRest );
+ else
+ pSecondRest = NULL;
+ }
+ else
+ {
+ pFirstRest = rMulti.GetRoot().GetPortion();
+ pSecondRest = rMulti.GetRoot().GetNext() ?
+ rMulti.GetRoot().GetNext()->GetPortion() : NULL;
+ if( pFirstRest )
+ rMulti.GetRoot().SetPortion( NULL );
+ if( pSecondRest )
+ rMulti.GetRoot().GetNext()->SetPortion( NULL );
+ rMulti.SetFormatted();
+ nMultiLen = nMultiLen - rInf.GetIdx();
+ }
+
+ // save some values
+ const XubString* pOldTxt = &(rInf.GetTxt());
+ const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
+
+ XubString aMultiStr( rInf.GetTxt(), 0, nMultiLen + rInf.GetIdx() );
+ rInf.SetTxt( aMultiStr );
+ SwTxtFormatInfo aInf( rInf, rMulti.GetRoot(), nActWidth );
+ // Do we allow break cuts? The FirstMulti-Flag is evaluated during
+ // line break determination.
+ sal_Bool bFirstMulti = rInf.GetIdx() != rInf.GetLineStart();
+
+ SwLinePortion *pNextFirst = NULL;
+ SwLinePortion *pNextSecond = NULL;
+ BOOL bRet = FALSE;
+
+ GETGRID( pFrm->FindPageFrm() )
+ const sal_Bool bHasGrid = pGrid && GRID_LINES_CHARS == pGrid->GetGridType();
+
+ USHORT nGridWidth = 0;
+ USHORT nRubyHeight = 0;
+ sal_Bool bRubyTop = sal_False;
+
+ if ( bHasGrid )
+ {
+ nGridWidth = pGrid->GetBaseHeight();
+ nRubyHeight = pGrid->GetRubyHeight();
+ bRubyTop = ! pGrid->GetRubyTextBelow();
+ }
+
+ do
+ {
+ pCurr = &rMulti.GetRoot();
+ nStart = nStartIdx;
+ bRet = FALSE;
+ FormatReset( aInf );
+ aInf.X( nTmpX );
+ aInf.Width( KSHORT(nActWidth) );
+ aInf.RealWidth( KSHORT(nActWidth) );
+ aInf.SetFirstMulti( bFirstMulti );
+ aInf.SetNumDone( rInf.IsNumDone() );
+ aInf.SetFtnDone( rInf.IsFtnDone() );
+
+ if( pFirstRest )
+ {
+ ASSERT( pFirstRest->InFldGrp(), "BuildMulti: Fieldrest expected");
+ SwFldPortion *pFld =
+ ((SwFldPortion*)pFirstRest)->Clone(
+ ((SwFldPortion*)pFirstRest)->GetExp() );
+ pFld->SetFollow( sal_True );
+ aInf.SetRest( pFld );
+ }
+ aInf.SetRuby( rMulti.IsRuby() && rMulti.OnTop() );
+
+ // in grid mode we temporarily have to disable the grid for the ruby line
+ const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
+ if ( bHasGrid && aInf.IsRuby() && bRubyTop )
+ aInf.SetSnapToGrid( sal_False );
+
+ // If there's no more rubytext, then buildportion is forbidden
+ if( pFirstRest || !aInf.IsRuby() )
+ BuildPortions( aInf );
+
+ aInf.SetSnapToGrid( bOldGridModeAllowed );
+
+ rMulti.CalcSize( *this, aInf );
+ pCurr->SetRealHeight( pCurr->Height() );
+
+ if( rMulti.IsBidi() )
+ {
+ pNextFirst = aInf.GetRest();
+ break;
+ }
+
+ if( rMulti.HasRotation() && !rMulti.IsDouble() )
+ break;
+ // second line has to be formatted
+ else if( pCurr->GetLen()<nMultiLen || rMulti.IsRuby() || aInf.GetRest())
+ {
+ xub_StrLen nFirstLen = pCurr->GetLen();
+ delete pCurr->GetNext();
+ pCurr->SetNext( new SwLineLayout() );
+ pCurr = pCurr->GetNext();
+ nStart = aInf.GetIdx();
+ aInf.X( nTmpX );
+ SwTxtFormatInfo aTmp( aInf, *pCurr, nActWidth );
+ if( rMulti.IsRuby() )
+ {
+ aTmp.SetRuby( !rMulti.OnTop() );
+ pNextFirst = aInf.GetRest();
+ if( pSecondRest )
+ {
+ ASSERT( pSecondRest->InFldGrp(), "Fieldrest expected");
+ SwFldPortion *pFld = ((SwFldPortion*)pSecondRest)->Clone(
+ ((SwFldPortion*)pSecondRest)->GetExp() );
+ pFld->SetFollow( sal_True );
+ aTmp.SetRest( pFld );
+ }
+ if( !rMulti.OnTop() && nFirstLen < nMultiLen )
+ bRet = sal_True;
+ }
+ else
+ aTmp.SetRest( aInf.GetRest() );
+ aInf.SetRest( NULL );
+
+ // in grid mode we temporarily have to disable the grid for the ruby line
+ if ( bHasGrid && aTmp.IsRuby() && ! bRubyTop )
+ aTmp.SetSnapToGrid( sal_False );
+
+ BuildPortions( aTmp );
+
+ aTmp.SetSnapToGrid( bOldGridModeAllowed );
+
+ rMulti.CalcSize( *this, aInf );
+ rMulti.GetRoot().SetRealHeight( rMulti.GetRoot().Height() );
+ pCurr->SetRealHeight( pCurr->Height() );
+ if( rMulti.IsRuby() )
+ {
+ pNextSecond = aTmp.GetRest();
+ if( pNextFirst )
+ bRet = sal_True;
+ }
+ else
+ pNextFirst = aTmp.GetRest();
+ if( ( !aTmp.IsRuby() && nFirstLen + pCurr->GetLen() < nMultiLen )
+ || aTmp.GetRest() )
+ // our guess for width of multiportion was too small,
+ // text did not fit into multiportion
+ bRet = sal_True;
+ }
+ if( rMulti.IsRuby() )
+ break;
+ if( bRet )
+ {
+ // our guess for multiportion width was too small,
+ // we set min to act
+ nMinWidth = nActWidth;
+ nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
+ if ( nActWidth == nMaxWidth && rInf.GetLineStart() == rInf.GetIdx() )
+ // we have too less space, we must allow break cuts
+ // ( the first multi flag is considered during TxtPortion::_Format() )
+ bFirstMulti = sal_False;
+ if( nActWidth <= nMinWidth )
+ break;
+ }
+ else
+ {
+ // For Solaris, this optimisation can causes trouble:
+ // Setting this to the portion width ( = rMulti.Width() )
+ // can make GetTextBreak inside SwTxtGuess::Guess return to small
+ // values. Therefore we add some extra twips.
+ if( nActWidth > nTmpX + rMulti.Width() + 6 )
+ nActWidth = nTmpX + rMulti.Width() + 6;
+ nMaxWidth = nActWidth;
+ nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
+ if( nActWidth >= nMaxWidth )
+ break;
+ // we do not allow break cuts during formatting
+ bFirstMulti = sal_True;
+ }
+ delete pNextFirst;
+ pNextFirst = NULL;
+ } while ( TRUE );
+
+ pMulti = pOldMulti;
+
+ pCurr = pOldCurr;
+ nStart = nOldStart;
+ SetPropFont( 0 );
+
+ rMulti.SetLen( rMulti.GetRoot().GetLen() + ( rMulti.GetRoot().GetNext() ?
+ rMulti.GetRoot().GetNext()->GetLen() : 0 ) );
+
+ if( rMulti.IsDouble() )
+ {
+ ((SwDoubleLinePortion&)rMulti).CalcBlanks( rInf );
+ if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() )
+ {
+ SwLineLayout* pLine = &rMulti.GetRoot();
+ if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() > 0 )
+ {
+ rInf.SetIdx( nStartIdx + pLine->GetLen() );
+ pLine = pLine->GetNext();
+ }
+ if( pLine )
+ {
+ GetInfo().SetMulti( sal_True );
+ CalcNewBlock( pLine, NULL, rMulti.Width() );
+ GetInfo().SetMulti( sal_False );
+ }
+ rInf.SetIdx( nStartIdx );
+ }
+ if( ((SwDoubleLinePortion&)rMulti).GetBrackets() )
+ {
+ rMulti.Width( rMulti.Width() +
+ ((SwDoubleLinePortion&)rMulti).BracketWidth() );
+ GetInfo().X( nOldX );
+ }
+ }
+ else
+ {
+ rMulti.ActualizeTabulator();
+ if( rMulti.IsRuby() )
+ {
+ ((SwRubyPortion&)rMulti).Adjust( rInf );
+ ((SwRubyPortion&)rMulti).CalcRubyOffset();
+ }
+ }
+ if( rMulti.HasRotation() )
+ {
+ SwTwips nH = rMulti.Width();
+ SwTwips nAsc = rMulti.GetAscent() + ( nH - rMulti.Height() )/2;
+ if( nAsc > nH )
+ nAsc = nH;
+ else if( nAsc < 0 )
+ nAsc = 0;
+ rMulti.Width( rMulti.Height() );
+ rMulti.Height( KSHORT(nH) );
+ rMulti.SetAscent( KSHORT(nAsc) );
+ bRet = ( rInf.GetPos().X() + rMulti.Width() > rInf.Width() ) &&
+ nStartIdx != rInf.GetLineStart();
+ }
+ else if ( rMulti.IsBidi() )
+ {
+ bRet = rMulti.GetLen() < nMultiLen || pNextFirst;
+ }
+
+ // line break has to be performed!
+ if( bRet )
+ {
+ ASSERT( !pNextFirst || pNextFirst->InFldGrp(),
+ "BuildMultiPortion: Surprising restportion, field expected" );
+ SwMultiPortion *pTmp;
+ if( rMulti.IsDouble() )
+ pTmp = new SwDoubleLinePortion( ((SwDoubleLinePortion&)rMulti),
+ nMultiLen + rInf.GetIdx() );
+ else if( rMulti.IsRuby() )
+ {
+ ASSERT( !pNextSecond || pNextSecond->InFldGrp(),
+ "BuildMultiPortion: Surprising restportion, field expected" );
+
+ if ( rInf.GetIdx() == rInf.GetLineStart() )
+ {
+ // the ruby portion has to be split in two portions
+ pTmp = new SwRubyPortion( ((SwRubyPortion&)rMulti),
+ nMultiLen + rInf.GetIdx() );
+
+ if( pNextSecond )
+ {
+ pTmp->GetRoot().SetNext( new SwLineLayout() );
+ pTmp->GetRoot().GetNext()->SetPortion( pNextSecond );
+ }
+ pTmp->SetFollowFld();
+ }
+ else
+ {
+ // we try to keep our ruby portion together
+ lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
+ pTmp = 0;
+ }
+ }
+ else if( rMulti.HasRotation() )
+ {
+ // we try to keep our rotated portion together
+ lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
+ pTmp = new SwRotatedPortion( nMultiLen + rInf.GetIdx(),
+ rMulti.GetDirection() );
+ }
+ // during a recursion of BuildMultiPortions we may not build
+ // a new SwBidiPortion, this would cause a memory leak
+ else if( rMulti.IsBidi() && ! pMulti )
+ {
+ if ( ! rMulti.GetLen() )
+ lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
+
+ // If there is a HolePortion at the end of the bidi portion,
+ // it has to be moved behind the bidi portion. Otherwise
+ // the visual cursor travelling gets into trouble.
+ SwLineLayout& aRoot = rMulti.GetRoot();
+ SwLinePortion* pPor = aRoot.GetFirstPortion();
+ while ( pPor )
+ {
+ if ( pPor->GetPortion() && pPor->GetPortion()->IsHolePortion() )
+ {
+ SwLinePortion* pHolePor = pPor->GetPortion();
+ pPor->SetPortion( NULL );
+ aRoot.SetLen( aRoot.GetLen() - pHolePor->GetLen() );
+ rMulti.SetLen( rMulti.GetLen() - pHolePor->GetLen() );
+ rMulti.SetPortion( pHolePor );
+ break;
+ }
+ pPor = pPor->GetPortion();
+ }
+
+ pTmp = new SwBidiPortion( nMultiLen + rInf.GetIdx(),
+ ((SwBidiPortion&)rMulti).GetLevel() );
+ }
+ else
+ pTmp = NULL;
+
+ if ( ! rMulti.GetLen() && rInf.GetLast() )
+ {
+ SeekAndChgBefore( rInf );
+ rInf.GetLast()->FormatEOL( rInf );
+ }
+
+ if( pNextFirst && pTmp )
+ {
+ pTmp->SetFollowFld();
+ pTmp->GetRoot().SetPortion( pNextFirst );
+ }
+ else
+ // A follow field portion is still waiting. If nobody wants it,
+ // we delete it.
+ delete pNextFirst;
+
+ rInf.SetRest( pTmp );
+ }
+
+ rInf.SetTxt( *pOldTxt );
+ rInf.SetPaintOfst( nOldPaintOfst );
+ rInf.SetStop( aInf.IsStop() );
+ rInf.SetNumDone( sal_True );
+ rInf.SetFtnDone( sal_True );
+ SeekAndChg( rInf );
+ delete pFirstRest;
+ delete pSecondRest;
+ delete pFontSave;
+ return bRet;
+}
+
+/*-----------------08.11.00 09:29-------------------
+ * SwTxtFormatter::MakeRestPortion(..)
+ * When a fieldportion at the end of line breaks and needs a following
+ * fieldportion in the next line, then the "restportion" of the formatinfo
+ * has to be set. Normally this happens during the formatting of the first
+ * part of the fieldportion.
+ * But sometimes the formatting starts at the line with the following part,
+ * exspecally when the following part is on the next page.
+ * In this case the MakeRestPortion-function has to create the following part.
+ * The first parameter is the line that contains possibly a first part
+ * of a field. When the function finds such field part, it creates the right
+ * restportion. This may be a multiportion, e.g. if the field is surrounded by
+ * a doubleline- or ruby-portion.
+ * The second parameter is the start index of the line.
+ * --------------------------------------------------*/
+
+SwLinePortion* SwTxtFormatter::MakeRestPortion( const SwLineLayout* pLine,
+ xub_StrLen nPosition )
+{
+ if( !nPosition )
+ return NULL;
+ xub_StrLen nMultiPos = nPosition - pLine->GetLen();
+ const SwMultiPortion *pTmpMulti = NULL;
+ const SwMultiPortion *pHelpMulti = NULL;
+ const SwLinePortion* pPor = pLine->GetFirstPortion();
+ SwFldPortion *pFld = NULL;
+ while( pPor )
+ {
+ if( pPor->GetLen() )
+ {
+ if( !pHelpMulti )
+ {
+ nMultiPos = nMultiPos + pPor->GetLen();
+ pTmpMulti = NULL;
+ }
+ }
+ if( pPor->InFldGrp() )
+ {
+ if( !pHelpMulti )
+ pTmpMulti = NULL;
+ pFld = (SwFldPortion*)pPor;
+ }
+ else if( pPor->IsMultiPortion() )
+ {
+ ASSERT( !pHelpMulti || pHelpMulti->IsBidi(),
+ "Nested multiportions are forbidden." );
+
+ pFld = NULL;
+ pTmpMulti = (SwMultiPortion*)pPor;
+ }
+ pPor = pPor->GetPortion();
+ // If the last portion is a multi-portion, we enter it
+ // and look for a field portion inside.
+ // If we are already in a multiportion, we could change to the
+ // next line
+ if( !pPor && pTmpMulti )
+ {
+ if( pHelpMulti )
+ { // We're already inside the multiportion, let's take the second
+ // line, if we are in a double line portion
+ if( !pHelpMulti->IsRuby() )
+ pPor = pHelpMulti->GetRoot().GetNext();
+ pTmpMulti = NULL;
+ }
+ else
+ { // Now we enter a multiportion, in a ruby portion we take the
+ // main line, not the phonetic line, in a doublelineportion we
+ // starts with the first line.
+ pHelpMulti = pTmpMulti;
+ nMultiPos = nMultiPos - pHelpMulti->GetLen();
+ if( pHelpMulti->IsRuby() && pHelpMulti->OnTop() )
+ pPor = pHelpMulti->GetRoot().GetNext();
+ else
+ pPor = pHelpMulti->GetRoot().GetFirstPortion();
+ }
+ }
+ }
+ if( pFld && !pFld->HasFollow() )
+ pFld = NULL;
+
+ SwLinePortion *pRest = NULL;
+ if( pFld )
+ {
+ const SwTxtAttr *pHint = GetAttr( nPosition - 1 );
+ if( pHint && pHint->Which() == RES_TXTATR_FIELD )
+ {
+ pRest = NewFldPortion( GetInfo(), pHint );
+ if( pRest->InFldGrp() )
+ ((SwFldPortion*)pRest)->TakeNextOffset( pFld );
+ else
+ {
+ delete pRest;
+ pRest = NULL;
+ }
+ }
+ }
+ if( !pHelpMulti )
+ return pRest;
+
+ nPosition = nMultiPos + pHelpMulti->GetLen();
+ SwMultiCreator* pCreate = GetInfo().GetMultiCreator( nMultiPos, 0 );
+
+ if ( !pCreate )
+ {
+ ASSERT( !pHelpMulti->GetLen(), "Multiportion without attribut?" );
+ if ( nMultiPos )
+ --nMultiPos;
+ pCreate = GetInfo().GetMultiCreator( --nMultiPos, 0 );
+ }
+
+ if( pRest || nMultiPos > nPosition || ( pHelpMulti->IsRuby() &&
+ ((SwRubyPortion*)pHelpMulti)->GetRubyOffset() < STRING_LEN ) )
+ {
+ SwMultiPortion* pTmp;
+ if( pHelpMulti->IsDouble() )
+ pTmp = new SwDoubleLinePortion( *pCreate, nMultiPos );
+ else if( pHelpMulti->IsBidi() )
+ pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel );
+ else if( pHelpMulti->IsRuby() )
+ {
+ sal_Bool bRubyTop;
+ sal_Bool* pRubyPos = 0;
+
+ if ( GetInfo().SnapToGrid() )
+ {
+ GETGRID( pFrm->FindPageFrm() )
+ if ( pGrid )
+ {
+ bRubyTop = ! pGrid->GetRubyTextBelow();
+ pRubyPos = &bRubyTop;
+ }
+ }
+
+ pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(),
+ *pFrm->GetTxtNode()->getIDocumentSettingAccess(),
+ nMultiPos, ((SwRubyPortion*)pHelpMulti)->GetRubyOffset(),
+ pRubyPos );
+ }
+ else if( pHelpMulti->HasRotation() )
+ pTmp = new SwRotatedPortion( nMultiPos, pHelpMulti->GetDirection() );
+ else
+ {
+ delete pCreate;
+ return pRest;
+ }
+ delete pCreate;
+ pTmp->SetFollowFld();
+ if( pRest )
+ {
+ SwLineLayout *pLay = &pTmp->GetRoot();
+ if( pTmp->IsRuby() && pTmp->OnTop() )
+ {
+ pLay->SetNext( new SwLineLayout() );
+ pLay = pLay->GetNext();
+ }
+ pLay->SetPortion( pRest );
+ }
+ return pTmp;
+ }
+ return pRest;
+}
+
+
+
+/*-----------------23.10.00 10:47-------------------
+ * SwTxtCursorSave notes the start and current line of a SwTxtCursor,
+ * sets them to the values for GetCrsrOfst inside a multiportion
+ * and restores them in the destructor.
+ * --------------------------------------------------*/
+
+SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor* pTxtCursor,
+ SwMultiPortion* pMulti,
+ SwTwips nY,
+ USHORT& nX,
+ xub_StrLen nCurrStart,
+ long nSpaceAdd )
+{
+ pTxtCrsr = pTxtCursor;
+ nStart = pTxtCursor->nStart;
+ pTxtCursor->nStart = nCurrStart;
+ pCurr = pTxtCursor->pCurr;
+ pTxtCursor->pCurr = &pMulti->GetRoot();
+ while( pTxtCursor->Y() + pTxtCursor->GetLineHeight() < nY &&
+ pTxtCursor->Next() )
+ ; // nothing
+ nWidth = pTxtCursor->pCurr->Width();
+ nOldProp = pTxtCursor->GetPropFont();
+
+ if ( pMulti->IsDouble() || pMulti->IsBidi() )
+ {
+ bSpaceChg = pMulti->ChgSpaceAdd( pTxtCursor->pCurr, nSpaceAdd );
+
+ USHORT nSpaceCnt;
+ if ( pMulti->IsDouble() )
+ {
+ pTxtCursor->SetPropFont( 50 );
+ nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
+ }
+ else
+ {
+ const xub_StrLen nOldIdx = pTxtCursor->GetInfo().GetIdx();
+ pTxtCursor->GetInfo().SetIdx ( nCurrStart );
+ nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
+ pTxtCursor->GetInfo().SetIdx ( nOldIdx );
+ }
+
+ if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
+ pTxtCursor->pCurr->Width( static_cast<USHORT>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
+
+ // For a BidiPortion we have to calculate the offset from the
+ // end of the portion
+ if ( nX && pMulti->IsBidi() )
+ nX = pTxtCursor->pCurr->Width() - nX;
+ }
+ else
+ bSpaceChg = sal_False;
+}
+
+SwTxtCursorSave::~SwTxtCursorSave()
+{
+ if( bSpaceChg )
+ SwDoubleLinePortion::ResetSpaceAdd( pTxtCrsr->pCurr );
+ pTxtCrsr->pCurr->Width( KSHORT(nWidth) );
+ pTxtCrsr->pCurr = pCurr;
+ pTxtCrsr->nStart = nStart;
+ pTxtCrsr->SetPropFont( nOldProp );
+}
+
diff --git a/sw/source/core/text/pormulti.hxx b/sw/source/core/text/pormulti.hxx
new file mode 100644
index 000000000000..a1e89f838b54
--- /dev/null
+++ b/sw/source/core/text/pormulti.hxx
@@ -0,0 +1,268 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORMULTI_HXX
+#define _PORMULTI_HXX
+
+#include "porlay.hxx"
+#include "porexp.hxx"
+
+class SwTxtFormatInfo;
+class SwFldPortion;
+class SwTxtCursor;
+class SwLineLayout;
+class SwTxtPaintInfo;
+class SwTxtAttr;
+class SfxPoolItem;
+class SwFont;
+
+/*-----------------02.02.01 15:01-------------------
+ * SwMultiCreator is a small structur to create a multiportion.
+ * It contains the kind of multiportion and a textattribute
+ * or a poolitem.
+ * The GetMultiCreator-function fills this structur and
+ * the Ctor of the SwMultiPortion uses it.
+ * --------------------------------------------------*/
+
+#define SW_MC_DOUBLE 0
+#define SW_MC_RUBY 1
+#define SW_MC_ROTATE 2
+#define SW_MC_BIDI 3
+
+struct SwMultiCreator
+{
+ const SwTxtAttr* pAttr;
+ const SfxPoolItem* pItem;
+ BYTE nId;
+ BYTE nLevel;
+};
+
+/*-----------------25.10.00 16:19-------------------
+ * A two-line-portion (SwMultiPortion) could have surrounding brackets,
+ * in this case the structur SwBracket will be used.
+ * --------------------------------------------------*/
+
+struct SwBracket
+{
+ xub_StrLen nStart; // Start of text attribute determins the font
+ KSHORT nAscent; // Ascent of the brackets
+ KSHORT nHeight; // Height of them
+ KSHORT nPreWidth; // Width of the opening bracket
+ KSHORT nPostWidth; // Width of the closing bracket
+ sal_Unicode cPre; // Initial character, e.g. '('
+ sal_Unicode cPost; // Final character, e.g. ')'
+ BYTE nPreScript; // Script of the initial character
+ BYTE nPostScript; // Script of the final character
+};
+
+/*-----------------16.10.00 12:45-------------------
+ * The SwMultiPortion is line portion inside a line portion,
+ * it's a group of portions,
+ * e.g. a double line portion in a line
+ * or phonetics (ruby)
+ * or combined characters
+ * or a rotated portion.
+ * --------------------------------------------------*/
+
+class SwMultiPortion : public SwLinePortion
+{
+ SwLineLayout aRoot; // One or more lines
+ SwFldPortion *pFldRest; // Field rest from the previous line
+ sal_Bool bTab1 :1; // First line tabulator
+ sal_Bool bTab2 :1; // Second line includes tabulator
+ sal_Bool bDouble :1; // Double line
+ sal_Bool bRuby :1; // Phonetics
+ sal_Bool bBidi :1;
+ sal_Bool bTop :1; // Phonetic position
+ sal_Bool bFormatted :1; // Already formatted
+ sal_Bool bFollowFld :1; // Field follow inside
+ sal_uInt8 nDirection:2; // Direction (0/90/180/270 degrees)
+ sal_Bool bFlyInCntnt:1; // Fly as character inside
+protected:
+ SwMultiPortion( xub_StrLen nEnd ) : pFldRest( 0 ), bTab1( sal_False ),
+ bTab2( sal_False ), bDouble( sal_False ), bRuby( sal_False ),
+ bBidi( sal_False ), bFormatted( sal_False ), bFollowFld( sal_False ),
+ nDirection( 0 ), bFlyInCntnt( sal_False )
+ { SetWhichPor( POR_MULTI ); SetLen( nEnd ); }
+ inline void SetDouble() { bDouble = sal_True; }
+ inline void SetRuby() { bRuby = sal_True; }
+ inline void SetBidi() { bBidi = sal_True; }
+ inline void SetTop( sal_Bool bNew ) { bTop = bNew; }
+ inline void SetTab1( sal_Bool bNew ) { bTab1 = bNew; }
+ inline void SetTab2( sal_Bool bNew ) { bTab2 = bNew; }
+ inline void SetDirection( sal_uInt8 nNew ) { nDirection = nNew; }
+ inline sal_Bool GetTab1() const { return bTab1; }
+ inline sal_Bool GetTab2() const { return bTab2; }
+public:
+ ~SwMultiPortion();
+ const SwLineLayout& GetRoot() const { return aRoot; }
+ SwLineLayout& GetRoot() { return aRoot; }
+ SwFldPortion* GetFldRest() { return pFldRest; }
+ void SetFldRest( SwFldPortion* pNew ) { pFldRest = pNew; }
+
+ inline sal_Bool HasTabulator() const { return bTab1 || bTab2; }
+ inline sal_Bool IsFormatted() const { return bFormatted; }
+ inline void SetFormatted() { bFormatted = sal_True; }
+ inline sal_Bool IsFollowFld() const { return bFollowFld; }
+ inline void SetFollowFld() { bFollowFld = sal_True; }
+ inline sal_Bool HasFlyInCntnt() const { return bFlyInCntnt; }
+ inline void SetFlyInCntnt( sal_Bool bNew ) { bFlyInCntnt = bNew; }
+ inline sal_Bool IsDouble() const { return bDouble; }
+ inline sal_Bool IsRuby() const { return bRuby; }
+ inline sal_Bool IsBidi() const { return bBidi; }
+ inline sal_Bool OnTop() const { return bTop; }
+ void ActualizeTabulator();
+
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual long CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const;
+ virtual sal_Bool ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const;
+
+ // Summarize the internal lines to calculate the (external) size
+ void CalcSize( SwTxtFormatter& rLine, SwTxtFormatInfo &rInf );
+
+ inline sal_Bool HasBrackets() const;
+ inline sal_Bool HasRotation() const { return 0 != (1 & nDirection); }
+ inline sal_Bool IsRevers() const { return 0 != (2 & nDirection); }
+ inline sal_uInt8 GetDirection() const { return nDirection; }
+ inline USHORT GetFontRotation() const
+ { return ( HasRotation() ? ( IsRevers() ? 2700 : 900 ) : 0 ); }
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+class SwDoubleLinePortion : public SwMultiPortion
+{
+ SwBracket* pBracket; // Surrounding brackets
+ SwTwips nLineDiff; // Difference of the width of the both lines
+ xub_StrLen nBlank1; // Number of blanks in the first line
+ xub_StrLen nBlank2; // Number of blanks in the second line
+public:
+ SwDoubleLinePortion( SwDoubleLinePortion& rDouble, xub_StrLen nEnd );
+ SwDoubleLinePortion( const SwMultiCreator& rCreate, xub_StrLen nEnd );
+ ~SwDoubleLinePortion();
+
+ inline SwBracket* GetBrackets() const { return pBracket; }
+ void SetBrackets( const SwDoubleLinePortion& rDouble );
+ void PaintBracket( SwTxtPaintInfo& rInf, long nSpaceAdd, sal_Bool bOpen ) const;
+ void FormatBrackets( SwTxtFormatInfo &rInf, SwTwips& nMaxWidth );
+ inline KSHORT PreWidth() const { return pBracket->nPreWidth; };
+ inline KSHORT PostWidth() const { return pBracket->nPostWidth; }
+ inline void ClearBrackets()
+ { pBracket->nPreWidth = pBracket->nPostWidth=0; Width( 0 ); }
+ inline KSHORT BracketWidth(){ return PreWidth() + PostWidth(); }
+
+ void CalcBlanks( SwTxtFormatInfo &rInf );
+ static void ResetSpaceAdd( SwLineLayout* pCurr );
+ inline SwTwips GetLineDiff() const { return nLineDiff; }
+ inline xub_StrLen GetSpaceCnt() const
+ { return ( nLineDiff < 0 ) ? nBlank2 : nBlank1; }
+ inline xub_StrLen GetSmallerSpaceCnt() const
+ { return ( nLineDiff < 0 ) ? nBlank1 : nBlank2; }
+ inline xub_StrLen GetBlank1() const { return nBlank1; }
+ inline xub_StrLen GetBlank2() const { return nBlank2; }
+
+ virtual long CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const;
+ virtual sal_Bool ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const;
+};
+
+class SwRubyPortion : public SwMultiPortion
+{
+ xub_StrLen nRubyOffset;
+ USHORT nAdjustment;
+ void _Adjust( SwTxtFormatInfo &rInf);
+public:
+ SwRubyPortion( const SwRubyPortion& rRuby, xub_StrLen nEnd );
+
+ SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt,
+ const IDocumentSettingAccess& rIDocumentSettingAccess,
+ xub_StrLen nEnd, xub_StrLen nOffs,
+ const sal_Bool* pForceRubyPos );
+
+ void CalcRubyOffset();
+ inline void Adjust( SwTxtFormatInfo &rInf )
+ { if(nAdjustment && GetRoot().GetNext()) _Adjust(rInf); }
+ inline USHORT GetAdjustment() const { return nAdjustment; }
+ inline xub_StrLen GetRubyOffset() const { return nRubyOffset; }
+};
+
+class SwRotatedPortion : public SwMultiPortion
+{
+public:
+ SwRotatedPortion( xub_StrLen nEnd, sal_uInt8 nDir = 1 )
+ : SwMultiPortion( nEnd ) { SetDirection( nDir ); }
+ SwRotatedPortion( const SwMultiCreator& rCreate, xub_StrLen nEnd,
+ sal_Bool bRTL );
+};
+
+class SwBidiPortion : public SwMultiPortion
+{
+ BYTE nLevel;
+
+public:
+ SwBidiPortion( xub_StrLen nEnd, BYTE nLv );
+
+ inline BYTE GetLevel() const { return nLevel; }
+ // Get number of blanks for justified alignment
+ xub_StrLen GetSpaceCnt( const SwTxtSizeInfo &rInf ) const;
+ // Calculates extra spacing based on number of blanks
+ virtual long CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const;
+ // Manipulate the spacing array at pCurr
+ virtual sal_Bool ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const;
+};
+
+// For cursor travelling in multiportions
+
+class SwTxtCursorSave
+{
+ SwTxtCursor* pTxtCrsr;
+ SwLineLayout* pCurr;
+ SwTwips nWidth;
+ xub_StrLen nStart;
+ BYTE nOldProp;
+ sal_Bool bSpaceChg;
+public:
+ SwTxtCursorSave( SwTxtCursor* pTxtCursor, SwMultiPortion* pMulti,
+ SwTwips nY, USHORT& nX, xub_StrLen nCurrStart, long nSpaceAdd );
+ ~SwTxtCursorSave();
+};
+
+/*************************************************************************
+ * inline - Implementations
+ *************************************************************************/
+
+inline sal_Bool SwMultiPortion::HasBrackets() const
+{
+ return sal::static_int_cast< sal_Bool >( IsDouble() ?
+ 0 != ((SwDoubleLinePortion*)this)->GetBrackets() :
+ sal_False );
+}
+
+CLASSIO( SwMultiPortion )
+
+#endif
diff --git a/sw/source/core/text/porref.cxx b/sw/source/core/text/porref.cxx
new file mode 100644
index 000000000000..6794d7c1ed0d
--- /dev/null
+++ b/sw/source/core/text/porref.cxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * 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 <SwPortionHandler.hxx>
+#include "viewopt.hxx" // SwViewOptions
+
+#include "txtcfg.hxx"
+#include "porref.hxx"
+#include "inftxt.hxx" // GetTxtSize()
+
+/*************************************************************************
+ * virtual SwRefPortion::Paint()
+ *************************************************************************/
+
+void SwRefPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ {
+ rInf.DrawViewOpt( *this, POR_REF );
+ SwTxtPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * class SwIsoRefPortion
+ *************************************************************************/
+
+SwLinePortion *SwIsoRefPortion::Compress() { return this; }
+
+SwIsoRefPortion::SwIsoRefPortion() : nViewWidth(0)
+{
+ SetLen(1);
+ SetWhichPor( POR_ISOREF );
+}
+
+/*************************************************************************
+ * virtual SwIsoRefPortion::GetViewWidth()
+ *************************************************************************/
+
+KSHORT SwIsoRefPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
+ // Moment errechnet werden:
+ SwIsoRefPortion* pThis = (SwIsoRefPortion*)this;
+ if( !Width() && rInf.OnWin() && SwViewOption::IsFieldShadings() &&
+ !rInf.GetOpt().IsReadonly() && !rInf.GetOpt().IsPagePreview() )
+ {
+ if( !nViewWidth )
+ pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width();
+ }
+ else
+ pThis->nViewWidth = 0;
+ return nViewWidth;
+}
+
+/*************************************************************************
+ * virtual SwIsoRefPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwIsoRefPortion::Format( SwTxtFormatInfo &rInf )
+{
+ const sal_Bool bFull = SwLinePortion::Format( rInf );
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwIsoRefPortion::Paint()
+ *************************************************************************/
+
+void SwIsoRefPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ rInf.DrawViewOpt( *this, POR_REF );
+}
+
+/*************************************************************************
+ * virtual SwIsoRefPortion::HandlePortion()
+ *************************************************************************/
+
+void SwIsoRefPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString;
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
+
+
diff --git a/sw/source/core/text/porref.hxx b/sw/source/core/text/porref.hxx
new file mode 100644
index 000000000000..aee1e46c66ad
--- /dev/null
+++ b/sw/source/core/text/porref.hxx
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORREF_HXX
+#define _PORREF_HXX
+
+#include "portxt.hxx"
+
+/*************************************************************************
+ * class SwRefPortion
+ *************************************************************************/
+
+class SwRefPortion : public SwTxtPortion
+{
+public:
+ inline SwRefPortion(){ SetWhichPor( POR_REF ); }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwIsoRefPortion
+ *************************************************************************/
+
+class SwIsoRefPortion : public SwRefPortion
+{
+ KSHORT nViewWidth;
+
+public:
+ SwIsoRefPortion();
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual SwLinePortion *Compress();
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * inline - Implementations
+ *************************************************************************/
+
+CLASSIO( SwRefPortion )
+CLASSIO( SwIsoRefPortion )
+
+
+#endif
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
new file mode 100644
index 000000000000..3bc8e566b335
--- /dev/null
+++ b/sw/source/core/text/porrst.cxx
@@ -0,0 +1,579 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+#include <sfx2/printer.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/adjitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/pgrditem.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <viewsh.hxx> // ViewShell
+#include <viewopt.hxx>
+#include <ndtxt.hxx> // SwTxtNode
+#include <pagefrm.hxx> // SwPageFrm
+#include <paratr.hxx>
+#include <SwPortionHandler.hxx>
+#include <txtcfg.hxx>
+#include <porrst.hxx>
+#include <inftxt.hxx>
+#include <txtpaint.hxx> // ClipVout
+#include <swfntcch.hxx> // SwFontAccess
+#include <tgrditem.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <frmatr.hxx>
+#include <redlnitr.hxx> // SwRedlineItr
+#include <porfly.hxx> // SwFlyPortion
+#include <atrhndl.hxx>
+
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentDeviceAccess.hxx>
+
+/*************************************************************************
+ * class SwTmpEndPortion
+ *************************************************************************/
+
+SwTmpEndPortion::SwTmpEndPortion( const SwLinePortion &rPortion )
+{
+ Height( rPortion.Height() );
+ SetAscent( rPortion.GetAscent() );
+ SetWhichPor( POR_TMPEND );
+}
+
+/*************************************************************************
+ * virtual SwTmpEndPortion::Paint()
+ *************************************************************************/
+
+void SwTmpEndPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( rInf.OnWin() && rInf.GetOpt().IsParagraph() )
+ {
+ SwDefFontSave aSave( rInf );
+ const XubString aTmp( CH_PAR );
+ rInf.DrawText( aTmp, *this );
+ }
+}
+
+/*************************************************************************
+ * class SwBreakPortion
+ *************************************************************************/
+SwBreakPortion::SwBreakPortion( const SwLinePortion &rPortion )
+ : SwLinePortion( rPortion )
+{
+ nLineLength = 1;
+ SetWhichPor( POR_BRK );
+}
+
+xub_StrLen SwBreakPortion::GetCrsrOfst( const KSHORT ) const
+{ return 0; }
+
+KSHORT SwBreakPortion::GetViewWidth( const SwTxtSizeInfo & ) const
+{ return 0; }
+
+SwLinePortion *SwBreakPortion::Compress()
+{ return (GetPortion() && GetPortion()->InTxtGrp() ? 0 : this); }
+
+void SwBreakPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( rInf.OnWin() && rInf.GetOpt().IsLineBreak() )
+ rInf.DrawLineBreak( *this );
+}
+
+/*************************************************************************
+ * virtual SwBreakPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwBreakPortion::Format( SwTxtFormatInfo &rInf )
+{
+ const SwLinePortion *pRoot = rInf.GetRoot();
+ Width( 0 );
+ Height( pRoot->Height() );
+ SetAscent( pRoot->GetAscent() );
+ if ( rInf.GetIdx()+1 == rInf.GetTxt().Len() )
+ rInf.SetNewLine( sal_True );
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwBreakPortion::HandlePortion()
+ *************************************************************************/
+
+void SwBreakPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Text( GetLen(), GetWhichPor() );
+}
+
+
+SwKernPortion::SwKernPortion( SwLinePortion &rPortion, short nKrn,
+ sal_Bool bBG, sal_Bool bGK ) :
+ nKern( nKrn ), bBackground( bBG ), bGridKern( bGK )
+{
+ Height( rPortion.Height() );
+ SetAscent( rPortion.GetAscent() );
+ nLineLength = 0;
+ SetWhichPor( POR_KERN );
+ if( nKern > 0 )
+ Width( nKern );
+ rPortion.Insert( this );
+}
+
+SwKernPortion::SwKernPortion( const SwLinePortion& rPortion ) :
+ nKern( 0 ), bBackground( sal_False ), bGridKern( sal_True )
+{
+ Height( rPortion.Height() );
+ SetAscent( rPortion.GetAscent() );
+
+ nLineLength = 0;
+ SetWhichPor( POR_KERN );
+}
+
+void SwKernPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ {
+ // bBackground is set for Kerning Portions between two fields
+ if ( bBackground )
+ rInf.DrawViewOpt( *this, POR_FLD );
+
+ rInf.DrawBackBrush( *this );
+
+ // do we have to repaint a post it portion?
+ if( rInf.OnWin() && pPortion && !pPortion->Width() )
+ pPortion->PrePaint( rInf, this );
+
+ if( rInf.GetFont()->IsPaintBlank() )
+ {
+ static sal_Char __READONLY_DATA sDoubleSpace[] = " ";
+ XubString aTxtDouble( sDoubleSpace, RTL_TEXTENCODING_MS_1252 );
+ // --> FME 2006-07-12 #b6439097#
+ SwRect aClipRect;
+ rInf.CalcRect( *this, &aClipRect, 0 );
+ SwSaveClip aClip( (OutputDevice*)rInf.GetOut() );
+ aClip.ChgClip( aClipRect, 0 );
+ // <--
+ rInf.DrawText( aTxtDouble, *this, 0, 2, sal_True );
+ }
+ }
+}
+
+void SwKernPortion::FormatEOL( SwTxtFormatInfo &rInf )
+{
+ if ( bGridKern )
+ return;
+
+ if( rInf.GetLast() == this )
+ rInf.SetLast( FindPrevPortion( rInf.GetRoot() ) );
+ if( nKern < 0 )
+ Width( -nKern );
+ else
+ Width( 0 );
+ rInf.GetLast()->FormatEOL( rInf );
+}
+
+SwArrowPortion::SwArrowPortion( const SwLinePortion &rPortion ) :
+ bLeft( sal_True )
+{
+ Height( rPortion.Height() );
+ SetAscent( rPortion.GetAscent() );
+ nLineLength = 0;
+ SetWhichPor( POR_ARROW );
+}
+
+SwArrowPortion::SwArrowPortion( const SwTxtPaintInfo &rInf )
+ : bLeft( sal_False )
+{
+ Height( (USHORT)(rInf.GetTxtFrm()->Prt().Height()) );
+ aPos.X() = rInf.GetTxtFrm()->Frm().Left() +
+ rInf.GetTxtFrm()->Prt().Right();
+ aPos.Y() = rInf.GetTxtFrm()->Frm().Top() +
+ rInf.GetTxtFrm()->Prt().Bottom();
+ SetWhichPor( POR_ARROW );
+}
+
+void SwArrowPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ ((SwArrowPortion*)this)->aPos = rInf.GetPos();
+}
+
+SwLinePortion *SwArrowPortion::Compress() { return this; }
+
+SwTwips SwTxtFrm::EmptyHeight() const
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::EmptyHeight with swapped frame" );
+
+ SwFont *pFnt;
+ const SwTxtNode& rTxtNode = *GetTxtNode();
+ const IDocumentSettingAccess* pIDSA = rTxtNode.getIDocumentSettingAccess();
+ ViewShell *pSh = GetShell();
+ if ( rTxtNode.HasSwAttrSet() )
+ {
+ const SwAttrSet *pAttrSet = &( rTxtNode.GetSwAttrSet() );
+ pFnt = new SwFont( pAttrSet, pIDSA );
+ }
+ else
+ {
+ SwFontAccess aFontAccess( &rTxtNode.GetAnyFmtColl(), pSh);
+ pFnt = new SwFont( *aFontAccess.Get()->GetFont() );
+ pFnt->ChkMagic( pSh, pFnt->GetActual() );
+ }
+
+ if ( IsVertical() )
+ pFnt->SetVertical( 2700 );
+
+ OutputDevice* pOut = pSh ? pSh->GetOut() : 0;
+ if ( !pOut || !pIDSA->get(IDocumentSettingAccess::BROWSE_MODE) ||
+ ( pSh->GetViewOptions()->IsPrtFormat() ) )
+ {
+ pOut = rTxtNode.getIDocumentDeviceAccess()->getReferenceDevice(true);
+ }
+
+ const IDocumentRedlineAccess* pIDRA = rTxtNode.getIDocumentRedlineAccess();
+ if( IDocumentRedlineAccess::IsShowChanges( pIDRA->GetRedlineMode() ) )
+ {
+ MSHORT nRedlPos = pIDRA->GetRedlinePos( rTxtNode, USHRT_MAX );
+ if( MSHRT_MAX != nRedlPos )
+ {
+ SwAttrHandler aAttrHandler;
+ aAttrHandler.Init( GetTxtNode()->GetSwAttrSet(),
+ *GetTxtNode()->getIDocumentSettingAccess(), NULL );
+ SwRedlineItr aRedln( rTxtNode, *pFnt, aAttrHandler,
+ nRedlPos, sal_True );
+ }
+ }
+
+ SwTwips nRet;
+ if( !pOut )
+ nRet = IsVertical() ?
+ Prt().SSize().Width() + 1 :
+ Prt().SSize().Height() + 1;
+ else
+ {
+ pFnt->SetFntChg( sal_True );
+ pFnt->ChgPhysFnt( pSh, *pOut );
+ nRet = pFnt->GetHeight( pSh, *pOut );
+ }
+ delete pFnt;
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::FormatEmpty()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::FormatEmpty()
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::FormatEmpty with swapped frame" );
+
+ if ( HasFollow() || GetTxtNode()->GetpSwpHints() ||
+ 0 != GetTxtNode()->GetNumRule() ||
+ GetTxtNode()->HasHiddenCharAttribute( true ) ||
+ IsInFtn() || ( HasPara() && GetPara()->IsPrepMustFit() ) )
+ return sal_False;
+ const SwAttrSet& aSet = GetTxtNode()->GetSwAttrSet();
+ const SvxAdjust nAdjust = aSet.GetAdjust().GetAdjust();
+ if( ( ( ! IsRightToLeft() && ( SVX_ADJUST_LEFT != nAdjust ) ) ||
+ ( IsRightToLeft() && ( SVX_ADJUST_RIGHT != nAdjust ) ) ) ||
+ aSet.GetRegister().GetValue() )
+ return sal_False;
+ const SvxLineSpacingItem &rSpacing = aSet.GetLineSpacing();
+ if( SVX_LINE_SPACE_MIN == rSpacing.GetLineSpaceRule() ||
+ SVX_LINE_SPACE_FIX == rSpacing.GetLineSpaceRule() ||
+ aSet.GetLRSpace().IsAutoFirst() )
+ return sal_False;
+ else
+ {
+ SwTxtFly aTxtFly( this );
+ SwRect aRect;
+ sal_Bool bFirstFlyCheck = 0 != Prt().Height();
+ if ( bFirstFlyCheck &&
+ aTxtFly.IsOn() && aTxtFly.IsAnyObj( aRect ) )
+ return sal_False;
+ else
+ {
+ SwTwips nHeight = EmptyHeight();
+
+ if ( GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() &&
+ IsInDocBody() )
+ {
+ GETGRID( FindPageFrm() )
+ if ( pGrid )
+ nHeight = pGrid->GetBaseHeight() + pGrid->GetRubyHeight();
+ }
+
+ SWRECTFN( this )
+ const SwTwips nChg = nHeight - (Prt().*fnRect->fnGetHeight)();
+
+ if( !nChg )
+ SetUndersized( sal_False );
+ AdjustFrm( nChg );
+
+ if( HasBlinkPor() )
+ {
+ ClearPara();
+ ResetBlinkPor();
+ }
+ SetCacheIdx( MSHRT_MAX );
+ if( !IsEmpty() )
+ {
+ SetEmpty( sal_True );
+ SetCompletePaint();
+ }
+ if( !bFirstFlyCheck &&
+ aTxtFly.IsOn() && aTxtFly.IsAnyObj( aRect ) )
+ return sal_False;
+
+ // --> OD 2004-11-17 #i35635# - call method <HideAndShowObjects()>
+ // to assure that objects anchored at the empty paragraph are
+ // correctly visible resp. invisible.
+ HideAndShowObjects();
+ // <--
+ return sal_True;
+ }
+ }
+}
+
+sal_Bool SwTxtFrm::FillRegister( SwTwips& rRegStart, KSHORT& rRegDiff )
+{
+ const SwFrm *pFrm = this;
+ rRegDiff = 0;
+ while( !( ( FRM_BODY | FRM_FLY )
+ & pFrm->GetType() ) && pFrm->GetUpper() )
+ pFrm = pFrm->GetUpper();
+ if( ( FRM_BODY| FRM_FLY ) & pFrm->GetType() )
+ {
+ SWRECTFN( pFrm )
+ rRegStart = (pFrm->*fnRect->fnGetPrtTop)();
+ pFrm = pFrm->FindPageFrm();
+ if( pFrm->IsPageFrm() )
+ {
+ SwPageDesc* pDesc = ((SwPageFrm*)pFrm)->FindPageDesc();
+ if( pDesc )
+ {
+ rRegDiff = pDesc->GetRegHeight();
+ if( !rRegDiff )
+ {
+ const SwTxtFmtColl *pFmt = pDesc->GetRegisterFmtColl();
+ if( pFmt )
+ {
+ const SvxLineSpacingItem &rSpace = pFmt->GetLineSpacing();
+ if( SVX_LINE_SPACE_FIX == rSpace.GetLineSpaceRule() )
+ {
+ rRegDiff = rSpace.GetLineHeight();
+ pDesc->SetRegHeight( rRegDiff );
+ pDesc->SetRegAscent( ( 4 * rRegDiff ) / 5 );
+ }
+ else
+ {
+ ViewShell *pSh = GetShell();
+ SwFontAccess aFontAccess( pFmt, pSh );
+ SwFont aFnt( *aFontAccess.Get()->GetFont() );
+
+ OutputDevice *pOut = 0;
+ if( !GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ||
+ (pSh && pSh->GetViewOptions()->IsPrtFormat()) )
+ pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
+
+ if( pSh && !pOut )
+ pOut = pSh->GetWin();
+
+ if( !pOut )
+ pOut = GetpApp()->GetDefaultDevice();
+
+ MapMode aOldMap( pOut->GetMapMode() );
+ pOut->SetMapMode( MapMode( MAP_TWIP ) );
+
+ aFnt.ChgFnt( pSh, *pOut );
+ rRegDiff = aFnt.GetHeight( pSh, *pOut );
+ KSHORT nNettoHeight = rRegDiff;
+
+ switch( rSpace.GetLineSpaceRule() )
+ {
+ case SVX_LINE_SPACE_AUTO:
+ break;
+ case SVX_LINE_SPACE_MIN:
+ {
+ if( rRegDiff < KSHORT( rSpace.GetLineHeight() ) )
+ rRegDiff = rSpace.GetLineHeight();
+ break;
+ }
+ default: ASSERT(
+ sal_False, ": unknown LineSpaceRule" );
+ }
+ switch( rSpace.GetInterLineSpaceRule() )
+ {
+ case SVX_INTER_LINE_SPACE_OFF:
+ break;
+ case SVX_INTER_LINE_SPACE_PROP:
+ {
+ long nTmp = rSpace.GetPropLineSpace();
+ if( nTmp < 50 )
+ nTmp = nTmp ? 50 : 100;
+ nTmp *= rRegDiff;
+ nTmp /= 100;
+ if( !nTmp )
+ ++nTmp;
+ rRegDiff = (KSHORT)nTmp;
+ nNettoHeight = rRegDiff;
+ break;
+ }
+ case SVX_INTER_LINE_SPACE_FIX:
+ {
+ rRegDiff = rRegDiff + rSpace.GetInterLineSpace();
+ nNettoHeight = rRegDiff;
+ break;
+ }
+ default: ASSERT( sal_False, ": unknown InterLineSpaceRule" );
+ }
+ pDesc->SetRegHeight( rRegDiff );
+ pDesc->SetRegAscent( rRegDiff - nNettoHeight +
+ aFnt.GetAscent( pSh, *pOut ) );
+ pOut->SetMapMode( aOldMap );
+ }
+ }
+ }
+ const long nTmpDiff = pDesc->GetRegAscent() - rRegDiff;
+ if ( bVert )
+ rRegStart -= nTmpDiff;
+ else
+ rRegStart += nTmpDiff;
+ }
+ }
+ }
+ return ( 0 != rRegDiff );
+}
+
+/*************************************************************************
+ * virtual SwHiddenTextPortion::Paint()
+ *************************************************************************/
+
+void SwHiddenTextPortion::Paint( const SwTxtPaintInfo & rInf) const
+{
+ (void)rInf;
+#if OSL_DEBUG_LEVEL > 1
+ OutputDevice* pOut = (OutputDevice*)rInf.GetOut();
+ Color aCol( SwViewOption::GetFieldShadingsColor() );
+ Color aOldColor( pOut->GetFillColor() );
+ pOut->SetFillColor( aCol );
+ Point aPos( rInf.GetPos() );
+ aPos.Y() -= 150;
+ aPos.X() -= 25;
+ SwRect aRect( aPos, Size( 100, 200 ) );
+ ((OutputDevice*)pOut)->DrawRect( aRect.SVRect() );
+ pOut->SetFillColor( aOldColor );
+#endif
+}
+
+/*************************************************************************
+ * virtual SwHiddenTextPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwHiddenTextPortion::Format( SwTxtFormatInfo &rInf )
+{
+ Width( 0 );
+ rInf.GetTxtFrm()->HideFootnotes( rInf.GetIdx(), rInf.GetIdx() + GetLen() );
+
+ return sal_False;
+};
+
+/*************************************************************************
+ * virtual SwControlCharPortion::Paint()
+ *************************************************************************/
+
+void SwControlCharPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if ( Width() ) // is only set during prepaint mode
+ {
+ rInf.DrawViewOpt( *this, POR_CONTROLCHAR );
+
+ if ( !rInf.GetOpt().IsPagePreview() &&
+ !rInf.GetOpt().IsReadonly() &&
+ SwViewOption::IsFieldShadings() &&
+ CHAR_ZWNBSP != mcChar )
+ {
+ SwFont aTmpFont( *rInf.GetFont() );
+ aTmpFont.SetEscapement( CHAR_ZWSP == mcChar ? DFLT_ESC_AUTO_SUB : -25 );
+ const USHORT nProp = 40;
+ aTmpFont.SetProportion( nProp ); // a smaller font
+ SwFontSave aFontSave( rInf, &aTmpFont );
+
+ String aOutString;
+
+ switch ( mcChar )
+ {
+ case CHAR_ZWSP :
+ aOutString = '/'; break;
+// case CHAR_LRM :
+// rTxt = sal_Unicode(0x2514); break;
+// case CHAR_RLM :
+// rTxt = sal_Unicode(0x2518); break;
+ }
+
+ if ( !mnHalfCharWidth )
+ mnHalfCharWidth = rInf.GetTxtSize( aOutString ).Width() / 2;
+
+ Point aOldPos = rInf.GetPos();
+ Point aNewPos( aOldPos );
+ aNewPos.X() = aNewPos.X() + ( Width() / 2 ) - mnHalfCharWidth;
+ const_cast< SwTxtPaintInfo& >( rInf ).SetPos( aNewPos );
+
+ rInf.DrawText( aOutString, *this );
+
+ const_cast< SwTxtPaintInfo& >( rInf ).SetPos( aOldPos );
+ }
+ }
+}
+
+/*************************************************************************
+ * virtual SwControlCharPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwControlCharPortion::Format( SwTxtFormatInfo &rInf )
+{
+ const SwLinePortion* pRoot = rInf.GetRoot();
+ Width( 0 );
+ Height( pRoot->Height() );
+ SetAscent( pRoot->GetAscent() );
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwControlCharPortion::GetViewWidth()
+ *************************************************************************/
+
+KSHORT SwControlCharPortion::GetViewWidth( const SwTxtSizeInfo& rInf ) const
+{
+ if( !mnViewWidth )
+ mnViewWidth = rInf.GetTxtSize( ' ' ).Width();
+
+ return mnViewWidth;
+}
diff --git a/sw/source/core/text/porrst.hxx b/sw/source/core/text/porrst.hxx
new file mode 100644
index 000000000000..f94410bb4213
--- /dev/null
+++ b/sw/source/core/text/porrst.hxx
@@ -0,0 +1,187 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORRST_HXX
+#define _PORRST_HXX
+#include "porlay.hxx"
+#include "porexp.hxx"
+
+#define LINE_BREAK_WIDTH 150
+#define SPECIAL_FONT_HEIGHT 200
+
+class SwTxtFormatInfo;
+
+/*************************************************************************
+ * class SwTmpEndPortion
+ *************************************************************************/
+
+class SwTmpEndPortion : public SwLinePortion
+{
+public:
+ SwTmpEndPortion( const SwLinePortion &rPortion );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwBreakPortion
+ *************************************************************************/
+
+class SwBreakPortion : public SwLinePortion
+{
+public:
+ SwBreakPortion( const SwLinePortion &rPortion );
+ // liefert 0 zurueck, wenn keine Nutzdaten enthalten sind.
+ virtual SwLinePortion *Compress();
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+ virtual xub_StrLen GetCrsrOfst( const MSHORT nOfst ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwKernPortion
+ *************************************************************************/
+
+class SwKernPortion : public SwLinePortion
+{
+ short nKern;
+ sal_Bool bBackground;
+ sal_Bool bGridKern;
+
+public:
+
+ // This constructor automatically appends the portion to rPortion
+ // bBG indicates, that the background of the kerning portion has to
+ // be painted, e.g., if the portion if positioned between to fields.
+ // bGridKern indicates, that the kerning portion is used to provide
+ // additional space in grid mode.
+ SwKernPortion( SwLinePortion &rPortion, short nKrn,
+ sal_Bool bBG = sal_False, sal_Bool bGridKern = sal_False );
+
+ // This constructor only sets the height and ascent to the values
+ // of rPortion. It is only used for kerning portions for grid mode
+ SwKernPortion( const SwLinePortion &rPortion );
+
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwArrowPortion
+ *************************************************************************/
+
+class SwArrowPortion : public SwLinePortion
+{
+ Point aPos;
+ sal_Bool bLeft;
+public:
+ SwArrowPortion( const SwLinePortion &rPortion );
+ SwArrowPortion( const SwTxtPaintInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual SwLinePortion *Compress();
+ inline sal_Bool IsLeft() const { return bLeft; }
+ inline const Point& GetPos() const { return aPos; }
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwHangingPortion
+ * The characters which are forbidden at the start of a line like the dot and
+ * other punctuation marks are allowed to display in the margin of the page
+ * by a user option.
+ * The SwHangingPortion is the corresponding textportion to do that.
+ *************************************************************************/
+
+class SwHangingPortion : public SwTxtPortion
+{
+ KSHORT nInnerWidth;
+public:
+ inline SwHangingPortion( SwPosSize aSize ) : nInnerWidth( aSize.Width() )
+ { SetWhichPor( POR_HNG ); SetLen( 1 ); Height( aSize.Height() ); }
+
+ inline KSHORT GetInnerWidth() const { return nInnerWidth; }
+};
+
+/*************************************************************************
+ * class SwHiddenTextPortion
+ * Is used to hide text
+ *************************************************************************/
+
+class SwHiddenTextPortion : public SwLinePortion
+{
+public:
+ inline SwHiddenTextPortion( xub_StrLen nLen )
+ { SetWhichPor( POR_HIDDEN_TXT ); SetLen( nLen ); }
+
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+};
+
+/*************************************************************************
+ * class SwControlCharPortion
+ *************************************************************************/
+
+class SwControlCharPortion : public SwLinePortion
+{
+
+private:
+ mutable USHORT mnViewWidth; // used to cache a calculated value
+ mutable USHORT mnHalfCharWidth; // used to cache a calculated value
+ sal_Unicode mcChar;
+
+public:
+
+ inline SwControlCharPortion( sal_Unicode cChar )
+ : mnViewWidth( 0 ), mnHalfCharWidth( 0 ), mcChar( cChar )
+ {
+ SetWhichPor( POR_CONTROLCHAR ); SetLen( 1 );
+ }
+
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo& rInf ) const;
+};
+
+
+
+/*************************************************************************
+ * inline - Implementations
+ *************************************************************************/
+
+CLASSIO( SwBreakPortion )
+CLASSIO( SwEndPortion )
+CLASSIO( SwKernPortion )
+CLASSIO( SwArrowPortion )
+
+#endif
diff --git a/sw/source/core/text/portab.hxx b/sw/source/core/text/portab.hxx
new file mode 100644
index 000000000000..a2f10803c894
--- /dev/null
+++ b/sw/source/core/text/portab.hxx
@@ -0,0 +1,157 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORTAB_HXX
+#define _PORTAB_HXX
+
+#include "porglue.hxx"
+
+/*************************************************************************
+ * class SwTabPortion
+ *************************************************************************/
+
+class SwTabPortion : public SwFixPortion
+{
+ const KSHORT nTabPos;
+ const xub_Unicode cFill;
+
+ // Das Format() verzweigt entweder in Pre- oder PostFormat()
+ sal_Bool PreFormat( SwTxtFormatInfo &rInf );
+public:
+ SwTabPortion( const KSHORT nTabPos, const xub_Unicode cFill = '\0' );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+ sal_Bool PostFormat( SwTxtFormatInfo &rInf );
+ inline sal_Bool IsFilled() const { return 0 != cFill; }
+ inline KSHORT GetTabPos() const { return nTabPos; }
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwTabLeftPortion
+ *************************************************************************/
+
+class SwTabLeftPortion : public SwTabPortion
+{
+public:
+ inline SwTabLeftPortion( const KSHORT nTabPosVal, const xub_Unicode cFillChar='\0' )
+ : SwTabPortion( nTabPosVal, cFillChar )
+ { SetWhichPor( POR_TABLEFT ); }
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwTabRightPortion
+ *************************************************************************/
+
+class SwTabRightPortion : public SwTabPortion
+{
+public:
+ inline SwTabRightPortion( const KSHORT nTabPosVal, const xub_Unicode cFillChar='\0' )
+ : SwTabPortion( nTabPosVal, cFillChar )
+ { SetWhichPor( POR_TABRIGHT ); }
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwTabCenterPortion
+ *************************************************************************/
+
+class SwTabCenterPortion : public SwTabPortion
+{
+public:
+ inline SwTabCenterPortion( const KSHORT nTabPosVal, const xub_Unicode cFillChar='\0' )
+ : SwTabPortion( nTabPosVal, cFillChar )
+ { SetWhichPor( POR_TABCENTER ); }
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwTabDecimalPortion
+ *************************************************************************/
+
+class SwTabDecimalPortion : public SwTabPortion
+{
+ const xub_Unicode mcTab;
+
+ /*
+ * During text formatting, we already store the width of the portions
+ * following the tab stop up to the decimal position. This value is
+ * evaluated during pLastTab->FormatEOL. FME 2006-01-06 #127428#.
+ */
+ USHORT mnWidthOfPortionsUpTpDecimalPosition;
+
+public:
+ inline SwTabDecimalPortion( const KSHORT nTabPosVal, const xub_Unicode cTab,
+ const xub_Unicode cFillChar = '\0' )
+ : SwTabPortion( nTabPosVal, cFillChar ),
+ mcTab(cTab),
+ mnWidthOfPortionsUpTpDecimalPosition( USHRT_MAX )
+ { SetWhichPor( POR_TABDECIMAL ); }
+
+ inline xub_Unicode GetTabDecimal() const { return mcTab; }
+
+ inline void SetWidthOfPortionsUpToDecimalPosition( USHORT nNew )
+ {
+ mnWidthOfPortionsUpTpDecimalPosition = nNew;
+ }
+ inline USHORT GetWidthOfPortionsUpToDecimalPosition() const
+ {
+ return mnWidthOfPortionsUpTpDecimalPosition;
+ }
+
+ OUTPUT_OPERATOR
+};
+
+
+/*************************************************************************
+ * class SwAutoTabDecimalPortion
+ *************************************************************************/
+
+class SwAutoTabDecimalPortion : public SwTabDecimalPortion
+{
+public:
+ inline SwAutoTabDecimalPortion( const KSHORT nTabPosVal, const xub_Unicode cTab,
+ const xub_Unicode cFillChar = '\0' )
+ : SwTabDecimalPortion( nTabPosVal, cTab, cFillChar )
+ { SetLen( 0 ); }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+};
+
+
+CLASSIO( SwTabPortion )
+CLASSIO( SwTabLeftPortion )
+CLASSIO( SwTabRightPortion )
+CLASSIO( SwTabCenterPortion )
+CLASSIO( SwTabDecimalPortion )
+
+
+#endif
diff --git a/sw/source/core/text/portox.cxx b/sw/source/core/text/portox.cxx
new file mode 100644
index 000000000000..91a8fcd5eff0
--- /dev/null
+++ b/sw/source/core/text/portox.cxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * 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 <SwPortionHandler.hxx>
+#include "viewopt.hxx" // SwViewOptions
+
+#include "txtcfg.hxx"
+#include "portox.hxx"
+#include "inftxt.hxx" // GetTxtSize()
+
+/*************************************************************************
+ * virtual SwToxPortion::Paint()
+ *************************************************************************/
+
+void SwToxPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ {
+ rInf.DrawViewOpt( *this, POR_TOX );
+ SwTxtPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * class SwIsoToxPortion
+ *************************************************************************/
+
+SwLinePortion *SwIsoToxPortion::Compress() { return this; }
+
+SwIsoToxPortion::SwIsoToxPortion() : nViewWidth(0)
+{
+ SetLen(1);
+ SetWhichPor( POR_ISOTOX );
+}
+
+/*************************************************************************
+ * virtual SwIsoToxPortion::GetViewWidth()
+ *************************************************************************/
+
+KSHORT SwIsoToxPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
+ // Moment errechnet werden:
+ SwIsoToxPortion* pThis = (SwIsoToxPortion*)this;
+ // nViewWidth muss errechnet werden.
+ if( !Width() && rInf.OnWin() &&
+ !rInf.GetOpt().IsPagePreview() &&
+ !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
+ {
+ if( !nViewWidth )
+ pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width();
+ }
+ else
+ pThis->nViewWidth = 0;
+ return nViewWidth;
+}
+
+/*************************************************************************
+ * virtual SwIsoToxPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwIsoToxPortion::Format( SwTxtFormatInfo &rInf )
+{
+ const sal_Bool bFull = SwLinePortion::Format( rInf );
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwIsoToxPortion::Paint()
+ *************************************************************************/
+
+void SwIsoToxPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ rInf.DrawViewOpt( *this, POR_TOX );
+}
+
+/*************************************************************************
+ * virtual SwIsoToxPortion::HandlePortion()
+ *************************************************************************/
+
+void SwIsoToxPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString;
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
diff --git a/sw/source/core/text/portox.hxx b/sw/source/core/text/portox.hxx
new file mode 100644
index 000000000000..848fc9ecf6f1
--- /dev/null
+++ b/sw/source/core/text/portox.hxx
@@ -0,0 +1,75 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _PORTOX_HXX
+#define _PORTOX_HXX
+
+#include "portxt.hxx"
+//#include "porglue.hxx"
+
+/*************************************************************************
+ * class SwToxPortion
+ *************************************************************************/
+
+class SwToxPortion : public SwTxtPortion
+{
+public:
+ inline SwToxPortion(){ SetWhichPor( POR_TOX ); }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * class SwIsoToxPortion
+ *************************************************************************/
+
+class SwIsoToxPortion : public SwToxPortion
+{
+ KSHORT nViewWidth;
+
+public:
+ SwIsoToxPortion();
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual SwLinePortion *Compress();
+ virtual KSHORT GetViewWidth( const SwTxtSizeInfo &rInf ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+};
+
+/*************************************************************************
+ * inline - Implementations
+ *************************************************************************/
+
+CLASSIO( SwToxPortion )
+CLASSIO( SwIsoToxPortion )
+
+
+#endif
diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx
new file mode 100644
index 000000000000..a849cbe42f40
--- /dev/null
+++ b/sw/source/core/text/portxt.cxx
@@ -0,0 +1,881 @@
+/*************************************************************************
+ *
+ * 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 <ctype.h>
+
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <hintids.hxx> // CH_TXTATR
+#include <errhdl.hxx> // ASSERT
+#include <SwPortionHandler.hxx>
+#include <txtcfg.hxx>
+#include <porlay.hxx>
+#include <inftxt.hxx>
+#include <guess.hxx> // SwTxtGuess, Zeilenumbruch
+#include <porglue.hxx>
+#include <portab.hxx> // pLastTab->
+#include <porfld.hxx> // SwFldPortion
+#include <wrong.hxx>
+#include <viewsh.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <viewopt.hxx> // SwViewOptions
+
+#include <IMark.hxx>
+#include <pam.hxx>
+#include <doc.hxx>
+#include <xmloff/odffields.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+const sal_Char *GetLangName( const MSHORT nLang );
+#endif
+
+using namespace ::sw::mark;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::i18n::ScriptType;
+
+/*************************************************************************
+ * lcl_AddSpace
+ * Returns for how many characters an extra space has to be added
+ * (for justified alignment).
+ *************************************************************************/
+
+USHORT lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr,
+ const SwLinePortion& rPor )
+{
+ xub_StrLen nPos, nEnd;
+ const SwScriptInfo* pSI = 0;
+
+ if ( pStr )
+ {
+ // passing a string means we are inside a field
+ nPos = 0;
+ nEnd = pStr->Len();
+ }
+ else
+ {
+ nPos = rInf.GetIdx();
+ nEnd = rInf.GetIdx() + rPor.GetLen();
+ pStr = &rInf.GetTxt();
+ pSI = &((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo();
+ }
+
+ USHORT nCnt = 0;
+ BYTE nScript = 0;
+
+ // If portion consists of Asian characters and language is not
+ // Korean, we add extra space to each character.
+ // first we get the script type
+ if ( pSI )
+ nScript = pSI->ScriptType( nPos );
+ else if ( pBreakIt->GetBreakIter().is() )
+ nScript = (BYTE)pBreakIt->GetBreakIter()->getScriptType( *pStr, nPos );
+
+ // Note: rInf.GetIdx() can differ from nPos,
+ // e.g., when rPor is a field portion. nPos referes to the string passed
+ // to the function, rInf.GetIdx() referes to the original string.
+
+ // We try to find out which justification mode is required. This is done by
+ // evaluating the script type and the language attribute set for this portion
+
+ // Asian Justification: Each character get some extra space
+ if ( nEnd > nPos && ASIAN == nScript )
+ {
+ LanguageType aLang =
+ rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
+
+ if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
+ {
+ const SwLinePortion* pPor = rPor.GetPortion();
+ if ( pPor && ( pPor->IsKernPortion() ||
+ pPor->IsControlCharPortion() ||
+ pPor->IsPostItsPortion() ) )
+ pPor = pPor->GetPortion();
+
+ nCnt += nEnd - nPos;
+
+ if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ||
+ pPor->IsBreakPortion() )
+ --nCnt;
+
+ return nCnt;
+ }
+ }
+
+ // Kashida Justification: Insert Kashidas
+ if ( nEnd > nPos && pSI && COMPLEX == nScript )
+ {
+ if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() )
+ {
+ const USHORT nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos );
+ // i60591: need to check result of KashidaJustify
+ // determine if kashida justification is applicable
+ if( nKashRes != STRING_LEN )
+ return nKashRes;
+ }
+ }
+
+ // Thai Justification: Each character cell gets some extra space
+ if ( nEnd > nPos && COMPLEX == nScript )
+ {
+ LanguageType aLang =
+ rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
+
+ if ( LANGUAGE_THAI == aLang )
+ {
+ nCnt = SwScriptInfo::ThaiJustify( *pStr, 0, 0, nPos, nEnd - nPos );
+
+ const SwLinePortion* pPor = rPor.GetPortion();
+ if ( pPor && ( pPor->IsKernPortion() ||
+ pPor->IsControlCharPortion() ||
+ pPor->IsPostItsPortion() ) )
+ pPor = pPor->GetPortion();
+
+ if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) )
+ --nCnt;
+
+ return nCnt;
+ }
+ }
+
+ // Here starts the good old "Look for blanks and add space to them" part.
+ // Note: We do not want to add space to an isolated latin blank in front
+ // of some complex characters in RTL environment
+ const sal_Bool bDoNotAddSpace =
+ LATIN == nScript && ( nEnd == nPos + 1 ) && pSI &&
+ ( i18n::ScriptType::COMPLEX ==
+ pSI->ScriptType( nPos + 1 ) ) &&
+ rInf.GetTxtFrm() && rInf.GetTxtFrm()->IsRightToLeft();
+
+ if ( bDoNotAddSpace )
+ return nCnt;
+
+ for ( ; nPos < nEnd; ++nPos )
+ {
+ if( CH_BLANK == pStr->GetChar( nPos ) )
+ ++nCnt;
+ }
+
+ // We still have to examine the next character:
+ // If the next character is ASIAN and not KOREAN we have
+ // to add an extra space
+ // nPos referes to the original string, even if a field string has
+ // been passed to this function
+ nPos = rInf.GetIdx() + rPor.GetLen();
+ if ( nPos < rInf.GetTxt().Len() )
+ {
+ BYTE nNextScript = 0;
+ const SwLinePortion* pPor = rPor.GetPortion();
+ if ( pPor && pPor->IsKernPortion() )
+ pPor = pPor->GetPortion();
+
+ if ( ! pBreakIt->GetBreakIter().is() || ! pPor || pPor->InFixMargGrp() )
+ return nCnt;
+
+ // next character is inside a field?
+ if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() )
+ {
+ sal_Bool bOldOnWin = rInf.OnWin();
+ ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False );
+
+ XubString aStr( aEmptyStr );
+ pPor->GetExpTxt( rInf, aStr );
+ ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
+
+ nNextScript = (BYTE)pBreakIt->GetBreakIter()->getScriptType( aStr, 0 );
+ }
+ else
+ nNextScript = (BYTE)pBreakIt->GetBreakIter()->getScriptType( rInf.GetTxt(), nPos );
+
+ if( ASIAN == nNextScript )
+ {
+ LanguageType aLang =
+ rInf.GetTxtFrm()->GetTxtNode()->GetLang( nPos, 1, nNextScript );
+
+ if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
+ ++nCnt;
+ }
+ }
+
+ return nCnt;
+}
+
+/*************************************************************************
+ * class SwTxtPortion
+ *************************************************************************/
+
+SwTxtPortion::SwTxtPortion( const SwLinePortion &rPortion )
+ : SwLinePortion( rPortion )
+{
+ SetWhichPor( POR_TXT );
+}
+
+/*************************************************************************
+ * SwTxtPortion::BreakCut()
+ *************************************************************************/
+
+void SwTxtPortion::BreakCut( SwTxtFormatInfo &rInf, const SwTxtGuess &rGuess )
+{
+ // Das Wort/Zeichen ist groesser als die Zeile
+ // Sonderfall Nr.1: Das Wort ist groesser als die Zeile
+ // Wir kappen...
+ const KSHORT nLineWidth = (KSHORT)(rInf.Width() - rInf.X());
+ xub_StrLen nLen = rGuess.CutPos() - rInf.GetIdx();
+ if( nLen )
+ {
+ // special case: guess does not always provide the correct
+ // width, only in common cases.
+ if ( !rGuess.BreakWidth() )
+ {
+ rInf.SetLen( nLen );
+ SetLen( nLen );
+ CalcTxtSize( rInf );
+
+ // changing these values requires also changing them in
+ // guess.cxx
+ KSHORT nItalic = 0;
+ if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
+ {
+ nItalic = Height() / 12;
+ }
+ Width( Width() + nItalic );
+ }
+ else
+ {
+ Width( rGuess.BreakWidth() );
+ SetLen( nLen );
+ }
+ }
+ // special case: first character does not fit to line
+ else if ( rGuess.CutPos() == rInf.GetLineStart() )
+ {
+ SetLen( 1 );
+ Width( nLineWidth );
+ }
+ else
+ {
+ SetLen( 0 );
+ Width( 0 );
+ }
+}
+
+/*************************************************************************
+ * SwTxtPortion::BreakUnderflow()
+ *************************************************************************/
+
+void SwTxtPortion::BreakUnderflow( SwTxtFormatInfo &rInf )
+{
+ Truncate();
+ Height( 0 );
+ Width( 0 );
+ SetLen( 0 );
+ SetAscent( 0 );
+ rInf.SetUnderFlow( this );
+}
+
+ /*************************************************************************
+ * SwTxtPortion::_Format()
+ *************************************************************************/
+
+sal_Bool lcl_HasContent( const SwFldPortion& rFld, SwTxtFormatInfo &rInf )
+{
+ String aTxt;
+ return rFld.GetExpTxt( rInf, aTxt ) && aTxt.Len();
+}
+
+sal_Bool SwTxtPortion::_Format( SwTxtFormatInfo &rInf )
+{
+ // 5744: wenn nur der Trennstrich nicht mehr passt,
+ // muss trotzdem das Wort umgebrochen werden, ansonsten return sal_True!
+ if( rInf.IsUnderFlow() && rInf.GetSoftHyphPos() )
+ {
+ // soft hyphen portion has triggered an underflow event because
+ // of an alternative spelling position
+ sal_Bool bFull = sal_False;
+ const sal_Bool bHyph = rInf.ChgHyph( sal_True );
+ if( rInf.IsHyphenate() )
+ {
+ SwTxtGuess aGuess;
+ // check for alternative spelling left from the soft hyphen
+ // this should usually be true but
+ aGuess.AlternativeSpelling( rInf, rInf.GetSoftHyphPos() - 1 );
+ bFull = CreateHyphen( rInf, aGuess );
+ ASSERT( bFull, "Problem with hyphenation!!!" );
+ }
+ rInf.ChgHyph( bHyph );
+ rInf.SetSoftHyphPos( 0 );
+ return bFull;
+ }
+
+ SwTxtGuess aGuess;
+ const sal_Bool bFull = !aGuess.Guess( *this, rInf, Height() );
+
+ // these are the possible cases:
+ // A Portion fits to current line
+ // B Portion does not fit to current line but a possible line break
+ // within the portion has been found by the break iterator, 2 subcases
+ // B1 break is hyphen
+ // B2 break is word end
+ // C Portion does not fit to current line and no possible line break
+ // has been found by break iterator, 2 subcases:
+ // C1 break iterator found a possible line break in portion before us
+ // ==> this break is used (underflow)
+ // C2 break iterator does not found a possible line break at all:
+ // ==> line break
+
+ // case A: line not yet full
+ if ( !bFull )
+ {
+ Width( aGuess.BreakWidth() );
+ // Vorsicht !
+ if( !InExpGrp() || InFldGrp() )
+ SetLen( rInf.GetLen() );
+
+ short nKern = rInf.GetFont()->CheckKerning();
+ if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern )
+ {
+ nKern = (short)(rInf.Width() - rInf.X() - Width() - 1);
+ if( nKern < 0 )
+ nKern = 0;
+ }
+ if( nKern )
+ new SwKernPortion( *this, nKern );
+ }
+ // special case: hanging portion
+ else if( bFull && aGuess.GetHangingPortion() )
+ {
+ Width( aGuess.BreakWidth() );
+ SetLen( aGuess.BreakPos() - rInf.GetIdx() );
+ Insert( aGuess.GetHangingPortion() );
+ aGuess.GetHangingPortion()->SetAscent( GetAscent() );
+ aGuess.ClearHangingPortion();
+ }
+ // breakPos >= index
+ else if ( aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != STRING_LEN )
+ {
+ // case B1
+ if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart()
+ && ( aGuess.BreakPos() > rInf.GetIdx() ||
+ ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) )
+ {
+ CreateHyphen( rInf, aGuess );
+ if ( rInf.GetFly() )
+ rInf.GetRoot()->SetMidHyph( sal_True );
+ else
+ rInf.GetRoot()->SetEndHyph( sal_True );
+ }
+ // case C1
+ // - Footnote portions with fake line start (i.e., not at beginning of line)
+ // should keep together with the text portion. (Note: no keep together
+ // with only footnote portions.
+ // - TabPortions not at beginning of line should keep together with the
+ // text portion, if they are not followed by a blank
+ // (work around different definition of tab stop character - breaking or
+ // non breaking character - in compatibility mode)
+ else if ( ( IsFtnPortion() && rInf.IsFakeLineStart() &&
+ // --> OD 2010-01-29 #b6921213#
+ rInf.IsOtherThanFtnInside() ) ||
+ // <--
+ ( rInf.GetLast() &&
+ rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) &&
+ rInf.GetLast()->InTabGrp() &&
+ rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() &&
+ aGuess.BreakPos() == rInf.GetIdx() &&
+ CH_BLANK != rInf.GetChar( rInf.GetIdx() ) &&
+ 0x3000 != rInf.GetChar( rInf.GetIdx() ) ) )
+ BreakUnderflow( rInf );
+ // case B2
+ else if( rInf.GetIdx() > rInf.GetLineStart() ||
+ aGuess.BreakPos() > rInf.GetIdx() ||
+ // this is weird: during formatting the follow of a field
+ // the values rInf.GetIdx and rInf.GetLineStart are replaced
+ // IsFakeLineStart indicates GetIdx > GetLineStart
+ rInf.IsFakeLineStart() ||
+ rInf.GetFly() ||
+ rInf.IsFirstMulti() ||
+ ( rInf.GetLast() &&
+ ( rInf.GetLast()->IsFlyPortion() ||
+ ( rInf.GetLast()->InFldGrp() &&
+ ! rInf.GetLast()->InNumberGrp() &&
+ ! rInf.GetLast()->IsErgoSumPortion() &&
+ lcl_HasContent(*((SwFldPortion*)rInf.GetLast()),rInf ) ) ) ) )
+ {
+ if ( rInf.X() + aGuess.BreakWidth() <= rInf.Width() )
+ Width( aGuess.BreakWidth() );
+ else
+ // this actually should not happen
+ Width( KSHORT(rInf.Width() - rInf.X()) );
+
+ SetLen( aGuess.BreakPos() - rInf.GetIdx() );
+
+ ASSERT( aGuess.BreakStart() >= aGuess.FieldDiff(),
+ "Trouble with expanded field portions during line break" );
+ const xub_StrLen nRealStart = aGuess.BreakStart() - aGuess.FieldDiff();
+ if( aGuess.BreakPos() < nRealStart && !InExpGrp() )
+ {
+ SwHolePortion *pNew = new SwHolePortion( *this );
+ pNew->SetLen( nRealStart - aGuess.BreakPos() );
+ Insert( pNew );
+ }
+ }
+ else // case C2, last exit
+ BreakCut( rInf, aGuess );
+ }
+ // breakPos < index or no breakpos at all
+ else
+ {
+ sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
+ if( aGuess.BreakPos() != STRING_LEN &&
+ aGuess.BreakPos() != rInf.GetLineStart() &&
+ ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() ||
+ rInf.IsFirstMulti() ) &&
+ ( !rInf.GetLast()->IsBlankPortion() || ((SwBlankPortion*)
+ rInf.GetLast())->MayUnderFlow( rInf, rInf.GetIdx()-1, sal_True )))
+ { // case C1 (former BreakUnderflow())
+ BreakUnderflow( rInf );
+ }
+ else
+ // case C2, last exit
+ BreakCut( rInf, aGuess );
+ }
+
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::Format()
+ *************************************************************************/
+
+
+
+sal_Bool SwTxtPortion::Format( SwTxtFormatInfo &rInf )
+{
+#if OSL_DEBUG_LEVEL > 1
+ const XubString aDbgTxt( rInf.GetTxt().Copy( rInf.GetIdx(), rInf.GetLen() ) );
+#endif
+
+ if( rInf.X() > rInf.Width() || (!GetLen() && !InExpGrp()) )
+ {
+ Height( 0 );
+ Width( 0 );
+ SetLen( 0 );
+ SetAscent( 0 );
+ SetPortion( NULL ); // ????
+ return sal_True;
+ }
+
+ ASSERT( rInf.RealWidth() || (rInf.X() == rInf.Width()),
+ "SwTxtPortion::Format: missing real width" );
+ ASSERT( Height(), "SwTxtPortion::Format: missing height" );
+
+ return _Format( rInf );
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::FormatEOL()
+ *************************************************************************/
+
+// Format end of line
+// 5083: Es kann schon manchmal unguenstige Faelle geben...
+// "vom {Nikolaus}", Nikolaus bricht um "vom " wird im Blocksatz
+// zu "vom" und " ", wobei der Glue expandiert wird, statt in die
+// MarginPortion aufzugehen.
+// rInf.nIdx steht auf dem naechsten Wort, nIdx-1 ist der letzte
+// Buchstabe der Portion.
+
+
+
+void SwTxtPortion::FormatEOL( SwTxtFormatInfo &rInf )
+{
+ if( ( !GetPortion() || ( GetPortion()->IsKernPortion() &&
+ !GetPortion()->GetPortion() ) ) && GetLen() &&
+ rInf.GetIdx() < rInf.GetTxt().Len() &&
+ 1 < rInf.GetIdx() && ' ' == rInf.GetChar( rInf.GetIdx() - 1 )
+ && !rInf.GetLast()->IsHolePortion() )
+ {
+ // calculate number of blanks
+ xub_StrLen nX = rInf.GetIdx() - 1;
+ USHORT nHoleLen = 1;
+ while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) )
+ nHoleLen++;
+
+ // Erst uns einstellen und dann Inserten, weil wir ja auch ein
+ // SwLineLayout sein koennten.
+ KSHORT nBlankSize;
+ if( nHoleLen == GetLen() )
+ nBlankSize = Width();
+ else
+ nBlankSize = nHoleLen * rInf.GetTxtSize( ' ' ).Width();
+ Width( Width() - nBlankSize );
+ rInf.X( rInf.X() - nBlankSize );
+ SetLen( GetLen() - nHoleLen );
+ SwLinePortion *pHole = new SwHolePortion( *this );
+ ( (SwHolePortion *)pHole )->SetBlankWidth( nBlankSize );
+ ( (SwHolePortion *)pHole )->SetLen( nHoleLen );
+ Insert( pHole );
+ }
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::GetCrsrOfst()
+ *************************************************************************/
+
+
+
+xub_StrLen SwTxtPortion::GetCrsrOfst( const KSHORT nOfst ) const
+{
+ ASSERT( !this, "SwTxtPortion::GetCrsrOfst: don't use this method!" );
+ return SwLinePortion::GetCrsrOfst( nOfst );
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::GetTxtSize()
+ *************************************************************************/
+// Das GetTxtSize() geht davon aus, dass die eigene Laenge korrekt ist
+
+SwPosSize SwTxtPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
+{
+ return rInf.GetTxtSize();
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::Paint()
+ *************************************************************************/
+
+
+
+void SwTxtPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetTxt().GetChar(rInf.GetIdx()))
+ {
+ rInf.DrawBackBrush( *this );
+ const XubString aTxt = XubString::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDEND);
+ rInf.DrawText( aTxt, *this, 0, aTxt.Len(), false );
+ }
+ else if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetTxt().GetChar(rInf.GetIdx()))
+ {
+ rInf.DrawBackBrush( *this );
+ const XubString aTxt = XubString::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDSTART);
+ rInf.DrawText( aTxt, *this, 0, aTxt.Len(), false );
+ }
+ else if( GetLen() )
+ {
+ rInf.DrawBackBrush( *this );
+
+ // do we have to repaint a post it portion?
+ if( rInf.OnWin() && pPortion && !pPortion->Width() )
+ pPortion->PrePaint( rInf, this );
+
+ const SwWrongList *pWrongList = rInf.GetpWrongList();
+ const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList();
+ // SMARTTAGS
+ const SwWrongList *pSmarttags = rInf.GetSmartTags();
+
+ const bool bWrong = 0 != pWrongList;
+ const bool bGrammarCheck = 0 != pGrammarCheckList;
+ const bool bSmartTags = 0 != pSmarttags;
+
+ if ( bWrong || bSmartTags || bGrammarCheck )
+ rInf.DrawMarkedText( *this, rInf.GetLen(), sal_False, bWrong, bSmartTags, bGrammarCheck );
+ else
+ rInf.DrawText( *this, rInf.GetLen(), sal_False );
+ }
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::GetExpTxt()
+ *************************************************************************/
+
+
+
+sal_Bool SwTxtPortion::GetExpTxt( const SwTxtSizeInfo &, XubString & ) const
+{
+ return sal_False;
+}
+
+/*************************************************************************
+ * xub_StrLen SwTxtPortion::GetSpaceCnt()
+ * long SwTxtPortion::CalcSpacing()
+ * sind fuer den Blocksatz zustaendig und ermitteln die Anzahl der Blanks
+ * und den daraus resultierenden zusaetzlichen Zwischenraum
+ *************************************************************************/
+
+xub_StrLen SwTxtPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf,
+ xub_StrLen& rCharCnt ) const
+{
+ xub_StrLen nCnt = 0;
+ xub_StrLen nPos = 0;
+ if ( InExpGrp() )
+ {
+ if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
+ {
+ // Bei OnWin() wird anstatt eines Leerstrings gern mal ein Blank
+ // zurueckgeliefert, das koennen wir hier aber gar nicht gebrauchen
+ sal_Bool bOldOnWin = rInf.OnWin();
+ ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False );
+
+ XubString aStr( aEmptyStr );
+ GetExpTxt( rInf, aStr );
+ ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
+
+ nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
+ nPos = aStr.Len();
+ }
+ }
+ else if( !IsDropPortion() )
+ {
+ nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
+ nPos = GetLen();
+ }
+ rCharCnt = rCharCnt + nPos;
+ return nCnt;
+}
+
+long SwTxtPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const
+{
+ xub_StrLen nCnt = 0;
+
+ if ( InExpGrp() )
+ {
+ if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
+ {
+ // Bei OnWin() wird anstatt eines Leerstrings gern mal ein Blank
+ // zurueckgeliefert, das koennen wir hier aber gar nicht gebrauchen
+ sal_Bool bOldOnWin = rInf.OnWin();
+ ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False );
+
+ XubString aStr( aEmptyStr );
+ GetExpTxt( rInf, aStr );
+ ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
+ if( nSpaceAdd > 0 )
+ nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
+ else
+ {
+ nSpaceAdd = -nSpaceAdd;
+ nCnt = aStr.Len();
+ }
+ }
+ }
+ else if( !IsDropPortion() )
+ {
+ if( nSpaceAdd > 0 )
+ nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
+ else
+ {
+ nSpaceAdd = -nSpaceAdd;
+ nCnt = GetLen();
+ SwLinePortion* pPor = GetPortion();
+
+ // we do not want an extra space in front of margin portions
+ if ( nCnt )
+ {
+ while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() )
+ pPor = pPor->GetPortion();
+
+ if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() )
+ --nCnt;
+ }
+ }
+ }
+
+ return nCnt * nSpaceAdd / SPACING_PRECISION_FACTOR;
+}
+
+/*************************************************************************
+ * virtual SwTxtPortion::HandlePortion()
+ *************************************************************************/
+
+void SwTxtPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Text( GetLen(), GetWhichPor() );
+}
+
+/*************************************************************************
+ * class SwHolePortion
+ *************************************************************************/
+
+
+
+SwHolePortion::SwHolePortion( const SwTxtPortion &rPor )
+ : nBlankWidth( 0 )
+{
+ SetLen( 1 );
+ Height( rPor.Height() );
+ SetAscent( rPor.GetAscent() );
+ SetWhichPor( POR_HOLE );
+}
+
+SwLinePortion *SwHolePortion::Compress() { return this; }
+
+/*************************************************************************
+ * virtual SwHolePortion::Paint()
+ *************************************************************************/
+
+
+
+void SwHolePortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ if( rInf.GetVsh() && rInf.GetVsh()->GetViewOptions()->IsPDFExport() )
+ {
+ const XubString aTxt( ' ' );
+ rInf.DrawText( aTxt, *this, 0, 1, false );
+ }
+ // <--
+}
+
+/*************************************************************************
+ * virtual SwHolePortion::Format()
+ *************************************************************************/
+
+
+
+sal_Bool SwHolePortion::Format( SwTxtFormatInfo &rInf )
+{
+ return rInf.IsFull() || rInf.X() >= rInf.Width();
+}
+
+/*************************************************************************
+ * virtual SwHolePortion::HandlePortion()
+ *************************************************************************/
+
+void SwHolePortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Text( GetLen(), GetWhichPor() );
+}
+
+void SwFieldMarkPortion::Paint( const SwTxtPaintInfo & /*rInf*/) const
+{
+ // These shouldn't be painted!
+ // SwTxtPortion::Paint(rInf);
+}
+
+sal_Bool SwFieldMarkPortion::Format( SwTxtFormatInfo & )
+{
+ sal_Bool ret=0;
+ Width(0);
+ return ret;
+}
+
+namespace {
+ static sal_Int32 getCurrentListIndex( IFieldmark* pBM,
+ ::rtl::OUString* io_pCurrentText = NULL )
+ {
+ const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters();
+ sal_Int32 nCurrentIdx = 0;
+ const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_RESULT));
+ if(pResult != pParameters->end())
+ pResult->second >>= nCurrentIdx;
+ if(io_pCurrentText)
+ {
+ const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_LISTENTRY));
+ if(pListEntries != pParameters->end())
+ {
+ uno::Sequence< ::rtl::OUString > vListEntries;
+ pListEntries->second >>= vListEntries;
+ if(nCurrentIdx < vListEntries.getLength())
+ *io_pCurrentText = vListEntries[nCurrentIdx];
+ }
+ }
+ return nCurrentIdx;
+ }
+}
+
+//FIXME Fieldbk
+void SwFieldFormPortion::Paint( const SwTxtPaintInfo& rInf ) const
+{
+ SwTxtNode* pNd = const_cast<SwTxtNode*>(rInf.GetTxtFrm()->GetTxtNode());
+ const SwDoc *doc=pNd->GetDoc();
+ SwIndex aIndex( pNd, rInf.GetIdx() );
+ SwPosition aPosition(*pNd, aIndex);
+
+ IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
+
+ OSL_ENSURE( pBM,
+ "SwFieldFormPortion::Paint(..)"
+ " - Where is my form field bookmark???");
+
+ if ( pBM != NULL )
+ {
+ if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) )
+ { // a checkbox...
+ ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM);
+ bool checked = pCheckboxFm->IsChecked();
+ rInf.DrawCheckBox(*this, checked);
+ }
+ else if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) )
+ { // a list...
+ rtl::OUString aTxt;
+ rInf.DrawViewOpt( *this, POR_FLD );
+ rInf.DrawText( aTxt, *this, 0, 0/*aTxt.getLength()*/, false );
+ }
+ else
+ {
+ assert(0); // unknown type...
+ }
+ }
+}
+
+sal_Bool SwFieldFormPortion::Format( SwTxtFormatInfo & rInf )
+{
+ sal_Bool ret = 0;
+ SwTxtNode *pNd = const_cast < SwTxtNode * >( rInf.GetTxtFrm( )->GetTxtNode( ) );
+ const SwDoc *doc = pNd->GetDoc( );
+ SwIndex aIndex( pNd, rInf.GetIdx( ) );
+ SwPosition aPosition( *pNd, aIndex );
+ IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
+ ASSERT( pBM != NULL, "Where is my form field bookmark???" );
+ if ( pBM != NULL )
+ {
+ if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) )
+ {
+ Width( rInf.GetTxtHeight( ) );
+ Height( rInf.GetTxtHeight( ) );
+ SetAscent( rInf.GetAscent( ) );
+ }
+ else if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) )
+ {
+ ::rtl::OUString aTxt;
+ getCurrentListIndex( pBM, &aTxt );
+ SwPosSize aPosSize = rInf.GetTxtSize( aTxt );
+ Width( aPosSize.Width( ) );
+ Height( aPosSize.Height( ) );
+ SetAscent( rInf.GetAscent( ) );
+ }
+ else
+ {
+ assert( 0 ); // unknown type...
+ }
+ }
+ return ret;
+}
+
+
diff --git a/sw/source/core/text/portxt.hxx b/sw/source/core/text/portxt.hxx
new file mode 100644
index 000000000000..2d4d5faf9e98
--- /dev/null
+++ b/sw/source/core/text/portxt.hxx
@@ -0,0 +1,117 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _PORTXT_HXX
+#define _PORTXT_HXX
+#ifdef GCC
+#include <sys/types.h>
+#else
+#include <new.h> //fuer size_t, FIXEDMEM aus tools
+#endif
+#include <tools/mempool.hxx>
+
+#include "porlin.hxx"
+
+class SwTxtGuess;
+
+/*************************************************************************
+ * class SwTxtPortion
+ *************************************************************************/
+
+class SwTxtPortion : public SwLinePortion
+{
+ void BreakCut( SwTxtFormatInfo &rInf, const SwTxtGuess &rGuess );
+ void BreakUnderflow( SwTxtFormatInfo &rInf );
+ sal_Bool _Format( SwTxtFormatInfo &rInf );
+
+public:
+ inline SwTxtPortion(){ SetWhichPor( POR_TXT ); }
+ SwTxtPortion( const SwLinePortion &rPortion );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void FormatEOL( SwTxtFormatInfo &rInf );
+ virtual xub_StrLen GetCrsrOfst( const KSHORT nOfst ) const;
+ virtual SwPosSize GetTxtSize( const SwTxtSizeInfo &rInfo ) const;
+ virtual sal_Bool GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const;
+ virtual long CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const;
+
+ // zaehlt die Spaces fuer Blocksatz
+ xub_StrLen GetSpaceCnt( const SwTxtSizeInfo &rInf, xub_StrLen& rCnt ) const;
+
+ sal_Bool CreateHyphen( SwTxtFormatInfo &rInf, SwTxtGuess &rGuess );
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+ DECL_FIXEDMEMPOOL_NEWDEL(SwTxtPortion)
+};
+
+/*************************************************************************
+ * class SwHolePortion
+ *************************************************************************/
+
+class SwHolePortion : public SwLinePortion
+{
+ KSHORT nBlankWidth;
+public:
+ SwHolePortion( const SwTxtPortion &rPor );
+ inline KSHORT GetBlankWidth( ) const { return nBlankWidth; }
+ inline void SetBlankWidth( const KSHORT nNew ) { nBlankWidth = nNew; }
+ virtual SwLinePortion *Compress();
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+
+ // Accessibility: pass information about this portion to the PortionHandler
+ virtual void HandlePortion( SwPortionHandler& rPH ) const;
+
+ OUTPUT_OPERATOR
+ DECL_FIXEDMEMPOOL_NEWDEL(SwHolePortion)
+};
+
+class SwFieldMarkPortion : public SwTxtPortion
+{
+ public:
+ inline SwFieldMarkPortion() : SwTxtPortion()
+ { }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+};
+
+class SwFieldFormPortion : public SwTxtPortion
+{
+ public:
+ inline SwFieldFormPortion() : SwTxtPortion()
+ { }
+ virtual void Paint( const SwTxtPaintInfo &rInf ) const;
+ virtual sal_Bool Format( SwTxtFormatInfo &rInf );
+};
+
+
+CLASSIO( SwTxtPortion )
+CLASSIO( SwHolePortion )
+
+#endif
diff --git a/sw/source/core/text/possiz.hxx b/sw/source/core/text/possiz.hxx
new file mode 100644
index 000000000000..a8f735c7b33a
--- /dev/null
+++ b/sw/source/core/text/possiz.hxx
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _POSSIZ_HXX
+#define _POSSIZ_HXX
+
+
+#include <tools/gen.hxx>
+#include "txttypes.hxx"
+
+// Im Gegensazt zu den SV-Sizes ist die SwPosSize immer positiv
+class SwPosSize
+{
+ KSHORT nWidth;
+ KSHORT nHeight;
+public:
+ inline SwPosSize( const KSHORT nW = 0, const KSHORT nH = 0 )
+ : nWidth(nW), nHeight(nH) { }
+ inline SwPosSize( const Size &rSize )
+ : nWidth(KSHORT(rSize.Width())), nHeight(KSHORT(rSize.Height())){ }
+ inline KSHORT Height() const { return nHeight; }
+ inline void Height( const KSHORT nNew ) { nHeight = nNew; }
+ inline KSHORT Width() const { return nWidth; }
+ inline void Width( const KSHORT nNew ) { nWidth = nNew; }
+
+ inline Size SvLSize() const { return Size( nWidth, nHeight ); }
+ inline void SvLSize( const Size &rSize );
+ inline void SvXSize( const Size &rSize );
+ inline SwPosSize &operator=( const SwPosSize &rSize );
+ inline SwPosSize &operator=( const Size &rSize );
+};
+
+inline SwPosSize &SwPosSize::operator=(const SwPosSize &rSize )
+{
+ nWidth = rSize.Width();
+ nHeight = rSize.Height();
+ return *this;
+}
+
+inline void SwPosSize::SvLSize( const Size &rSize )
+{
+ nWidth = KSHORT(rSize.Width());
+ nHeight = KSHORT(rSize.Height());
+}
+
+inline void SwPosSize::SvXSize( const Size &rSize )
+{
+ nHeight = KSHORT(rSize.Width());
+ nWidth = KSHORT(rSize.Height());
+}
+
+inline SwPosSize &SwPosSize::operator=( const Size &rSize )
+{
+ nWidth = KSHORT(rSize.Width());
+ nHeight = KSHORT(rSize.Height());
+ return *this;
+}
+
+
+#endif
+
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
new file mode 100644
index 000000000000..d789121de4b8
--- /dev/null
+++ b/sw/source/core/text/redlnitr.cxx
@@ -0,0 +1,505 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+#include <svl/whiter.hxx>
+#include <tools/shl.hxx>
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <swmodule.hxx>
+#include <redline.hxx> // SwRedline
+#include <txtatr.hxx> // SwTxt ...
+#include <docary.hxx> // SwRedlineTbl
+#include <itratr.hxx> // SwAttrIter
+#include <ndtxt.hxx> // SwTxtNode
+#include <doc.hxx> // SwDoc
+#include <rootfrm.hxx>
+#include <breakit.hxx>
+#include <vcl/keycodes.hxx>
+#include <vcl/cmdevt.hxx>
+#include <vcl/settings.hxx>
+#include <txtfrm.hxx> // SwTxtFrm
+#ifndef _APP_HXX //autogen
+#include <vcl/svapp.hxx>
+#endif
+#include <redlnitr.hxx>
+#include <extinput.hxx>
+#include <sfx2/printer.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * SwAttrIter::CtorInitAttrIter()
+ *************************************************************************/
+void SwAttrIter::CtorInitAttrIter( SwTxtNode& rTxtNode, SwScriptInfo& rScrInf, SwTxtFrm* pFrm )
+{
+ // Beim HTML-Import kann es vorkommen, dass kein Layout existiert.
+ SwRootFrm* pRootFrm = rTxtNode.getIDocumentLayoutAccess()->GetRootFrm();
+ pShell = pRootFrm ? pRootFrm->GetShell() : 0;
+
+ pScriptInfo = &rScrInf;
+
+ // attributes set at the whole paragraph
+ pAttrSet = rTxtNode.GetpSwAttrSet();
+ // attribute array
+ pHints = rTxtNode.GetpSwpHints();
+
+ // Build a font matching the default paragraph style:
+ SwFontAccess aFontAccess( &rTxtNode.GetAnyFmtColl(), pShell );
+ delete pFnt;
+ pFnt = new SwFont( *aFontAccess.Get()->GetFont() );
+
+ // set font to vertical if frame layout is vertical
+ sal_Bool bVertLayout = sal_False;
+ sal_Bool bRTL = sal_False;
+ if ( pFrm )
+ {
+ if ( pFrm->IsVertical() )
+ {
+ bVertLayout = sal_True;
+ pFnt->SetVertical( pFnt->GetOrientation(), sal_True );
+ }
+ bRTL = pFrm->IsRightToLeft();
+ }
+
+ // Initialize the default attribute of the attribute handler
+ // based on the attribute array cached together with the font.
+ // If any further attributes for the paragraph are given in pAttrSet
+ // consider them during construction of the default array, and apply
+ // them to the font
+ aAttrHandler.Init( aFontAccess.Get()->GetDefault(), pAttrSet,
+ *rTxtNode.getIDocumentSettingAccess(), pShell, *pFnt, bVertLayout );
+
+ aMagicNo[SW_LATIN] = aMagicNo[SW_CJK] = aMagicNo[SW_CTL] = NULL;
+
+ // determine script changes if not already done for current paragraph
+ ASSERT( pScriptInfo, "No script info available");
+ if ( pScriptInfo->GetInvalidity() != STRING_LEN )
+ pScriptInfo->InitScriptInfo( rTxtNode, bRTL );
+
+ if ( pBreakIt->GetBreakIter().is() )
+ {
+ pFnt->SetActual( SwScriptInfo::WhichFont( 0, 0, pScriptInfo ) );
+
+ xub_StrLen nChg = 0;
+ USHORT nCnt = 0;
+
+ do
+ {
+ nChg = pScriptInfo->GetScriptChg( nCnt );
+ USHORT nScript = pScriptInfo->GetScriptType( nCnt++ );
+ BYTE nTmp = 4;
+ switch ( nScript ) {
+ case i18n::ScriptType::ASIAN :
+ if( !aMagicNo[SW_CJK] ) nTmp = SW_CJK; break;
+ case i18n::ScriptType::COMPLEX :
+ if( !aMagicNo[SW_CTL] ) nTmp = SW_CTL; break;
+ default:
+ if( !aMagicNo[SW_LATIN ] ) nTmp = SW_LATIN;
+ }
+ if( nTmp < 4 )
+ {
+ pFnt->ChkMagic( pShell, nTmp );
+ pFnt->GetMagic( aMagicNo[ nTmp ], aFntIdx[ nTmp ], nTmp );
+ }
+ } while( nChg < rTxtNode.GetTxt().Len() );
+ }
+ else
+ {
+ pFnt->ChkMagic( pShell, SW_LATIN );
+ pFnt->GetMagic( aMagicNo[ SW_LATIN ], aFntIdx[ SW_LATIN ], SW_LATIN );
+ }
+
+ nStartIndex = nEndIndex = nPos = nChgCnt = 0;
+ nPropFont = 0;
+ SwDoc* pDoc = rTxtNode.GetDoc();
+ const IDocumentRedlineAccess* pIDRA = rTxtNode.getIDocumentRedlineAccess();
+
+ const SwExtTextInput* pExtInp = pDoc->GetExtTextInput( rTxtNode );
+ const bool bShow = IDocumentRedlineAccess::IsShowChanges( pIDRA->GetRedlineMode() );
+ if( pExtInp || bShow )
+ {
+ MSHORT nRedlPos = pIDRA->GetRedlinePos( rTxtNode, USHRT_MAX );
+ if( pExtInp || MSHRT_MAX != nRedlPos )
+ {
+ const SvUShorts* pArr = 0;
+ xub_StrLen nInputStt = 0;
+ if( pExtInp )
+ {
+ pArr = &pExtInp->GetAttrs();
+ nInputStt = pExtInp->Start()->nContent.GetIndex();
+ Seek( 0 );
+ }
+
+ pRedln = new SwRedlineItr( rTxtNode, *pFnt, aAttrHandler, nRedlPos,
+ bShow, pArr, nInputStt );
+
+ if( pRedln->IsOn() )
+ ++nChgCnt;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwRedlineItr - Der Redline-Iterator
+ *
+ * Folgende Informationen/Zustaende gibt es im RedlineIterator:
+ *
+ * nFirst ist der erste Index der RedlineTbl, der mit dem Absatz ueberlappt.
+ *
+ * nAct ist der zur Zeit aktive ( wenn bOn gesetzt ist ) oder der naechste
+ * in Frage kommende Index.
+ * nStart und nEnd geben die Grenzen des Objekts innerhalb des Absatzes an.
+ *
+ * Wenn bOn gesetzt ist, ist der Font entsprechend manipuliert worden.
+ *
+ * Wenn nAct auf MSHRT_MAX gesetzt wurde ( durch Reset() ), so ist zur Zeit
+ * kein Redline aktiv, nStart und nEnd sind invalid.
+ *************************************************************************/
+
+SwRedlineItr::SwRedlineItr( const SwTxtNode& rTxtNd, SwFont& rFnt,
+ SwAttrHandler& rAH, MSHORT nRed, sal_Bool bShw, const SvUShorts *pArr,
+ xub_StrLen nExtStart )
+ : rDoc( *rTxtNd.GetDoc() ), rNd( rTxtNd ), rAttrHandler( rAH ), pSet( 0 ),
+ nNdIdx( rTxtNd.GetIndex() ), nFirst( nRed ),
+ nAct( MSHRT_MAX ), bOn( sal_False ), bShow( bShw )
+{
+ if( pArr )
+ pExt = new SwExtend( *pArr, nExtStart );
+ else
+ pExt = NULL;
+ Seek( rFnt, 0, STRING_LEN );
+}
+
+SwRedlineItr::~SwRedlineItr()
+{
+ Clear( NULL );
+ delete pSet;
+ delete pExt;
+}
+
+// Der Return-Wert von SwRedlineItr::Seek gibt an, ob der aktuelle Font
+// veraendert wurde durch Verlassen (-1) oder Betreten eines Bereichs (+1)
+
+short SwRedlineItr::_Seek( SwFont& rFnt, xub_StrLen nNew, xub_StrLen nOld )
+{
+ short nRet = 0;
+ if( ExtOn() )
+ return 0; // Abkuerzung: wenn wir innerhalb eines ExtendTextInputs sind
+ // kann es keine anderen Attributwechsel (auch nicht durch Redlining) geben
+ if( bShow )
+ {
+ if( bOn )
+ {
+ if( nNew >= nEnd )
+ {
+ --nRet;
+ _Clear( &rFnt ); // Wir gehen hinter den aktuellen Bereich
+ ++nAct; // und pruefen gleich den naechsten
+ }
+ else if( nNew < nStart )
+ {
+ --nRet;
+ _Clear( &rFnt ); // Wir gehen vor den aktuellen Bereich
+ if( nAct > nFirst )
+ nAct = nFirst; // Die Pruefung muss von vorne beginnen
+ else
+ return nRet + EnterExtend( rFnt, nNew ); // Es gibt keinen vor uns.
+ }
+ else
+ return nRet + EnterExtend( rFnt, nNew ); // Wir sind im gleichen Bereich geblieben.
+ }
+ if( MSHRT_MAX == nAct || nOld > nNew )
+ nAct = nFirst;
+
+ nStart = STRING_LEN;
+ nEnd = STRING_LEN;
+
+ for( ; nAct < rDoc.GetRedlineTbl().Count() ; ++nAct )
+ {
+ rDoc.GetRedlineTbl()[ nAct ]->CalcStartEnd( nNdIdx, nStart, nEnd );
+
+ if( nNew < nEnd )
+ {
+ if( nNew >= nStart ) // der einzig moegliche Kandidat
+ {
+ bOn = sal_True;
+ const SwRedline *pRed = rDoc.GetRedlineTbl()[ nAct ];
+
+ if (pSet)
+ pSet->ClearItem();
+ else
+ {
+ SwAttrPool& rPool =
+ const_cast<SwDoc&>(rDoc).GetAttrPool();
+ pSet = new SfxItemSet(rPool, RES_CHRATR_BEGIN, RES_CHRATR_END-1);
+ }
+
+ if( 1 < pRed->GetStackCount() )
+ FillHints( pRed->GetAuthor( 1 ), pRed->GetType( 1 ) );
+ FillHints( pRed->GetAuthor(), pRed->GetType() );
+
+ SfxWhichIter aIter( *pSet );
+ MSHORT nWhich = aIter.FirstWhich();
+ while( nWhich )
+ {
+ const SfxPoolItem* pItem;
+ if( ( nWhich < RES_CHRATR_END ) &&
+ ( SFX_ITEM_SET == pSet->GetItemState( nWhich, sal_True, &pItem ) ) )
+ {
+ SwTxtAttr* pAttr = MakeRedlineTxtAttr(
+ const_cast<SwDoc&>(rDoc),
+ *const_cast<SfxPoolItem*>(pItem) );
+ pAttr->SetPriorityAttr( sal_True );
+ aHints.C40_INSERT( SwTxtAttr, pAttr, aHints.Count());
+ rAttrHandler.PushAndChg( *pAttr, rFnt );
+ if( RES_CHRATR_COLOR == nWhich )
+ rFnt.SetNoCol( sal_True );
+ }
+ nWhich = aIter.NextWhich();
+ }
+
+ ++nRet;
+ }
+ break;
+ }
+ nStart = STRING_LEN;
+ nEnd = STRING_LEN;
+ }
+ }
+ return nRet + EnterExtend( rFnt, nNew );
+}
+
+void SwRedlineItr::FillHints( MSHORT nAuthor, RedlineType_t eType )
+{
+ switch ( eType )
+ {
+ case nsRedlineType_t::REDLINE_INSERT:
+ SW_MOD()->GetInsertAuthorAttr(nAuthor, *pSet);
+ break;
+ case nsRedlineType_t::REDLINE_DELETE:
+ SW_MOD()->GetDeletedAuthorAttr(nAuthor, *pSet);
+ break;
+ case nsRedlineType_t::REDLINE_FORMAT:
+ case nsRedlineType_t::REDLINE_FMTCOLL:
+ SW_MOD()->GetFormatAuthorAttr(nAuthor, *pSet);
+ break;
+ default:
+ break;
+ }
+}
+
+void SwRedlineItr::ChangeTxtAttr( SwFont* pFnt, SwTxtAttr &rHt, sal_Bool bChg )
+{
+ ASSERT( IsOn(), "SwRedlineItr::ChangeTxtAttr: Off?" );
+
+ if( !bShow && !pExt )
+ return;
+
+ if( bChg )
+ {
+ if ( pExt && pExt->IsOn() )
+ rAttrHandler.PushAndChg( rHt, *pExt->GetFont() );
+ else
+ rAttrHandler.PushAndChg( rHt, *pFnt );
+ }
+ else
+ {
+ ASSERT( ! pExt || ! pExt->IsOn(), "Pop of attribute during opened extension" )
+ rAttrHandler.PopAndChg( rHt, *pFnt );
+ }
+}
+
+void SwRedlineItr::_Clear( SwFont* pFnt )
+{
+ ASSERT( bOn, "SwRedlineItr::Clear: Off?" );
+ bOn = sal_False;
+ while( aHints.Count() )
+ {
+ SwTxtAttr *pPos = aHints[ 0 ];
+ aHints.Remove(0);
+ if( pFnt )
+ rAttrHandler.PopAndChg( *pPos, *pFnt );
+ else
+ rAttrHandler.Pop( *pPos );
+ SwTxtAttr::Destroy(pPos, const_cast<SwDoc&>(rDoc).GetAttrPool() );
+ }
+ if( pFnt )
+ pFnt->SetNoCol( sal_False );
+}
+
+xub_StrLen SwRedlineItr::_GetNextRedln( xub_StrLen nNext )
+{
+ nNext = NextExtend( nNext );
+ if( !bShow || MSHRT_MAX == nFirst )
+ return nNext;
+ if( MSHRT_MAX == nAct )
+ {
+ nAct = nFirst;
+ rDoc.GetRedlineTbl()[ nAct ]->CalcStartEnd( nNdIdx, nStart, nEnd );
+ }
+ if( bOn || !nStart )
+ {
+ if( nEnd < nNext )
+ nNext = nEnd;
+ }
+ else if( nStart < nNext )
+ nNext = nStart;
+ return nNext;
+}
+
+sal_Bool SwRedlineItr::_ChkSpecialUnderline() const
+{
+ // Wenn die Unterstreichung oder das Escapement vom Redling kommt,
+ // wenden wir immer das SpecialUnderlining, d.h. die Unterstreichung
+ // unter der Grundlinie an.
+ for( MSHORT i = 0; i < aHints.Count(); ++i )
+ {
+ MSHORT nWhich = aHints[i]->Which();
+ if( RES_CHRATR_UNDERLINE == nWhich ||
+ RES_CHRATR_ESCAPEMENT == nWhich )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+sal_Bool SwRedlineItr::CheckLine( xub_StrLen nChkStart, xub_StrLen nChkEnd )
+{
+ if( nFirst == MSHRT_MAX )
+ return sal_False;
+ if( nChkEnd == nChkStart ) // Leerzeilen gucken ein Zeichen weiter.
+ ++nChkEnd;
+ xub_StrLen nOldStart = nStart;
+ xub_StrLen nOldEnd = nEnd;
+ xub_StrLen nOldAct = nAct;
+ sal_Bool bRet = sal_False;
+
+ for( nAct = nFirst; nAct < rDoc.GetRedlineTbl().Count() ; ++nAct )
+ {
+ rDoc.GetRedlineTbl()[ nAct ]->CalcStartEnd( nNdIdx, nStart, nEnd );
+ if( nChkEnd < nStart )
+ break;
+ if( nChkStart <= nEnd && ( nChkEnd > nStart || STRING_LEN == nEnd ) )
+ {
+ bRet = sal_True;
+ break;
+ }
+ }
+
+ nStart = nOldStart;
+ nEnd = nOldEnd;
+ nAct = nOldAct;
+ return bRet;
+}
+
+void SwExtend::ActualizeFont( SwFont &rFnt, MSHORT nAttr )
+{
+ if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
+ rFnt.SetUnderline( UNDERLINE_SINGLE );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
+ rFnt.SetUnderline( UNDERLINE_BOLD );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
+ rFnt.SetUnderline( UNDERLINE_DOTTED );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
+ rFnt.SetUnderline( UNDERLINE_DOTTED );
+
+ if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
+ rFnt.SetColor( Color( COL_RED ) );
+
+ if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
+ {
+ const StyleSettings& rStyleSettings = GetpApp()->GetSettings().GetStyleSettings();
+ rFnt.SetColor( rStyleSettings.GetHighlightTextColor() );
+ rFnt.SetBackColor( new Color( rStyleSettings.GetHighlightColor() ) );
+ }
+ if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
+ rFnt.SetGreyWave( sal_True );
+}
+
+short SwExtend::Enter( SwFont& rFnt, xub_StrLen nNew )
+{
+ ASSERT( !Inside(), "SwExtend: Enter without Leave" );
+ ASSERT( !pFnt, "SwExtend: Enter with Font" );
+ nPos = nNew;
+ if( Inside() )
+ {
+ pFnt = new SwFont( rFnt );
+ ActualizeFont( rFnt, rArr[ nPos - nStart ] );
+ return 1;
+ }
+ return 0;
+}
+
+sal_Bool SwExtend::_Leave( SwFont& rFnt, xub_StrLen nNew )
+{
+ ASSERT( Inside(), "SwExtend: Leave without Enter" );
+ MSHORT nOldAttr = rArr[ nPos - nStart ];
+ nPos = nNew;
+ if( Inside() )
+ { // Wir sind innerhalb des ExtendText-Bereichs geblieben
+ MSHORT nAttr = rArr[ nPos - nStart ];
+ if( nOldAttr != nAttr ) // Gibt es einen (inneren) Attributwechsel?
+ {
+ rFnt = *pFnt;
+ ActualizeFont( rFnt, nAttr );
+ }
+ }
+ else
+ {
+ rFnt = *pFnt;
+ delete pFnt;
+ pFnt = NULL;
+ return sal_True;
+ }
+ return sal_False;
+}
+
+xub_StrLen SwExtend::Next( xub_StrLen nNext )
+{
+ if( nPos < nStart )
+ {
+ if( nNext > nStart )
+ nNext = nStart;
+ }
+ else if( nPos < nEnd )
+ {
+ MSHORT nIdx = nPos - nStart;
+ MSHORT nAttr = rArr[ nIdx ];
+ while( ++nIdx < rArr.Count() && nAttr == rArr[ nIdx ] )
+ ; //nothing
+ nIdx = nIdx + nStart;
+ if( nNext > nIdx )
+ nNext = nIdx;
+ }
+ return nNext;
+}
diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
new file mode 100644
index 000000000000..466cd5a9ad02
--- /dev/null
+++ b/sw/source/core/text/redlnitr.hxx
@@ -0,0 +1,123 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _REDLNITR_HXX
+#define _REDLNITR_HXX
+
+#include "ndhints.hxx"
+
+#ifndef IDOCUMENTREDLINEACCESS_HXX_INCLUDED
+#include <IDocumentRedlineAccess.hxx>
+#endif
+
+#include "swfont.hxx"
+#ifndef _SVSTDARR_USHORTS
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+#endif
+
+class SwTxtNode;
+class SwDoc;
+class SfxItemSet;
+class SwAttrHandler;
+
+class SwExtend
+{
+ SwFont *pFnt;
+ const SvUShorts &rArr; // XAMA: Array of xub_StrLen
+ xub_StrLen nStart;
+ xub_StrLen nPos;
+ xub_StrLen nEnd;
+ sal_Bool _Leave( SwFont& rFnt, xub_StrLen nNew );
+ sal_Bool Inside() const { return ( nPos >= nStart && nPos < nEnd ); }
+ void ActualizeFont( SwFont &rFnt, xub_StrLen nAttr );
+public:
+ SwExtend( const SvUShorts &rA, xub_StrLen nSt ) : pFnt(0), rArr( rA ),
+ nStart( nSt ), nPos( STRING_LEN ), nEnd( nStart + rA.Count() ) {}
+ ~SwExtend() { delete pFnt; }
+ sal_Bool IsOn() const { return pFnt != 0; }
+ void Reset() { if( pFnt ) { delete pFnt; pFnt = NULL; } nPos = STRING_LEN; }
+ sal_Bool Leave( SwFont& rFnt, xub_StrLen nNew )
+ { if( pFnt ) return _Leave( rFnt, nNew ); return sal_False; }
+ short Enter( SwFont& rFnt, xub_StrLen nNew );
+ xub_StrLen Next( xub_StrLen nNext );
+ SwFont* GetFont() { return pFnt; }
+ void UpdateFont( SwFont &rFnt ) { ActualizeFont( rFnt, rArr[ nPos - nStart ] ); }
+};
+
+class SwRedlineItr
+{
+ SwpHtStart_SAR aHints;
+ const SwDoc& rDoc;
+ const SwTxtNode& rNd;
+ SwAttrHandler& rAttrHandler;
+ SfxItemSet *pSet;
+ SwExtend *pExt;
+ ULONG nNdIdx;
+ xub_StrLen nFirst;
+ xub_StrLen nAct;
+ xub_StrLen nStart;
+ xub_StrLen nEnd;
+ sal_Bool bOn;
+ sal_Bool bShow;
+
+ void _Clear( SwFont* pFnt );
+ sal_Bool _ChkSpecialUnderline() const;
+ void FillHints( MSHORT nAuthor, RedlineType_t eType );
+ short _Seek( SwFont& rFnt, xub_StrLen nNew, xub_StrLen nOld );
+ xub_StrLen _GetNextRedln( xub_StrLen nNext );
+ inline short EnterExtend( SwFont& rFnt, xub_StrLen nNew )
+ { if( pExt ) return pExt->Enter( rFnt, nNew ); return 0; }
+ inline xub_StrLen NextExtend( xub_StrLen nNext )
+ { if( pExt ) return pExt->Next( nNext ); return nNext; }
+public:
+ SwRedlineItr( const SwTxtNode& rTxtNd, SwFont& rFnt, SwAttrHandler& rAH,
+ xub_StrLen nRedlPos, sal_Bool bShw, const SvUShorts *pArr = 0,
+ xub_StrLen nStart = STRING_LEN );
+ ~SwRedlineItr();
+ inline sal_Bool IsOn() const { return bOn || ( pExt && pExt->IsOn() ); }
+ inline void Clear( SwFont* pFnt ) { if( bOn ) _Clear( pFnt ); }
+ void ChangeTxtAttr( SwFont* pFnt, SwTxtAttr &rHt, sal_Bool bChg );
+ inline short Seek( SwFont& rFnt, xub_StrLen nNew, xub_StrLen nOld )
+ { if( bShow || pExt ) return _Seek( rFnt, nNew, nOld ); return 0; }
+ inline void Reset() { if( nAct != nFirst ) nAct = STRING_LEN;
+ if( pExt ) pExt->Reset(); }
+ inline xub_StrLen GetNextRedln( xub_StrLen nNext )
+ { if( bShow || pExt ) return _GetNextRedln( nNext ); return nNext; }
+ inline sal_Bool ChkSpecialUnderline() const
+ { if ( IsOn() ) return _ChkSpecialUnderline(); return sal_False; }
+ sal_Bool CheckLine( xub_StrLen nChkStart, xub_StrLen nChkEnd );
+ inline sal_Bool LeaveExtend( SwFont& rFnt, xub_StrLen nNew )
+ { return pExt->Leave(rFnt, nNew ); }
+ inline sal_Bool ExtOn() { if( pExt ) return pExt->IsOn(); return sal_False; }
+ inline void UpdateExtFont( SwFont &rFnt ) {
+ ASSERT( ExtOn(), "UpdateExtFont without ExtOn" )
+ pExt->UpdateFont( rFnt ); }
+};
+
+
+#endif
+
diff --git a/sw/source/core/text/txtcache.cxx b/sw/source/core/text/txtcache.cxx
new file mode 100644
index 000000000000..6a54639390dd
--- /dev/null
+++ b/sw/source/core/text/txtcache.cxx
@@ -0,0 +1,241 @@
+/*************************************************************************
+ *
+ * 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 "errhdl.hxx"
+
+#include "txtcache.hxx"
+#include "txtfrm.hxx"
+#include "porlay.hxx"
+
+/*************************************************************************
+|*
+|* SwTxtLine::SwTxtLine(), ~SwTxtLine()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 16. Mar. 94
+|*
+|*************************************************************************/
+
+SwTxtLine::SwTxtLine( SwTxtFrm *pFrm, SwParaPortion *pNew ) :
+ SwCacheObj( (void*)pFrm ),
+ pLine( pNew )
+{
+}
+
+SwTxtLine::~SwTxtLine()
+{
+ delete pLine;
+}
+
+/*************************************************************************
+|*
+|* SwTxtLineAccess::NewObj()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 16. Mar. 94
+|*
+|*************************************************************************/
+
+SwCacheObj *SwTxtLineAccess::NewObj()
+{
+ return new SwTxtLine( (SwTxtFrm*)pOwner );
+}
+
+/*************************************************************************
+|*
+|* SwTxtLineAccess::GetPara()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 16. Mar. 94
+|*
+|*************************************************************************/
+
+SwParaPortion *SwTxtLineAccess::GetPara()
+{
+ SwTxtLine *pRet;
+ if ( pObj )
+ pRet = (SwTxtLine*)pObj;
+ else
+ {
+ pRet = (SwTxtLine*)Get();
+ ((SwTxtFrm*)pOwner)->SetCacheIdx( pRet->GetCachePos() );
+ }
+ if ( !pRet->GetPara() )
+ pRet->SetPara( new SwParaPortion );
+ return pRet->GetPara();
+}
+
+
+/*************************************************************************
+|*
+|* SwTxtLineAccess::SwTxtLineAccess()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 16. Mar. 94
+|*
+|*************************************************************************/
+
+SwTxtLineAccess::SwTxtLineAccess( const SwTxtFrm *pOwn ) :
+ SwCacheAccess( *SwTxtFrm::GetTxtCache(), pOwn, pOwn->GetCacheIdx() )
+{
+}
+
+/*************************************************************************
+|*
+|* SwTxtLineAccess::IsAvailable
+|*
+|* Ersterstellung MA 23. Mar. 94
+|* Letzte Aenderung MA 23. Mar. 94
+|*
+|*************************************************************************/
+
+sal_Bool SwTxtLineAccess::IsAvailable() const
+{
+ if ( pObj )
+ return ((SwTxtLine*)pObj)->GetPara() != 0;
+ return sal_False;
+}
+
+/*************************************************************************
+|*
+|* SwTxtFrm::HasPara()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 22. Aug. 94
+|*
+|*************************************************************************/
+
+sal_Bool SwTxtFrm::_HasPara() const
+{
+ SwTxtLine *pTxtLine = (SwTxtLine*)SwTxtFrm::GetTxtCache()->
+ Get( this, GetCacheIdx(), sal_False );
+ if ( pTxtLine )
+ {
+ if ( pTxtLine->GetPara() )
+ return sal_True;
+ }
+ else
+ ((SwTxtFrm*)this)->nCacheIdx = MSHRT_MAX;
+
+ return sal_False;
+}
+
+/*************************************************************************
+|*
+|* SwTxtFrm::GetPara()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 22. Aug. 94
+|*
+|*************************************************************************/
+
+SwParaPortion *SwTxtFrm::GetPara()
+{
+ if ( GetCacheIdx() != MSHRT_MAX )
+ { SwTxtLine *pLine = (SwTxtLine*)SwTxtFrm::GetTxtCache()->
+ Get( this, GetCacheIdx(), sal_False );
+ if ( pLine )
+ return pLine->GetPara();
+ else
+ nCacheIdx = MSHRT_MAX;
+ }
+ return 0;
+}
+
+
+/*************************************************************************
+|*
+|* SwTxtFrm::ClearPara()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 22. Aug. 94
+|*
+|*************************************************************************/
+
+void SwTxtFrm::ClearPara()
+{
+ ASSERT( !IsLocked(), "+SwTxtFrm::ClearPara: this is locked." );
+ if ( !IsLocked() && GetCacheIdx() != MSHRT_MAX )
+ {
+ SwTxtLine *pTxtLine = (SwTxtLine*)SwTxtFrm::GetTxtCache()->
+ Get( this, GetCacheIdx(), sal_False );
+ if ( pTxtLine )
+ {
+ delete pTxtLine->GetPara();
+ pTxtLine->SetPara( 0 );
+ }
+ else
+ nCacheIdx = MSHRT_MAX;
+ }
+}
+
+/*************************************************************************
+|*
+|* SwTxtFrm::SetPara()
+|*
+|* Ersterstellung MA 16. Mar. 94
+|* Letzte Aenderung MA 22. Aug. 94
+|*
+|*************************************************************************/
+
+void SwTxtFrm::SetPara( SwParaPortion *pNew, sal_Bool bDelete )
+{
+ if ( GetCacheIdx() != MSHRT_MAX )
+ {
+ //Nur die Information Auswechseln, das CacheObj bleibt stehen.
+ SwTxtLine *pTxtLine = (SwTxtLine*)SwTxtFrm::GetTxtCache()->
+ Get( this, GetCacheIdx(), sal_False );
+ if ( pTxtLine )
+ {
+ if( bDelete )
+ delete pTxtLine->GetPara();
+ pTxtLine->SetPara( pNew );
+ }
+ else
+ {
+ ASSERT( !pNew, "+SetPara: Losing SwParaPortion" );
+ nCacheIdx = MSHRT_MAX;
+ }
+ }
+ else if ( pNew )
+ { //Einen neuen einfuegen.
+ SwTxtLine *pTxtLine = new SwTxtLine( this, pNew );
+ if ( SwTxtFrm::GetTxtCache()->Insert( pTxtLine ) )
+ nCacheIdx = pTxtLine->GetCachePos();
+ else
+ {
+ ASSERT( sal_False, "+SetPara: InsertCache failed." );
+ }
+ }
+}
+
+
diff --git a/sw/source/core/text/txtcache.hxx b/sw/source/core/text/txtcache.hxx
new file mode 100644
index 000000000000..d484f8f1c7f5
--- /dev/null
+++ b/sw/source/core/text/txtcache.hxx
@@ -0,0 +1,76 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _TXTCACHE_HXX
+#define _TXTCACHE_HXX
+
+#include <sal/types.h>
+#include <tools/mempool.hxx>
+#include "swcache.hxx"
+
+class SwParaPortion;
+class SwTxtFrm;
+
+class SwTxtLine : public SwCacheObj
+{
+ SwParaPortion *pLine;
+
+public:
+ DECL_FIXEDMEMPOOL_NEWDEL(SwTxtLine)
+
+ SwTxtLine( SwTxtFrm *pFrm, SwParaPortion *pNew = 0 );
+ virtual ~SwTxtLine();
+
+ inline SwParaPortion *GetPara() { return pLine; }
+ inline const SwParaPortion *GetPara() const { return pLine; }
+
+ inline void SetPara( SwParaPortion *pNew ) { pLine = pNew; }
+};
+
+
+class SwTxtLineAccess : public SwCacheAccess
+{
+
+protected:
+ virtual SwCacheObj *NewObj();
+
+public:
+ SwTxtLineAccess( const SwTxtFrm *pOwner );
+
+ SwParaPortion *GetPara();
+
+ inline SwTxtLine &GetTxtLine();
+
+ virtual sal_Bool IsAvailable() const;
+};
+
+
+inline SwTxtLine &SwTxtLineAccess::GetTxtLine()
+{
+ return *((SwTxtLine*)Get());
+}
+
+#endif
diff --git a/sw/source/core/text/txtcfg.hxx b/sw/source/core/text/txtcfg.hxx
new file mode 100644
index 000000000000..b72fbfb1bd47
--- /dev/null
+++ b/sw/source/core/text/txtcfg.hxx
@@ -0,0 +1,54 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _TXTCFG_HXX
+#define _TXTCFG_HXX
+
+#if OSL_DEBUG_LEVEL > 1
+#include "dbgloop.hxx" // DBG_LOOP
+#else
+#ifdef DBG_LOOP //kann per precompiled hereinkommen
+#undef DBG_LOOP
+#undef DBG_LOOP_RESET
+#endif
+#define DBG_LOOP
+#define DBG_LOOP_RESET
+#endif
+
+// Toleranzwert in der Formatierung und Textausgabe.
+#define SLOPPY_TWIPS 5
+
+#define CONSTCHAR( name, string ) static const sal_Char __FAR_DATA name[] = string
+
+// Allgemeines ...
+
+#ifndef CONST
+#define CONST const
+#endif
+
+
+#endif
diff --git a/sw/source/core/text/txtdrop.cxx b/sw/source/core/text/txtdrop.cxx
new file mode 100644
index 000000000000..3e67e1037dfe
--- /dev/null
+++ b/sw/source/core/text/txtdrop.cxx
@@ -0,0 +1,1105 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <paratr.hxx>
+#include <txtfrm.hxx> // Format()
+#include <charfmt.hxx>
+#include <viewopt.hxx> // SwViewOption
+#include <viewsh.hxx> // ViewShell
+#include <pordrop.hxx>
+#include <itrform2.hxx>
+#include <txtpaint.hxx> // SwSaveClip
+#include <blink.hxx> // pBlink
+#include <breakit.hxx>
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <com/sun/star/i18n/WordType.hpp>
+#include <editeng/langitem.hxx>
+#include <charatr.hxx>
+#include <editeng/fhgtitem.hxx>
+
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * lcl_IsDropFlyInter
+ *
+ * Calculates if a drop caps portion intersects with a fly
+ * The width and height of the drop caps portion are passed as arguments,
+ * the position is calculated from the values in rInf
+ *************************************************************************/
+
+sal_Bool lcl_IsDropFlyInter( const SwTxtFormatInfo &rInf,
+ USHORT nWidth, USHORT nHeight )
+{
+ const SwTxtFly *pTxtFly = rInf.GetTxtFly();
+ if( pTxtFly && pTxtFly->IsOn() )
+ {
+ SwRect aRect( rInf.GetTxtFrm()->Frm().Pos(), Size( nWidth, nHeight) );
+ aRect.Pos() += rInf.GetTxtFrm()->Prt().Pos();
+ aRect.Pos().X() += rInf.X();
+ aRect.Pos().Y() = rInf.Y();
+ aRect = pTxtFly->GetFrm( aRect );
+ return aRect.HasArea();
+ }
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * class SwDropSave
+ *************************************************************************/
+
+class SwDropSave
+{
+ SwTxtPaintInfo* pInf;
+ xub_StrLen nIdx;
+ xub_StrLen nLen;
+ long nX;
+ long nY;
+
+public:
+ SwDropSave( const SwTxtPaintInfo &rInf );
+ ~SwDropSave();
+};
+
+SwDropSave::SwDropSave( const SwTxtPaintInfo &rInf ) :
+ pInf( ((SwTxtPaintInfo*)&rInf) ), nIdx( rInf.GetIdx() ),
+ nLen( rInf.GetLen() ), nX( rInf.X() ), nY( rInf.Y() )
+{
+}
+
+SwDropSave::~SwDropSave()
+{
+ pInf->SetIdx( nIdx );
+ pInf->SetLen( nLen );
+ pInf->X( nX );
+ pInf->Y( nY );
+}
+
+/*************************************************************************
+ * SwDropPortionPart DTor
+ *************************************************************************/
+
+SwDropPortionPart::~SwDropPortionPart()
+{
+ if ( pFollow )
+ delete pFollow;
+ delete pFnt;
+}
+
+/*************************************************************************
+ * SwDropPortion CTor, DTor
+ *************************************************************************/
+
+SwDropPortion::SwDropPortion( const MSHORT nLineCnt,
+ const KSHORT nDrpHeight,
+ const KSHORT nDrpDescent,
+ const KSHORT nDist )
+ : pPart( 0 ),
+ nLines( nLineCnt ),
+ nDropHeight(nDrpHeight),
+ nDropDescent(nDrpDescent),
+ nDistance(nDist),
+ nFix(0),
+ nX(0)
+{
+ SetWhichPor( POR_DROP );
+}
+
+SwDropPortion::~SwDropPortion()
+{
+ delete pPart;
+ if( pBlink )
+ pBlink->Delete( this );
+}
+
+sal_Bool SwTxtSizeInfo::_HasHint( const SwTxtNode* pTxtNode, xub_StrLen nPos )
+{
+ return 0 != pTxtNode->GetTxtAttrForCharAt(nPos);
+}
+
+/*************************************************************************
+ * SwTxtNode::GetDropLen()
+ *
+ * nWishLen = 0 indicates that we want a whole word
+ *************************************************************************/
+
+MSHORT SwTxtNode::GetDropLen( MSHORT nWishLen ) const
+{
+ xub_StrLen nEnd = GetTxt().Len();
+ if( nWishLen && nWishLen < nEnd )
+ nEnd = nWishLen;
+
+ if ( ! nWishLen && pBreakIt->GetBreakIter().is() )
+ {
+ // find first word
+ const SwAttrSet& rAttrSet = GetSwAttrSet();
+ const USHORT nTxtScript = pBreakIt->GetRealScriptOfText( GetTxt(), 0 );
+
+ LanguageType eLanguage;
+
+ switch ( nTxtScript )
+ {
+ case i18n::ScriptType::ASIAN :
+ eLanguage = rAttrSet.GetCJKLanguage().GetLanguage();
+ break;
+ case i18n::ScriptType::COMPLEX :
+ eLanguage = rAttrSet.GetCTLLanguage().GetLanguage();
+ break;
+ default :
+ eLanguage = rAttrSet.GetLanguage().GetLanguage();
+ break;
+ }
+
+ Boundary aBound =
+ pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), 0,
+ pBreakIt->GetLocale( eLanguage ), WordType::DICTIONARY_WORD, sal_True );
+
+ nEnd = (xub_StrLen)aBound.endPos;
+ }
+
+ xub_StrLen i = 0;
+ for( ; i < nEnd; ++i )
+ {
+ xub_Unicode cChar = GetTxt().GetChar( i );
+ if( CH_TAB == cChar || CH_BREAK == cChar ||
+ (( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar )
+ && SwTxtSizeInfo::_HasHint( this, i ) ) )
+ break;
+ }
+ return i;
+}
+
+/*************************************************************************
+ * SwTxtNode::GetDropSize()
+ *
+ * If a dropcap is found the return value is true otherwise false. The
+ * drop cap sizes passed back by reference are font height, drop height
+ * and drop descent.
+ *************************************************************************/
+bool SwTxtNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const
+{
+ rFontHeight = 0;
+ rDropHeight = 0;
+ rDropDescent =0;
+
+ const SwAttrSet& rSet = GetSwAttrSet();
+ const SwFmtDrop& rDrop = rSet.GetDrop();
+
+ // Return (0,0) if there is no drop cap at this paragraph
+ if( 1 >= rDrop.GetLines() ||
+ ( !rDrop.GetChars() && !rDrop.GetWholeWord() ) )
+ {
+ return false;
+ }
+
+ // get text frame
+ SwClientIter aClientIter( (SwTxtNode&)*this );
+ SwClient* pLastFrm = aClientIter.GoStart();
+
+ while( pLastFrm )
+ {
+ // Only (master-) text frames can have a drop cap.
+ if ( pLastFrm->ISA( SwTxtFrm ) && !((SwTxtFrm*)pLastFrm)->IsFollow() )
+ {
+
+ if( !((SwTxtFrm*)pLastFrm)->HasPara() )
+ ((SwTxtFrm*)pLastFrm)->GetFormatted();
+
+ if ( !((SwTxtFrm*)pLastFrm)->IsEmpty() )
+ {
+ const SwParaPortion* pPara = ((SwTxtFrm*)pLastFrm)->GetPara();
+ ASSERT( pPara, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" )
+
+ if ( pPara )
+ {
+ const SwLinePortion* pFirstPor = pPara->GetFirstPortion();
+ if (pFirstPor && pFirstPor->IsDropPortion())
+ {
+ const SwDropPortion* pDrop = (const SwDropPortion*)pFirstPor;
+ rDropHeight = pDrop->GetDropHeight();
+ rDropDescent = pDrop->GetDropDescent();
+ if (const SwFont *pFont = pDrop->GetFnt())
+ rFontHeight = pFont->GetSize(pFont->GetActual()).Height();
+ else
+ {
+ const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get(RES_CHRATR_FONTSIZE);
+ rFontHeight = rItem.GetHeight();
+ }
+ }
+ }
+ }
+ break;
+ }
+ pLastFrm = ++aClientIter;
+ }
+
+ if (rFontHeight==0 && rDropHeight==0 && rDropDescent==0)
+ {
+ const USHORT nLines = rDrop.GetLines();
+
+ const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get( RES_CHRATR_FONTSIZE );
+ rFontHeight = rItem.GetHeight();
+ rDropHeight = nLines * rFontHeight;
+ rDropDescent = rFontHeight / 5;
+ return false;
+ }
+
+ return true;
+}
+
+/*************************************************************************
+ * SwDropPortion::PaintTxt()
+ *************************************************************************/
+
+// Die Breite manipulieren, sonst werden die Buchstaben gestretcht
+
+void SwDropPortion::PaintTxt( const SwTxtPaintInfo &rInf ) const
+{
+ if ( rInf.OnWin() &&
+ !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
+ rInf.DrawBackground( *this );
+
+ ASSERT( nDropHeight && pPart && nLines != 1, "Drop Portion painted twice" );
+
+ const SwDropPortionPart* pCurrPart = GetPart();
+ const xub_StrLen nOldLen = GetLen();
+
+ const SwTwips nBasePosY = rInf.Y();
+ ((SwTxtPaintInfo&)rInf).Y( nBasePosY + nY );
+ SwDropSave aSave( rInf );
+ // for text inside drop portions we let vcl handle the text directions
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ aLayoutModeModifier.SetAuto();
+
+ while ( pCurrPart )
+ {
+ ((SwDropPortion*)this)->SetLen( pCurrPart->GetLen() );
+ ((SwTxtPaintInfo&)rInf).SetLen( pCurrPart->GetLen() );
+ SwFontSave aFontSave( rInf, &pCurrPart->GetFont() );
+
+ SwTxtPortion::Paint( rInf );
+
+ ((SwTxtPaintInfo&)rInf).SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
+ ((SwTxtPaintInfo&)rInf).X( rInf.X() + pCurrPart->GetWidth() );
+ pCurrPart = pCurrPart->GetFollow();
+ }
+
+ ((SwTxtPaintInfo&)rInf).Y( nBasePosY );
+ ((SwDropPortion*)this)->SetLen( nOldLen );
+}
+
+/*************************************************************************
+ * SwDropPortion::Paint()
+ *************************************************************************/
+
+void SwDropPortion::PaintDrop( const SwTxtPaintInfo &rInf ) const
+{
+ // ganz normale Ausgabe wird w?hrend des normalen Paints erledigt
+ if( ! nDropHeight || ! pPart || nLines == 1 )
+ return;
+
+ // Luegenwerte einstellen!
+ const KSHORT nOldHeight = Height();
+ const KSHORT nOldWidth = Width();
+ const KSHORT nOldAscent = GetAscent();
+ const SwTwips nOldPosY = rInf.Y();
+ const KSHORT nOldPosX = (KSHORT)rInf.X();
+ const SwParaPortion *pPara = rInf.GetParaPortion();
+ const Point aOutPos( nOldPosX + nX, nOldPosY - pPara->GetAscent()
+ - pPara->GetRealHeight() + pPara->Height() );
+ // Retusche nachholen.
+
+ // Set baseline
+ ((SwTxtPaintInfo&)rInf).Y( aOutPos.Y() + nDropHeight );
+
+ // for background
+ ((SwDropPortion*)this)->Height( nDropHeight + nDropDescent );
+ ((SwDropPortion*)this)->Width( Width() - nX );
+ ((SwDropPortion*)this)->SetAscent( nDropHeight );
+
+ // Clipregion auf uns einstellen!
+ // Und zwar immer, und nie mit dem bestehenden ClipRect
+ // verrechnen, weil dies auf die Zeile eingestellt sein koennte.
+
+ SwRect aClipRect;
+ if ( rInf.OnWin() )
+ {
+ aClipRect = SwRect( aOutPos, SvLSize() );
+ aClipRect.Intersection( rInf.GetPaintRect() );
+ }
+ SwSaveClip aClip( (OutputDevice*)rInf.GetOut() );
+ aClip.ChgClip( aClipRect, rInf.GetTxtFrm() );
+ // Das machen, was man sonst nur macht ...
+ PaintTxt( rInf );
+
+ // Alte Werte sichern
+ ((SwDropPortion*)this)->Height( nOldHeight );
+ ((SwDropPortion*)this)->Width( nOldWidth );
+ ((SwDropPortion*)this)->SetAscent( nOldAscent );
+ ((SwTxtPaintInfo&)rInf).Y( nOldPosY );
+}
+
+/*************************************************************************
+ * virtual SwDropPortion::Paint()
+ *************************************************************************/
+
+void SwDropPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // ganz normale Ausgabe wird hier erledigt.
+ if( ! nDropHeight || ! pPart || 1 == nLines )
+ {
+ if ( rInf.OnWin() &&
+ !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
+ rInf.DrawBackground( *this );
+
+ // make sure that font is not rotated
+ SwFont* pTmpFont = 0;
+ if ( rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() ) )
+ {
+ pTmpFont = new SwFont( *rInf.GetFont() );
+ pTmpFont->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() );
+ }
+
+ SwFontSave aFontSave( rInf, pTmpFont );
+ // for text inside drop portions we let vcl handle the text directions
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ aLayoutModeModifier.SetAuto();
+
+ SwTxtPortion::Paint( rInf );
+ delete pTmpFont;
+ }
+}
+
+/*************************************************************************
+ * virtual Format()
+ *************************************************************************/
+
+
+sal_Bool SwDropPortion::FormatTxt( SwTxtFormatInfo &rInf )
+{
+ const xub_StrLen nOldLen = GetLen();
+ const xub_StrLen nOldInfLen = rInf.GetLen();
+ const sal_Bool bFull = SwTxtPortion::Format( rInf );
+ if( bFull )
+ {
+ // sieht zwar Scheisse aus, aber was soll man schon machen?
+ rInf.SetUnderFlow( 0 );
+ Truncate();
+ SetLen( nOldLen );
+ rInf.SetLen( nOldInfLen );
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual GetTxtSize()
+ *************************************************************************/
+
+
+SwPosSize SwDropPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
+{
+ USHORT nMyX = 0;
+ xub_StrLen nIdx = 0;
+
+ const SwDropPortionPart* pCurrPart = GetPart();
+
+ // skip parts
+ while ( pCurrPart && nIdx + pCurrPart->GetLen() < rInf.GetLen() )
+ {
+ nMyX = nMyX + pCurrPart->GetWidth();
+ nIdx = nIdx + pCurrPart->GetLen();
+ pCurrPart = pCurrPart->GetFollow();
+ }
+
+ xub_StrLen nOldIdx = rInf.GetIdx();
+ xub_StrLen nOldLen = rInf.GetLen();
+
+ ((SwTxtSizeInfo&)rInf).SetIdx( nIdx );
+ ((SwTxtSizeInfo&)rInf).SetLen( rInf.GetLen() - nIdx );
+
+ // robust
+ SwFontSave aFontSave( rInf, pCurrPart ? &pCurrPart->GetFont() : 0 );
+ SwPosSize aPosSize( SwTxtPortion::GetTxtSize( rInf ) );
+ aPosSize.Width( aPosSize.Width() + nMyX );
+
+ ((SwTxtSizeInfo&)rInf).SetIdx( nOldIdx );
+ ((SwTxtSizeInfo&)rInf).SetLen( nOldLen );
+
+ return aPosSize;
+}
+
+/*************************************************************************
+ * virtual GetCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwDropPortion::GetCrsrOfst( const KSHORT ) const
+{
+ return 0;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcDropHeight()
+ *************************************************************************/
+
+void SwTxtFormatter::CalcDropHeight( const MSHORT nLines )
+{
+ const SwLinePortion *const pOldCurr = GetCurr();
+ KSHORT nDropHght = 0;
+ KSHORT nAscent = 0;
+ KSHORT nHeight = 0;
+ KSHORT nDropLns = 0;
+ sal_Bool bRegisterOld = IsRegisterOn();
+ bRegisterOn = sal_False;
+
+ Top();
+
+ while( GetCurr()->IsDummy() )
+ {
+ if ( !Next() )
+ break;
+ }
+
+ // Wenn wir nur eine Zeile haben returnen wir 0
+ if( GetNext() || GetDropLines() == 1 )
+ {
+ for( ; nDropLns < nLines; nDropLns++ )
+ {
+ if ( GetCurr()->IsDummy() )
+ break;
+ else
+ {
+ CalcAscentAndHeight( nAscent, nHeight );
+ nDropHght = nDropHght + nHeight;
+ bRegisterOn = bRegisterOld;
+ }
+ if ( !Next() )
+ {
+ nDropLns++; // Fix: 11356
+ break;
+ }
+ }
+
+ // In der letzten Zeile plumpsen wir auf den Zeilenascent!
+ nDropHght = nDropHght - nHeight;
+ nDropHght = nDropHght + nAscent;
+ Top();
+ }
+ bRegisterOn = bRegisterOld;
+ SetDropDescent( nHeight - nAscent );
+ SetDropHeight( nDropHght );
+ SetDropLines( nDropLns );
+ // Alte Stelle wiederfinden!
+ while( pOldCurr != GetCurr() )
+ {
+ if( !Next() )
+ {
+ ASSERT( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
+ break;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::GuessDropHeight()
+ *
+ * Wir schaetzen mal, dass die Fonthoehe sich nicht aendert und dass
+ * erst mindestens soviele Zeilen gibt, wie die DropCap-Einstellung angibt.
+ *
+ *************************************************************************/
+
+
+
+void SwTxtFormatter::GuessDropHeight( const MSHORT nLines )
+{
+ ASSERT( nLines, "GuessDropHeight: Give me more Lines!" );
+ KSHORT nAscent = 0;
+ KSHORT nHeight = 0;
+ SetDropLines( nLines );
+ if ( GetDropLines() > 1 )
+ {
+ CalcRealHeight();
+ CalcAscentAndHeight( nAscent, nHeight );
+ }
+ SetDropDescent( nHeight - nAscent );
+ SetDropHeight( nHeight * nLines - GetDropDescent() );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewDropPortion
+ *************************************************************************/
+
+SwDropPortion *SwTxtFormatter::NewDropPortion( SwTxtFormatInfo &rInf )
+{
+ if( !pDropFmt )
+ return 0;
+
+ xub_StrLen nPorLen = pDropFmt->GetWholeWord() ? 0 : pDropFmt->GetChars();
+ nPorLen = pFrm->GetTxtNode()->GetDropLen( nPorLen );
+ if( !nPorLen )
+ {
+ ((SwTxtFormatter*)this)->ClearDropFmt();
+ return 0;
+ }
+
+ SwDropPortion *pDropPor = 0;
+
+ // erste oder zweite Runde?
+ if ( !( GetDropHeight() || IsOnceMore() ) )
+ {
+ if ( GetNext() )
+ CalcDropHeight( pDropFmt->GetLines() );
+ else
+ GuessDropHeight( pDropFmt->GetLines() );
+ }
+
+ // the DropPortion
+ if( GetDropHeight() )
+ pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(),
+ GetDropDescent(), pDropFmt->GetDistance() );
+ else
+ pDropPor = new SwDropPortion( 0,0,0,pDropFmt->GetDistance() );
+
+ pDropPor->SetLen( nPorLen );
+
+ // If it was not possible to create a proper drop cap portion
+ // due to avoiding endless loops. We return a drop cap portion
+ // with an empty SwDropCapPart. For these portions the current
+ // font is used.
+ if ( GetDropLines() < 2 )
+ {
+ ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
+ return pDropPor;
+ }
+
+ // build DropPortionParts:
+ ASSERT( ! rInf.GetIdx(), "Drop Portion not at 0 position!" );
+ xub_StrLen nNextChg = 0;
+ const SwCharFmt* pFmt = pDropFmt->GetCharFmt();
+ SwDropPortionPart* pCurrPart = 0;
+
+ while ( nNextChg < nPorLen )
+ {
+ // check for attribute changes and if the portion has to split:
+ Seek( nNextChg );
+
+ // the font is deleted in the destructor of the drop portion part
+ SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
+ if ( pFmt )
+ {
+ const SwAttrSet& rSet = pFmt->GetAttrSet();
+ pTmpFnt->SetDiffFnt( &rSet, pFrm->GetTxtNode()->getIDocumentSettingAccess() );
+ }
+
+ // we do not allow a vertical font for the drop portion
+ pTmpFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() );
+
+ // find next attribute change / script change
+ const xub_StrLen nTmpIdx = nNextChg;
+ xub_StrLen nNextAttr = Min( GetNextAttr(), rInf.GetTxt().Len() );
+ nNextChg = pScriptInfo->NextScriptChg( nTmpIdx );
+ if( nNextChg > nNextAttr )
+ nNextChg = nNextAttr;
+ if ( nNextChg > nPorLen )
+ nNextChg = nPorLen;
+
+ SwDropPortionPart* pPart =
+ new SwDropPortionPart( *pTmpFnt, nNextChg - nTmpIdx );
+
+ if ( ! pCurrPart )
+ pDropPor->SetPart( pPart );
+ else
+ pCurrPart->SetFollow( pPart );
+
+ pCurrPart = pPart;
+ }
+
+ ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
+ return pDropPor;
+}
+
+/*************************************************************************
+ * SwTxtPainter::PaintDropPortion()
+ *************************************************************************/
+
+
+
+void SwTxtPainter::PaintDropPortion()
+{
+ const SwDropPortion *pDrop = GetInfo().GetParaPortion()->FindDropPortion();
+ ASSERT( pDrop, "DrapCop-Portion not available." );
+ if( !pDrop )
+ return;
+
+ const SwTwips nOldY = GetInfo().Y();
+
+ Top();
+
+ GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
+ GetInfo().ResetSpaceIdx();
+ GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
+ GetInfo().ResetKanaIdx();
+
+ // 8047: Drops und Dummies
+ while( !pCurr->GetLen() && Next() )
+ ;
+
+ // MarginPortion und Adjustment!
+ const SwLinePortion *pPor = pCurr->GetFirstPortion();
+ KSHORT nX = 0;
+ while( pPor && !pPor->IsDropPortion() )
+ {
+ nX = nX + pPor->Width();
+ pPor = pPor->GetPortion();
+ }
+ Point aLineOrigin( GetTopLeft() );
+
+#ifdef NIE
+ // Retusche nachholen...
+ if( nX )
+ {
+ const Point aPoint( Left(), Y() );
+ const Size aSize( nX - 1, GetDropHeight()+GetDropDescent() );
+ SwRect aRetouche( aPoint, aSize );
+ GetInfo().DrawRect( aRetouche );
+ }
+#endif
+
+ aLineOrigin.X() += nX;
+ KSHORT nTmpAscent, nTmpHeight;
+ CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+ aLineOrigin.Y() += nTmpAscent;
+ GetInfo().SetIdx( GetStart() );
+ GetInfo().SetPos( aLineOrigin );
+ GetInfo().SetLen( pDrop->GetLen() );
+
+ pDrop->PaintDrop( GetInfo() );
+
+ GetInfo().Y( nOldY );
+}
+
+/*************************************************************************
+ * clas SwDropCapCache
+ *
+ * Da die Berechnung der Fontgroesse der Initialen ein teures Geschaeft ist,
+ * wird dies durch einen DropCapCache geschleust.
+ *************************************************************************/
+
+#define DROP_CACHE_SIZE 10
+
+class SwDropCapCache
+{
+ long aMagicNo[ DROP_CACHE_SIZE ];
+ XubString aTxt[ DROP_CACHE_SIZE ];
+ USHORT aFactor[ DROP_CACHE_SIZE ];
+ KSHORT aWishedHeight[ DROP_CACHE_SIZE ];
+ short aDescent[ DROP_CACHE_SIZE ];
+ MSHORT nIndex;
+public:
+ SwDropCapCache();
+ ~SwDropCapCache(){}
+ void CalcFontSize( SwDropPortion* pDrop, SwTxtFormatInfo &rInf );
+};
+
+/*************************************************************************
+ * SwDropCapCache Ctor / Dtor
+ *************************************************************************/
+
+SwDropCapCache::SwDropCapCache() : nIndex( 0 )
+{
+ memset( &aMagicNo, 0, sizeof(aMagicNo) );
+ memset( &aWishedHeight, 0, sizeof(aWishedHeight) );
+}
+
+void SwDropPortion::DeleteDropCapCache()
+{
+ delete pDropCapCache;
+}
+
+/*************************************************************************
+ * SwDropCapCache::CalcFontSize
+ *************************************************************************/
+
+void SwDropCapCache::CalcFontSize( SwDropPortion* pDrop, SwTxtFormatInfo &rInf )
+{
+ const void* pFntNo = 0;
+ MSHORT nTmpIdx = 0;
+
+ ASSERT( pDrop->GetPart(),"DropPortion without part during font calculation");
+
+ SwDropPortionPart* pCurrPart = pDrop->GetPart();
+ const sal_Bool bUseCache = ! pCurrPart->GetFollow();
+ xub_StrLen nIdx = rInf.GetIdx();
+ XubString aStr( rInf.GetTxt(), nIdx, pCurrPart->GetLen() );
+
+ long nAscent = 0;
+ long nDescent = 0;
+ long nFactor = -1;
+
+ if ( bUseCache )
+ {
+ SwFont& rFnt = pCurrPart->GetFont();
+ rFnt.ChkMagic( rInf.GetVsh(), rFnt.GetActual() );
+ rFnt.GetMagic( pFntNo, nTmpIdx, rFnt.GetActual() );
+
+ nTmpIdx = 0;
+
+ while( nTmpIdx < DROP_CACHE_SIZE &&
+ ( aTxt[ nTmpIdx ] != aStr || aMagicNo[ nTmpIdx ] != long(pFntNo) ||
+ aWishedHeight[ nTmpIdx ] != pDrop->GetDropHeight() ) )
+ ++nTmpIdx;
+ }
+
+ // we have to calculate a new font scaling factor if
+ // 1. we did not find a scaling factor in the cache or
+ // 2. we are not allowed to use the cache because the drop portion
+ // consists of more than one part
+ if( nTmpIdx >= DROP_CACHE_SIZE || ! bUseCache )
+ {
+ ++nIndex;
+ nIndex %= DROP_CACHE_SIZE;
+ nTmpIdx = nIndex;
+
+ long nWishedHeight = pDrop->GetDropHeight();
+
+ // find out biggest font size for initial scaling factor
+ long nMaxFontHeight = 0;
+ while ( pCurrPart )
+ {
+ const SwFont& rFnt = pCurrPart->GetFont();
+ const long nCurrHeight = rFnt.GetHeight( rFnt.GetActual() );
+ if ( nCurrHeight > nMaxFontHeight )
+ nMaxFontHeight = nCurrHeight;
+
+ pCurrPart = pCurrPart->GetFollow();
+ }
+
+ nFactor = ( 1000 * nWishedHeight ) / nMaxFontHeight;
+
+ if ( bUseCache )
+ {
+ // save keys for cache
+ aMagicNo[ nTmpIdx ] = long(pFntNo);
+ aTxt[ nTmpIdx ] = aStr;
+ aWishedHeight[ nTmpIdx ] = KSHORT(nWishedHeight);
+ // save initial scaling factor
+ aFactor[ nTmpIdx ] = (USHORT)nFactor;
+ }
+
+ sal_Bool bGrow = ( pDrop->GetLen() != 0 );
+
+ // for growing controll
+ long nMax = KSHRT_MAX;
+ long nMin = nFactor / 2;
+#if OSL_DEBUG_LEVEL > 1
+ long nGrow = 0;
+#endif
+
+ sal_Bool bWinUsed = sal_False;
+ Font aOldFnt;
+ MapMode aOldMap( MAP_TWIP );
+ OutputDevice* pOut = rInf.GetOut();
+ OutputDevice* pWin;
+ if( rInf.GetVsh() && rInf.GetVsh()->GetWin() )
+ pWin = rInf.GetVsh()->GetWin();
+ else
+ pWin = GetpApp()->GetDefaultDevice();
+
+ while( bGrow )
+ {
+ // reset pCurrPart to first part
+ pCurrPart = pDrop->GetPart();
+ sal_Bool bFirstGlyphRect = sal_True;
+ sal_Bool bHaveGlyphRect = sal_False;
+ Rectangle aCommonRect, aRect;
+
+ while ( pCurrPart )
+ {
+ // current font
+ SwFont& rFnt = pCurrPart->GetFont();
+
+ // Get height including proportion
+ const USHORT nCurrHeight =
+ (USHORT)rFnt.GetHeight( rFnt.GetActual() );
+
+ // Get without proportion
+ const BYTE nOldProp = rFnt.GetPropr();
+ rFnt.SetProportion( 100 );
+ Size aOldSize = Size( 0, rFnt.GetHeight( rFnt.GetActual() ) );
+
+ Size aNewSize( 0, ( nFactor * nCurrHeight ) / 1000 );
+ rFnt.SetSize( aNewSize, rFnt.GetActual() );
+ rFnt.ChgPhysFnt( rInf.GetVsh(), *pOut );
+
+ nAscent = rFnt.GetAscent( rInf.GetVsh(), *pOut );
+
+ // Wir besorgen uns das alle Buchstaben umfassende Rechteck:
+ bHaveGlyphRect = pOut->GetTextBoundRect( aRect, rInf.GetTxt(), 0,
+ nIdx, pCurrPart->GetLen() ) &&
+ ! aRect.IsEmpty();
+
+ if ( ! bHaveGlyphRect )
+ {
+ // getting glyph boundaries failed for some reason,
+ // we take the window for calculating sizes
+ if ( pWin )
+ {
+ if ( ! bWinUsed )
+ {
+ bWinUsed = sal_True;
+ aOldMap = pWin->GetMapMode( );
+ pWin->SetMapMode( MapMode( MAP_TWIP ) );
+ aOldFnt = pWin->GetFont();
+ }
+ pWin->SetFont( rFnt.GetActualFont() );
+
+ bHaveGlyphRect = pWin->GetTextBoundRect( aRect, rInf.GetTxt(), 0,
+ nIdx, pCurrPart->GetLen() ) &&
+ ! aRect.IsEmpty();
+ }
+ if ( bHaveGlyphRect )
+ {
+ FontMetric aWinMet( pWin->GetFontMetric() );
+ nAscent = (KSHORT) aWinMet.GetAscent();
+ }
+ else
+ // We do not have a window or our window could not
+ // give us glyph boundaries.
+ aRect = Rectangle( Point( 0, 0 ), Size( 0, nAscent ) );
+ }
+
+ // Now we (hopefully) have a bounding rectangle for the
+ // glyphs of the current portion and the ascent of the current
+ // font
+
+ // reset font size and proportion
+ rFnt.SetSize( aOldSize, rFnt.GetActual() );
+ rFnt.SetProportion( nOldProp );
+
+ if ( bFirstGlyphRect )
+ {
+ aCommonRect = aRect;
+ bFirstGlyphRect = sal_False;
+ }
+ else
+ aCommonRect.Union( aRect );
+
+ nIdx = nIdx + pCurrPart->GetLen();
+ pCurrPart = pCurrPart->GetFollow();
+ }
+
+ // now we have a union ( aCommonRect ) of all glyphs with
+ // respect to a common baseline : 0
+
+ // get descent and ascent from union
+ if ( rInf.GetTxtFrm()->IsVertical() )
+ {
+ nDescent = aCommonRect.Left();
+ nAscent = aCommonRect.Right();
+
+ if ( nDescent < 0 )
+ nDescent = -nDescent;
+ }
+ else
+ {
+ nDescent = aCommonRect.Bottom();
+ nAscent = aCommonRect.Top();
+ }
+ if ( nAscent < 0 )
+ nAscent = -nAscent;
+
+ const long nHght = nAscent + nDescent;
+ if ( nHght )
+ {
+ if ( nHght > nWishedHeight )
+ nMax = nFactor;
+ else
+ {
+ if ( bUseCache )
+ aFactor[ nTmpIdx ] = (USHORT)nFactor;
+ nMin = nFactor;
+ }
+
+ nFactor = ( nFactor * nWishedHeight ) / nHght;
+ bGrow = ( nFactor > nMin ) && ( nFactor < nMax );
+#if OSL_DEBUG_LEVEL > 1
+ if ( bGrow )
+ nGrow++;
+#endif
+ nIdx = rInf.GetIdx();
+ }
+ else
+ bGrow = sal_False;
+ }
+
+ if ( bWinUsed )
+ {
+ // reset window if it has been used
+ pWin->SetMapMode( aOldMap );
+ pWin->SetFont( aOldFnt );
+ }
+
+ if ( bUseCache )
+ aDescent[ nTmpIdx ] = -short( nDescent );
+ }
+
+ pCurrPart = pDrop->GetPart();
+
+ // did made any new calculations or did we use the cache?
+ if ( -1 == nFactor )
+ {
+ nFactor = aFactor[ nTmpIdx ];
+ nDescent = aDescent[ nTmpIdx ];
+ }
+ else
+ nDescent = -nDescent;
+
+ while ( pCurrPart )
+ {
+ // scale current font
+ SwFont& rFnt = pCurrPart->GetFont();
+ Size aNewSize( 0, ( nFactor * rFnt.GetHeight( rFnt.GetActual() ) ) / 1000 );
+
+ const BYTE nOldProp = rFnt.GetPropr();
+ rFnt.SetProportion( 100 );
+ rFnt.SetSize( aNewSize, rFnt.GetActual() );
+ rFnt.SetProportion( nOldProp );
+
+ pCurrPart = pCurrPart->GetFollow();
+ }
+ pDrop->SetY( (short)nDescent );
+}
+
+/*************************************************************************
+ * virtual Format()
+ *************************************************************************/
+
+sal_Bool SwDropPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_Bool bFull = sal_False;
+ Fix( (USHORT)rInf.X() );
+
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ aLayoutModeModifier.SetAuto();
+
+ if( nDropHeight && pPart && nLines!=1 )
+ {
+ if( !pDropCapCache )
+ pDropCapCache = new SwDropCapCache();
+
+ // adjust font sizes to fit into the rectangle
+ pDropCapCache->CalcFontSize( this, rInf );
+
+ const long nOldX = rInf.X();
+ {
+ SwDropSave aSave( rInf );
+ SwDropPortionPart* pCurrPart = pPart;
+
+ while ( pCurrPart )
+ {
+ rInf.SetLen( pCurrPart->GetLen() );
+ SwFont& rFnt = pCurrPart->GetFont();
+ {
+ SwFontSave aFontSave( rInf, &rFnt );
+ bFull = FormatTxt( rInf );
+
+ if ( bFull )
+ break;
+ }
+
+ const SwTwips nTmpWidth =
+ ( InSpaceGrp() && rInf.GetSpaceAdd() ) ?
+ Width() + CalcSpacing( rInf.GetSpaceAdd(), rInf ) :
+ Width();
+
+ // set values
+ pCurrPart->SetWidth( (USHORT)nTmpWidth );
+
+ // Move
+ rInf.SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
+ rInf.X( rInf.X() + nTmpWidth );
+ pCurrPart = pCurrPart->GetFollow();
+ }
+
+ Width( (USHORT)(rInf.X() - nOldX) );
+ }
+
+ // reset my length
+ SetLen( rInf.GetLen() );
+
+ // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
+ if( ! bFull )
+ bFull = lcl_IsDropFlyInter( rInf, Width(), nDropHeight );
+
+ if( bFull )
+ {
+ // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
+ if ( !Height() )
+ Height( rInf.GetTxtHeight() );
+
+ // Jetzt noch einmal der ganze Spass
+ nDropHeight = nLines = 0;
+ delete pPart;
+ pPart = NULL;
+
+ // meanwhile use normal formatting
+ bFull = SwTxtPortion::Format( rInf );
+ }
+ else
+ rInf.SetDropInit( sal_True );
+
+ Height( rInf.GetTxtHeight() );
+ SetAscent( rInf.GetAscent() );
+ }
+ else
+ bFull = SwTxtPortion::Format( rInf );
+
+ if( bFull )
+ nDistance = 0;
+ else
+ {
+ const KSHORT nWant = Width() + GetDistance();
+ const KSHORT nRest = (USHORT)(rInf.Width() - rInf.X());
+ if( ( nWant > nRest ) ||
+ lcl_IsDropFlyInter( rInf, Width() + GetDistance(), nDropHeight ) )
+ nDistance = 0;
+
+ Width( Width() + nDistance );
+ }
+ return bFull;
+}
+
diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx
new file mode 100644
index 000000000000..526dbe74c4d9
--- /dev/null
+++ b/sw/source/core/text/txtfld.cxx
@@ -0,0 +1,549 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <charfmt.hxx>
+
+#include "viewsh.hxx" // NewFldPortion, GetDoc()
+#include "doc.hxx" // NewFldPortion, GetSysFldType()
+#include "rootfrm.hxx" // Info ueber virt. PageNumber
+#include "pagefrm.hxx" // NewFldPortion, GetVirtPageNum()
+#include "ndtxt.hxx" // NewNumberPortion, pHints->GetNum()
+#include "fldbas.hxx" // SwField
+#include "viewopt.hxx" // SwViewOptions
+#include "flyfrm.hxx" //IsInBody()
+#include "viewimp.hxx"
+#include "txtatr.hxx" // SwTxtFld
+#include "txtcfg.hxx"
+#include "swfont.hxx" // NewFldPortion, new SwFont
+#include "fntcache.hxx" // NewFldPortion, SwFntAccess
+#include "porfld.hxx"
+#include "porftn.hxx" // NewExtraPortion
+#include "porref.hxx" // NewExtraPortion
+#include "portox.hxx" // NewExtraPortion
+#include "porhyph.hxx" // NewExtraPortion
+#include "porfly.hxx" // NewExtraPortion
+#include "itrform2.hxx" // SwTxtFormatter
+#include "chpfld.hxx"
+#include "dbfld.hxx"
+#include "expfld.hxx"
+#include "docufld.hxx"
+#include "pagedesc.hxx" // NewFldPortion, GetNum()
+#include <pormulti.hxx> // SwMultiPortion
+#include "fmtmeta.hxx" // lcl_NewMetaPortion
+
+
+/*************************************************************************
+ * SwTxtFormatter::NewFldPortion()
+ *************************************************************************/
+
+
+sal_Bool lcl_IsInBody( SwFrm *pFrm )
+{
+ if ( pFrm->IsInDocBody() )
+ return sal_True;
+ else
+ {
+ const SwFrm *pTmp = pFrm;
+ const SwFlyFrm *pFly;
+ while ( 0 != (pFly = pTmp->FindFlyFrm()) )
+ pTmp = pFly->GetAnchorFrm();
+ return pTmp->IsInDocBody();
+ }
+}
+
+
+SwExpandPortion *SwTxtFormatter::NewFldPortion( SwTxtFormatInfo &rInf,
+ const SwTxtAttr *pHint ) const
+{
+ SwExpandPortion *pRet = 0;
+ SwFrm *pFrame = (SwFrm*)pFrm;
+ SwField *pFld = (SwField*)pHint->GetFld().GetFld();
+ const sal_Bool bName = rInf.GetOpt().IsFldName();
+
+ SwCharFmt* pChFmt = 0;
+ sal_Bool bNewFlyPor = sal_False,
+ bINet = sal_False;
+
+ // set language
+ ((SwTxtFormatter*)this)->SeekAndChg( rInf );
+ if (pFld->GetLanguage() != GetFnt()->GetLanguage())
+ {
+ pFld->SetLanguage( GetFnt()->GetLanguage() );
+ // let the visual note know about its new language
+ if (pFld->GetTyp()->Which()==RES_POSTITFLD)
+ const_cast<SwFmtFld*> (&pHint->GetFld())->Broadcast( SwFmtFldHint( &pHint->GetFld(), SWFMTFLD_LANGUAGE ) );
+ }
+
+ ViewShell *pSh = rInf.GetVsh();
+ sal_Bool bPlaceHolder = sal_False;
+
+ switch( pFld->GetTyp()->Which() )
+ {
+ case RES_SCRIPTFLD:
+ case RES_POSTITFLD:
+ pRet = new SwPostItsPortion( RES_SCRIPTFLD == pFld->GetTyp()->Which() );
+ break;
+
+ case RES_COMBINED_CHARS:
+ {
+ String sStr( pFld->GetCntnt( bName ));
+ if( bName )
+ pRet = new SwFldPortion( sStr );
+ else
+ pRet = new SwCombinedPortion( sStr );
+ }
+ break;
+
+ case RES_HIDDENTXTFLD:
+ pRet = new SwHiddenPortion(pFld->GetCntnt( bName ));
+ break;
+
+ case RES_CHAPTERFLD:
+ if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
+ {
+ ((SwChapterField*)pFld)->ChangeExpansion( pFrame,
+ &((SwTxtFld*)pHint)->GetTxtNode() );
+ }
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
+ break;
+
+ case RES_DOCSTATFLD:
+ if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
+ ((SwDocStatField*)pFld)->ChangeExpansion( pFrame );
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
+ break;
+
+ case RES_PAGENUMBERFLD:
+ {
+ if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
+ {
+ SwPageNumberFieldType *pPageNr = (SwPageNumberFieldType *)pFld->GetTyp();
+
+ const SwRootFrm* pTmpRootFrm = pSh->GetLayout();
+ const sal_Bool bVirt = pTmpRootFrm->IsVirtPageNum();
+
+ SwDoc* pDoc = pSh->GetDoc();
+ MSHORT nVirtNum = pFrame->GetVirtPageNum();
+ MSHORT nNumPages = pTmpRootFrm->GetPageNum();
+ sal_Int16 nNumFmt = -1;
+ if(SVX_NUM_PAGEDESC == pFld->GetFormat())
+ nNumFmt = pFrame->FindPageFrm()->GetPageDesc()->GetNumType().GetNumberingType();
+
+ pPageNr->ChangeExpansion( pDoc, nVirtNum, nNumPages,
+ bVirt, nNumFmt > -1 ? &nNumFmt : 0);
+ }
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
+ break;
+ }
+ case RES_GETEXPFLD:
+ {
+ if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
+ {
+ SwGetExpField* pExpFld = (SwGetExpField*)pFld;
+ if( !::lcl_IsInBody( pFrame ) )
+ {
+ pExpFld->ChgBodyTxtFlag( sal_False );
+ pExpFld->ChangeExpansion( *pFrame, *((SwTxtFld*)pHint) );
+ }
+ else if( !pExpFld->IsInBodyTxt() )
+ {
+ // war vorher anders, also erst expandieren, dann umsetzen!!
+ pExpFld->ChangeExpansion( *pFrame, *((SwTxtFld*)pHint) );
+ pExpFld->ChgBodyTxtFlag( sal_True );
+ }
+ }
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
+ break;
+ }
+ case RES_DBFLD:
+ {
+ if( !bName )
+ {
+ SwDBField* pDBFld = (SwDBField*)pFld;
+ pDBFld->ChgBodyTxtFlag( ::lcl_IsInBody( pFrame ) );
+/* Solange das ChangeExpansion auskommentiert ist.
+ * Aktualisieren in Kopf/Fuszeilen geht aktuell nicht.
+ if( !::lcl_IsInBody( pFrame ) )
+ {
+ pDBFld->ChgBodyTxtFlag( sal_False );
+ pDBFld->ChangeExpansion( pFrame, (SwTxtFld*)pHint );
+ }
+ else if( !pDBFld->IsInBodyTxt() )
+ {
+ // war vorher anders, also erst expandieren, dann umsetzen!!
+ pDBFld->ChangeExpansion( pFrame, (SwTxtFld*)pHint );
+ pDBFld->ChgBodyTxtFlag( sal_True );
+ }
+*/
+ }
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
+ break;
+ }
+ case RES_REFPAGEGETFLD:
+ if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
+ ((SwRefPageGetField*)pFld)->ChangeExpansion( pFrame, (SwTxtFld*)pHint );
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
+ break;
+
+ case RES_JUMPEDITFLD:
+ if( !bName )
+ pChFmt = ((SwJumpEditField*)pFld)->GetCharFmt();
+ bNewFlyPor = sal_True;
+ bPlaceHolder = sal_True;
+ break;
+
+ default:
+ {
+ pRet = new SwFldPortion(pFld->GetCntnt( bName ) );
+ }
+ }
+
+ if( bNewFlyPor )
+ {
+ SwFont *pTmpFnt = 0;
+ if( !bName )
+ {
+ pTmpFnt = new SwFont( *pFnt );
+ if( bINet )
+ {
+ SwAttrPool* pPool = pChFmt->GetAttrSet().GetPool();
+ SfxItemSet aSet( *pPool, RES_CHRATR_BEGIN, RES_CHRATR_END );
+ SfxItemSet aTmpSet( aSet );
+ pFrm->GetTxtNode()->GetAttr(aSet,rInf.GetIdx(),rInf.GetIdx()+1);
+ aTmpSet.Set( pChFmt->GetAttrSet() );
+ aTmpSet.Differentiate( aSet );
+ if( aTmpSet.Count() )
+ pTmpFnt->SetDiffFnt( &aTmpSet, pFrm->GetTxtNode()->getIDocumentSettingAccess() );
+ }
+ else
+ pTmpFnt->SetDiffFnt( &pChFmt->GetAttrSet(), pFrm->GetTxtNode()->getIDocumentSettingAccess() );
+ }
+ pRet = new SwFldPortion( pFld->GetCntnt( bName ), pTmpFnt, bPlaceHolder );
+ }
+
+ return pRet;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::TryNewNoLengthPortion()
+ *************************************************************************/
+
+SwFldPortion * lcl_NewMetaPortion(SwTxtAttr & rHint, const bool bPrefix)
+{
+ ::sw::Meta *const pMeta(
+ static_cast<SwFmtMeta &>(rHint.GetAttr()).GetMeta() );
+ ::rtl::OUString fix;
+ ::sw::MetaField *const pField( dynamic_cast< ::sw::MetaField * >(pMeta) );
+ OSL_ENSURE(pField, "lcl_NewMetaPortion: no meta field?");
+ if (pField)
+ {
+ pField->GetPrefixAndSuffix((bPrefix) ? &fix : 0, (bPrefix) ? 0 : &fix);
+ }
+ return new SwFldPortion( fix );
+}
+
+/** Try to create a new portion with zero length, for an end of a hint
+ (where there is no CH_TXTATR). Because there may be multiple hint ends at a
+ given index, m_nHintEndIndex is used to keep track of the already created
+ portions. But the portions created here may actually be deleted again,
+ due to UnderFlow. In that case, m_nHintEndIndex must be decremented,
+ so the portion will be created again on the next line.
+ */
+SwExpandPortion *
+SwTxtFormatter::TryNewNoLengthPortion(SwTxtFormatInfo & rInfo)
+{
+ if (pHints)
+ {
+ const xub_StrLen nIdx(rInfo.GetIdx());
+ while (m_nHintEndIndex < pHints->GetEndCount())
+ {
+ SwTxtAttr & rHint( *pHints->GetEnd(m_nHintEndIndex) );
+ xub_StrLen const nEnd( *rHint.GetAnyEnd() );
+ if (nEnd > nIdx)
+ {
+ break;
+ }
+ ++m_nHintEndIndex;
+ if (nEnd == nIdx)
+ {
+ if (RES_TXTATR_METAFIELD == rHint.Which())
+ {
+ SwFldPortion *const pPortion(
+ lcl_NewMetaPortion(rHint, false));
+ pPortion->SetNoLength(); // no CH_TXTATR at hint end!
+ return pPortion;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewExtraPortion()
+ *************************************************************************/
+
+SwLinePortion *SwTxtFormatter::NewExtraPortion( SwTxtFormatInfo &rInf )
+{
+ SwTxtAttr *pHint = GetAttr( rInf.GetIdx() );
+ SwLinePortion *pRet = 0;
+ if( !pHint )
+ {
+#if OSL_DEBUG_LEVEL > 1
+// aDbstream << "NewExtraPortion: hint not found?" << endl;
+#endif
+ pRet = new SwTxtPortion;
+ pRet->SetLen( 1 );
+ rInf.SetLen( 1 );
+ return pRet;
+ }
+
+ switch( pHint->Which() )
+ {
+ case RES_TXTATR_FLYCNT :
+ {
+ pRet = NewFlyCntPortion( rInf, pHint );
+ break;
+ }
+ case RES_TXTATR_FTN :
+ {
+ pRet = NewFtnPortion( rInf, pHint );
+ break;
+ }
+ case RES_TXTATR_FIELD :
+ {
+ pRet = NewFldPortion( rInf, pHint );
+ break;
+ }
+ case RES_TXTATR_REFMARK :
+ {
+ pRet = new SwIsoRefPortion;
+ break;
+ }
+ case RES_TXTATR_TOXMARK :
+ {
+ pRet = new SwIsoToxPortion;
+ break;
+ }
+ case RES_TXTATR_METAFIELD:
+ {
+ pRet = lcl_NewMetaPortion( *pHint, true );
+ break;
+ }
+ default: ;
+ }
+ if( !pRet )
+ {
+#if OSL_DEBUG_LEVEL > 1
+// aDbstream << "NewExtraPortion: unknown hint" << endl;
+#endif
+ const XubString aNothing;
+ pRet = new SwFldPortion( aNothing );
+ rInf.SetLen( 1 );
+ }
+ return pRet;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewNumberPortion()
+ *************************************************************************/
+
+
+SwNumberPortion *SwTxtFormatter::NewNumberPortion( SwTxtFormatInfo &rInf ) const
+{
+ if( rInf.IsNumDone() || rInf.GetTxtStart() != nStart
+ || rInf.GetTxtStart() != rInf.GetIdx() )
+ return 0;
+
+ SwNumberPortion *pRet = 0;
+ const SwTxtNode* pTxtNd = GetTxtFrm()->GetTxtNode();
+ const SwNumRule* pNumRule = pTxtNd->GetNumRule();
+
+ // hat ein "gueltige" Nummer ?
+ if( pTxtNd->IsNumbered() && pTxtNd->IsCountedInList())
+ {
+ const SwNumFmt &rNumFmt = pNumRule->Get( static_cast<USHORT>(pTxtNd->GetActualListLevel()) );
+ const sal_Bool bLeft = SVX_ADJUST_LEFT == rNumFmt.GetNumAdjust();
+ const sal_Bool bCenter = SVX_ADJUST_CENTER == rNumFmt.GetNumAdjust();
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ const bool bLabelAlignmentPosAndSpaceModeActive(
+ rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT );
+ const KSHORT nMinDist = bLabelAlignmentPosAndSpaceModeActive
+ ? 0 : rNumFmt.GetCharTextDistance();
+ // <--
+
+ if( SVX_NUM_BITMAP == rNumFmt.GetNumberingType() )
+ {
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ pRet = new SwGrfNumPortion( (SwFrm*)GetTxtFrm(),
+ pTxtNd->GetLabelFollowedBy(),
+ rNumFmt.GetBrush(),
+ rNumFmt.GetGraphicOrientation(),
+ rNumFmt.GetGraphicSize(),
+ bLeft, bCenter, nMinDist,
+ bLabelAlignmentPosAndSpaceModeActive );
+ // <--
+ long nTmpA = rInf.GetLast()->GetAscent();
+ long nTmpD = rInf.GetLast()->Height() - nTmpA;
+ if( !rInf.IsTest() )
+ ((SwGrfNumPortion*)pRet)->SetBase( nTmpA, nTmpD, nTmpA, nTmpD );
+ }
+ else
+ {
+ // Der SwFont wird dynamisch angelegt und im CTOR uebergeben,
+ // weil das CharFmt nur einen SV-Font zurueckliefert.
+ // Im Dtor vom SwNumberPortion wird der SwFont deletet.
+ SwFont *pNumFnt = 0;
+ const SwAttrSet* pFmt = rNumFmt.GetCharFmt() ?
+ &rNumFmt.GetCharFmt()->GetAttrSet() :
+ NULL;
+ const IDocumentSettingAccess* pIDSA = pTxtNd->getIDocumentSettingAccess();
+
+ if( SVX_NUM_CHAR_SPECIAL == rNumFmt.GetNumberingType() )
+ {
+ const Font *pFmtFnt = rNumFmt.GetBulletFont();
+
+ //
+ // Build a new bullet font basing on the current paragraph font:
+ //
+ pNumFnt = new SwFont( &rInf.GetCharAttr(), pIDSA );
+
+ // --> FME 2005-08-11 #i53199#
+ if ( !pIDSA->get(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) )
+ {
+ // i18463:
+ // Underline style of paragraph font should not be considered
+ // Overline style of paragraph font should not be considered
+ // Weight style of paragraph font should not be considered
+ // Posture style of paragraph font should not be considered
+ pNumFnt->SetUnderline( UNDERLINE_NONE );
+ pNumFnt->SetOverline( UNDERLINE_NONE );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
+ }
+
+ //
+ // Apply the explicit attributes from the character style
+ // associated with the numering to the new bullet font.
+ //
+ if( pFmt )
+ pNumFnt->SetDiffFnt( pFmt, pIDSA );
+
+ if ( pFmtFnt )
+ {
+ const BYTE nAct = pNumFnt->GetActual();
+ pNumFnt->SetFamily( pFmtFnt->GetFamily(), nAct );
+ pNumFnt->SetName( pFmtFnt->GetName(), nAct );
+ pNumFnt->SetStyleName( pFmtFnt->GetStyleName(), nAct );
+ pNumFnt->SetCharSet( pFmtFnt->GetCharSet(), nAct );
+ pNumFnt->SetPitch( pFmtFnt->GetPitch(), nAct );
+ }
+
+ // we do not allow a vertical font
+ pNumFnt->SetVertical( pNumFnt->GetOrientation(),
+ pFrm->IsVertical() );
+
+ // --> OD 2008-01-23 #newlistelevelattrs#
+ pRet = new SwBulletPortion( rNumFmt.GetBulletChar(),
+ pTxtNd->GetLabelFollowedBy(),
+ pNumFnt,
+ bLeft, bCenter, nMinDist,
+ bLabelAlignmentPosAndSpaceModeActive );
+ // <--
+ }
+ else
+ {
+ // --> OD 2006-06-02 #b6432095#
+ // use method <SwNumRule::MakeNumString(..)> instead of
+ // method <SwTxtNode::GetNumString()>, because for levels with
+ // numbering none the prefix and the suffix strings have to be provided.
+// XubString aTxt( pTxtNd->GetNumString() );
+ XubString aTxt( pNumRule->MakeNumString( *(pTxtNd->GetNum()) ) );
+ // <--
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ if ( aTxt.Len() > 0 )
+ {
+ aTxt.Insert( pTxtNd->GetLabelFollowedBy() );
+ }
+ // <--
+
+ // 7974: Nicht nur eine Optimierung...
+ // Eine Numberportion ohne Text wird die Breite von 0
+ // erhalten. Die nachfolgende Textportion wird im BreakLine
+ // in das BreakCut laufen, obwohl rInf.GetLast()->GetFlyPortion()
+ // vorliegt!
+ if( aTxt.Len() )
+ {
+ //
+ // Build a new numbering font basing on the current paragraph font:
+ //
+ pNumFnt = new SwFont( &rInf.GetCharAttr(), pIDSA );
+
+ // --> FME 2005-08-11 #i53199#
+ if ( !pIDSA->get(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) )
+ {
+ // i18463:
+ // Underline style of paragraph font should not be considered
+ pNumFnt->SetUnderline( UNDERLINE_NONE );
+ // Overline style of paragraph font should not be considered
+ pNumFnt->SetOverline( UNDERLINE_NONE );
+ }
+
+
+ //
+ // Apply the explicit attributes from the character style
+ // associated with the numering to the new bullet font.
+ //
+ if( pFmt )
+ pNumFnt->SetDiffFnt( pFmt, pIDSA );
+
+ // we do not allow a vertical font
+ pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
+
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ pRet = new SwNumberPortion( aTxt, pNumFnt,
+ bLeft, bCenter, nMinDist,
+ bLabelAlignmentPosAndSpaceModeActive );
+ // <--
+ }
+ }
+ }
+ }
+ return pRet;
+}
+
diff --git a/sw/source/core/text/txtfly.cxx b/sw/source/core/text/txtfly.cxx
new file mode 100644
index 000000000000..db245de1e28b
--- /dev/null
+++ b/sw/source/core/text/txtfly.cxx
@@ -0,0 +1,2430 @@
+/*************************************************************************
+ *
+ * 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 <vcl/outdev.hxx>
+#include <vcl/virdev.hxx>
+
+#include "viewsh.hxx"
+#include "pagefrm.hxx"
+#include "rootfrm.hxx"
+#include "viewimp.hxx" // SwViewImp
+#include "pam.hxx" // SwPosition
+#include "swregion.hxx" // SwRegionRects
+#include "dcontact.hxx" // SwContact
+#include "dflyobj.hxx" // SdrObject
+#include "flyfrm.hxx" // SwFlyFrm
+#include "frmtool.hxx" // ::DrawGraphic
+#include "porfld.hxx" // SwGrfNumPortion
+#include "txtfrm.hxx" // SwTxtFrm
+#include "itrform2.hxx" // SwTxtFormatter
+#include "porfly.hxx" // NewFlyCntPortion
+#include "porfld.hxx" // SwGrfNumPortion
+#include "txtfly.hxx" // SwTxtFly
+#include "txtpaint.hxx" // SwSaveClip
+#include "txtatr.hxx" // SwTxtFlyCnt
+#include "txtcfg.hxx"
+#include "notxtfrm.hxx"
+#include "flyfrms.hxx"
+#include "fmtcnct.hxx" // SwFmtChain
+#include <pormulti.hxx> // SwMultiPortion
+#include <svx/obj3d.hxx>
+#include <editeng/txtrange.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+// --> OD 2004-06-16 #i28701#
+#include <editeng/lspcitem.hxx>
+// <--
+#include <txtflcnt.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtanchr.hxx>
+#include <fmtflcnt.hxx>
+#include <frmfmt.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <sortedobjs.hxx>
+#include <layouter.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <svx/obj3d.hxx>
+#include <editeng/txtrange.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <svx/svdoedge.hxx>
+#include "doc.hxx"
+
+#ifdef DBG_UTIL
+#include "viewopt.hxx" // SwViewOptions, nur zum Testen (Test2)
+#endif
+
+#ifdef VERT_DISTANCE
+#include <math.h>
+#endif
+
+
+using namespace ::com::sun::star;
+
+/*****************************************************************************
+ * Beschreibung:
+ * Die Klasse SwTxtFly soll die Universalschnittstelle zwischen der
+ * Formatierung/Textausgabe und den u.U. ueberlappenden freifliegenden
+ * Frames sein.
+ * Waehrend der Formatierung erkundigt sich der Formatierer beim SwTxtFly,
+ * ob ein bestimmter Bereich durch die Attribute eines ueberlappenden
+ * Frames vorliegt. Solche Bereiche werden in Form von Dummy-Portions
+ * abgebildet.
+ * Die gesamte Textausgabe und Retusche wird ebenfalls an ein SwTxtFly
+ * weitergeleitet. Dieser entscheidet, ob Textteile geclippt werden muessen
+ * und zerteilt z.B. die Bereiche bei einem DrawRect.
+ * Zu beachten ist, dass alle freifliegenden Frames in einem nach TopLeft
+ * sortiertem PtrArray an der Seite zu finden sind. Intern wird immer nur
+ * in dokumentglobalen Werten gerechnet. Die IN- und OUT-Parameter sind
+ * jedoch in den meisten Faellen an die Beduerfnisse des LineIters
+ * zugeschnitten, d.h. sie werden in frame- oder windowlokalen Koordinaten
+ * konvertiert.
+ * Wenn mehrere Frames mit Umlaufattributen in einer Zeile liegen,
+ * ergeben sich unterschiedliche Auswirkungen fuer den Textfluss:
+ *
+ * L/R P L R K
+ * P -P-P- -P-L -P R- -P K
+ * L -L P- -L L -L R- -L K
+ * R R-P- R-L R R- R K
+ * K K P- K L K R- K K
+ *
+ * (P=parallel, L=links, R=rechts, K=kein Umlauf)
+ *
+ * Das Verhalten so beschreiben:
+ * Jeder Rahmen kann Text verdraengen, wobei der Einfluss allerdings nur
+ * bis zum naechsten Rahmen reicht.
+ *****************************************************************************/
+
+void SwTxtFormatter::CalcUnclipped( SwTwips& rTop, SwTwips& rBottom )
+{
+ ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
+ "SwTxtFormatter::CalcUnclipped with unswapped frame" )
+
+ long nFlyAsc, nFlyDesc;
+ // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
+ //lcl_MaxAscDescent( pCurr, rTop, rBottom, nFlyAsc, nFlyDesc );
+ pCurr->MaxAscentDescent( rTop, rBottom, nFlyAsc, nFlyDesc );
+ rTop = Y() + GetCurr()->GetAscent();
+ rBottom = rTop + nFlyDesc;
+ rTop -= nFlyAsc;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::UpdatePos() aktualisiert die Referenzpunkte der zeichengeb.
+ * Objekte, z. B. nach Adjustierung ( rechtsbuendig, Blocksatz etc. )
+ * ( hauptsaechlich Korrrektur der X-Position )
+ *************************************************************************/
+
+void SwTxtFormatter::UpdatePos( SwLineLayout *pCurrent, Point aStart,
+ xub_StrLen nStartIdx, sal_Bool bAllWays ) const
+{
+ ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
+ "SwTxtFormatter::UpdatePos with unswapped frame" )
+
+ if( GetInfo().IsTest() )
+ return;
+ SwLinePortion *pFirst = pCurrent->GetFirstPortion();
+ SwLinePortion *pPos = pFirst;
+ SwTxtPaintInfo aTmpInf( GetInfo() );
+ aTmpInf.SetpSpaceAdd( pCurrent->GetpLLSpaceAdd() );
+ aTmpInf.ResetSpaceIdx();
+ aTmpInf.SetKanaComp( pCurrent->GetpKanaComp() );
+ aTmpInf.ResetKanaIdx();
+
+ // Die Groesse des Frames
+ aTmpInf.SetIdx( nStartIdx );
+ aTmpInf.SetPos( aStart );
+
+ long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
+ // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
+ //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
+ pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
+
+ KSHORT nTmpHeight = pCurrent->GetRealHeight();
+ KSHORT nAscent = pCurrent->GetAscent() + nTmpHeight - pCurrent->Height();
+ objectpositioning::AsCharFlags nFlags = AS_CHAR_ULSPACE;
+ if( GetMulti() )
+ {
+ aTmpInf.SetDirection( GetMulti()->GetDirection() );
+ if( GetMulti()->HasRotation() )
+ {
+ nFlags |= AS_CHAR_ROTATE;
+ if( GetMulti()->IsRevers() )
+ {
+ nFlags |= AS_CHAR_REVERSE;
+ aTmpInf.X( aTmpInf.X() - nAscent );
+ }
+ else
+ aTmpInf.X( aTmpInf.X() + nAscent );
+ }
+ else
+ {
+ if ( GetMulti()->IsBidi() )
+ nFlags |= AS_CHAR_BIDI;
+ aTmpInf.Y( aTmpInf.Y() + nAscent );
+ }
+ }
+ else
+ aTmpInf.Y( aTmpInf.Y() + nAscent );
+
+ while( pPos )
+ {
+ // bislang ist mir nur ein Fall bekannt, wo die Positionsaenderung
+ // (verursacht durch das Adjustment) fuer eine Portion wichtig
+ // sein koennte: Bei FlyCntPortions muss ein SetRefPoint erfolgen.
+ if( ( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
+ && ( bAllWays || !IsQuick() ) )
+ {
+ // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
+ //lcl_MaxAscDescent( pFirst, nTmpAscent, nTmpDescent,
+ // nFlyAsc, nFlyDesc, pPos );
+ pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
+
+ if( pPos->IsGrfNumPortion() )
+ {
+ if( !nFlyAsc && !nFlyDesc )
+ {
+ nTmpAscent = nAscent;
+ nFlyAsc = nAscent;
+ nTmpDescent = nTmpHeight - nAscent;
+ nFlyDesc = nTmpDescent;
+ }
+ ((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
+ nFlyAsc, nFlyDesc );
+ }
+ else
+ {
+ Point aBase( aTmpInf.GetPos() );
+ if ( GetInfo().GetTxtFrm()->IsVertical() )
+ GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aBase );
+
+ ((SwFlyCntPortion*)pPos)->SetBase( *aTmpInf.GetTxtFrm(),
+ aBase, nTmpAscent, nTmpDescent, nFlyAsc,
+ nFlyDesc, nFlags );
+ }
+ }
+ if( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasFlyInCntnt() )
+ {
+ ASSERT( !GetMulti(), "Too much multi" );
+ ((SwTxtFormatter*)this)->pMulti = (SwMultiPortion*)pPos;
+ SwLineLayout *pLay = &GetMulti()->GetRoot();
+ Point aSt( aTmpInf.X(), aStart.Y() );
+
+ if ( GetMulti()->HasBrackets() )
+ {
+ ASSERT( GetMulti()->IsDouble(), "Brackets only for doubles");
+ aSt.X() += ((SwDoubleLinePortion*)GetMulti())->PreWidth();
+ }
+ else if( GetMulti()->HasRotation() )
+ {
+ aSt.Y() += pCurrent->GetAscent() - GetMulti()->GetAscent();
+ if( GetMulti()->IsRevers() )
+ aSt.X() += GetMulti()->Width();
+ else
+ aSt.Y() += GetMulti()->Height();
+ }
+ else if ( GetMulti()->IsBidi() )
+ // jump to end of the bidi portion
+ aSt.X() += pLay->Width();
+
+ xub_StrLen nStIdx = aTmpInf.GetIdx();
+ do
+ {
+ UpdatePos( pLay, aSt, nStIdx, bAllWays );
+ nStIdx = nStIdx + pLay->GetLen();
+ aSt.Y() += pLay->Height();
+ pLay = pLay->GetNext();
+ } while ( pLay );
+ ((SwTxtFormatter*)this)->pMulti = NULL;
+ }
+ pPos->Move( aTmpInf );
+ pPos = pPos->GetPortion();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFormatter::AlignFlyInCntBase()
+ * richtet die zeichengeb. Objekte in Y-Richtung ggf. neu aus.
+ *************************************************************************/
+
+void SwTxtFormatter::AlignFlyInCntBase( long nBaseLine ) const
+{
+ ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
+ "SwTxtFormatter::AlignFlyInCntBase with unswapped frame" )
+
+ if( GetInfo().IsTest() )
+ return;
+ SwLinePortion *pFirst = pCurr->GetFirstPortion();
+ SwLinePortion *pPos = pFirst;
+ objectpositioning::AsCharFlags nFlags = AS_CHAR_NOFLAG;
+ if( GetMulti() && GetMulti()->HasRotation() )
+ {
+ nFlags |= AS_CHAR_ROTATE;
+ if( GetMulti()->IsRevers() )
+ nFlags |= AS_CHAR_REVERSE;
+ }
+
+ long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
+
+ while( pPos )
+ {
+ if( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
+ {
+ // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
+ //lcl_MaxAscDescent( pFirst, nTmpAscent, nTmpDescent,
+ // nFlyAsc, nFlyDesc, pPos );
+ pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
+
+ if( pPos->IsGrfNumPortion() )
+ ((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
+ nFlyAsc, nFlyDesc );
+ else
+ {
+ Point aBase;
+ if ( GetInfo().GetTxtFrm()->IsVertical() )
+ {
+ nBaseLine = GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( nBaseLine );
+ aBase = Point( nBaseLine, ((SwFlyCntPortion*)pPos)->GetRefPoint().Y() );
+ }
+ else
+ aBase = Point( ((SwFlyCntPortion*)pPos)->GetRefPoint().X(), nBaseLine );
+
+ ((SwFlyCntPortion*)pPos)->SetBase( *GetInfo().GetTxtFrm(), aBase, nTmpAscent, nTmpDescent,
+ nFlyAsc, nFlyDesc, nFlags );
+ }
+ }
+ pPos = pPos->GetPortion();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFly::ChkFlyUnderflow()
+ * This is called after the real height of the line has been calculated
+ * Therefore it is possible, that more flys from below intersect with the
+ * line, or that flys from above do not intersect with the line anymore
+ * We check this and return true if so, meaning that the line has to be
+ * formatted again
+ *************************************************************************/
+
+sal_Bool SwTxtFormatter::ChkFlyUnderflow( SwTxtFormatInfo &rInf ) const
+{
+ ASSERT( rInf.GetTxtFly()->IsOn(), "SwTxtFormatter::ChkFlyUnderflow: why?" );
+ if( GetCurr() )
+ {
+ // Erst pruefen wir, ob ueberhaupt ein Fly mit der Zeile ueberlappt.
+ // = GetLineHeight()
+ const long nHeight = GetCurr()->GetRealHeight();
+ SwRect aLine( GetLeftMargin(), Y(), rInf.RealWidth(), nHeight );
+
+ SwRect aLineVert( aLine );
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchHorizontalToVertical( aLineVert );
+ SwRect aInter( rInf.GetTxtFly()->GetFrm( aLineVert ) );
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchVerticalToHorizontal( aInter );
+
+ if( !aInter.HasArea() )
+ return sal_False;
+
+ // Nun ueberpruefen wir jede Portion, die sich haette senken koennen,
+ // ob sie mit dem Fly ueberlappt.
+ const SwLinePortion *pPos = GetCurr()->GetFirstPortion();
+ aLine.Pos().Y() = Y() + GetCurr()->GetRealHeight() - GetCurr()->Height();
+ aLine.Height( GetCurr()->Height() );
+
+ while( pPos )
+ {
+ aLine.Width( pPos->Width() );
+
+ aLineVert = aLine;
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchHorizontalToVertical( aLineVert );
+ aInter = rInf.GetTxtFly()->GetFrm( aLineVert );
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchVerticalToHorizontal( aInter );
+
+ // new flys from below?
+ if( !pPos->IsFlyPortion() )
+ {
+ if( aInter.IsOver( aLine ) )
+ {
+ aInter._Intersection( aLine );
+ if( aInter.HasArea() )
+ {
+ // to be evaluated during reformat of this line:
+ // RealHeight including spacing
+ rInf.SetLineHeight( KSHORT(nHeight) );
+ // Height without extra spacing
+ rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
+ return sal_True;
+ }
+ }
+ }
+ else
+ {
+ // the fly portion is not anylonger intersected by a fly
+ if ( ! aInter.IsOver( aLine ) )
+ {
+ rInf.SetLineHeight( KSHORT(nHeight) );
+ rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
+ return sal_True;
+ }
+ else
+ {
+ aInter._Intersection( aLine );
+
+ // no area means a fly has become invalid because of
+ // lowering the line => reformat the line
+ // we also have to reformat the line, if the fly size
+ // differs from the intersection intervals size
+ if( ! aInter.HasArea() ||
+ ((SwFlyPortion*)pPos)->GetFixWidth() != aInter.Width() )
+ {
+ rInf.SetLineHeight( KSHORT(nHeight) );
+ rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
+ return sal_True;
+ }
+ }
+ }
+
+ aLine.Left( aLine.Left() + pPos->Width() );
+ pPos = pPos->GetPortion();
+ }
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::CalcFlyWidth()
+ * ermittelt das naechste Objekt, das in die restliche Zeile ragt und
+ * konstruiert die zugehoerige FlyPortion.
+ * Dazu wird SwTxtFly.GetFrm(..) benutzt.
+ *************************************************************************/
+
+// Durch Flys kann sich der rechte Rand verkuerzen.
+
+void SwTxtFormatter::CalcFlyWidth( SwTxtFormatInfo &rInf )
+{
+ if( GetMulti() || rInf.GetFly() )
+ return;
+
+ SwTxtFly *pTxtFly = rInf.GetTxtFly();
+ if( !pTxtFly->IsOn() || rInf.IsIgnoreFly() )
+ return;
+
+ const SwLinePortion *pLast = rInf.GetLast();
+
+ long nAscent;
+ long nTop = Y();
+ long nHeight;
+
+ if( rInf.GetLineHeight() )
+ {
+ // real line height has already been calculated, we only have to
+ // search for intersections in the lower part of the strip
+ nAscent = pCurr->GetAscent();
+ nHeight = rInf.GetLineNettoHeight();
+ nTop += rInf.GetLineHeight() - nHeight;
+ }
+ else
+ {
+ nAscent = pLast->GetAscent();
+ nHeight = pLast->Height();
+
+ // we make a first guess for the lines real height
+ if ( ! pCurr->GetRealHeight() )
+ CalcRealHeight();
+
+ if ( pCurr->GetRealHeight() > nHeight )
+ nTop += pCurr->GetRealHeight() - nHeight;
+ else
+ // important for fixed space between lines
+ nHeight = pCurr->GetRealHeight();
+ }
+
+ const long nLeftMar = GetLeftMargin();
+ const long nLeftMin = (rInf.X() || GetDropLeft()) ? nLeftMar : GetLeftMin();
+
+ SwRect aLine( rInf.X() + nLeftMin, nTop, rInf.RealWidth() - rInf.X()
+ + nLeftMar - nLeftMin , nHeight );
+
+ SwRect aLineVert( aLine );
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( aLineVert );
+
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchHorizontalToVertical( aLineVert );
+ SwRect aInter( pTxtFly->GetFrm( aLineVert ) );
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchRTLtoLTR( aInter );
+
+ if ( pFrm->IsVertical() )
+ pFrm->SwitchVerticalToHorizontal( aInter );
+
+ if( aInter.IsOver( aLine ) )
+ {
+ aLine.Left( rInf.X() + nLeftMar );
+ sal_Bool bForced = sal_False;
+ if( aInter.Left() <= nLeftMin )
+ {
+ SwTwips nFrmLeft = GetTxtFrm()->Frm().Left();
+ if( GetTxtFrm()->Prt().Left() < 0 )
+ nFrmLeft += GetTxtFrm()->Prt().Left();
+ if( aInter.Left() < nFrmLeft )
+ aInter.Left( nFrmLeft );
+
+ long nAddMar = 0;
+ if ( pFrm->IsRightToLeft() )
+ {
+ nAddMar = pFrm->Frm().Right() - Right();
+ if ( nAddMar < 0 )
+ nAddMar = 0;
+ }
+ else
+ nAddMar = nLeftMar - nFrmLeft;
+
+ aInter.Width( aInter.Width() + nAddMar );
+ // Bei negativem Erstzeileneinzug setzen wir das Flag,
+ // um anzuzeigen, dass der Einzug/Rand verschoben wurde
+ // Dies muss beim DefaultTab an der Nullposition beruecksichtigt
+ // werden.
+ if( IsFirstTxtLine() && HasNegFirst() )
+ bForced = sal_True;
+ }
+ aInter.Intersection( aLine );
+ if( !aInter.HasArea() )
+ return;
+
+ const sal_Bool bFullLine = aLine.Left() == aInter.Left() &&
+ aLine.Right() == aInter.Right();
+
+ // Obwohl kein Text mehr da ist, muss eine weitere Zeile
+ // formatiert werden, weil auch leere Zeilen einem Fly
+ // ohne Umlauf ausweichen muessen.
+ if( bFullLine && rInf.GetIdx() == rInf.GetTxt().Len() )
+ {
+ rInf.SetNewLine( sal_True );
+ // 8221: Dummies erkennt man an Ascent == Height
+ pCurr->SetDummy(sal_True);
+ }
+
+ // aInter wird framelokal
+ aInter.Pos().X() -= nLeftMar;
+ SwFlyPortion *pFly = new SwFlyPortion( aInter );
+ if( bForced )
+ {
+ pCurr->SetForcedLeftMargin( sal_True );
+ rInf.ForcedLeftMargin( (USHORT)aInter.Width() );
+ }
+
+ if( bFullLine )
+ {
+ // 8110: wir muessen um Einheiten von Zeilenhoehen anwachsen,
+ // um nebeneinanderliegende Flys mit unterschiedlichen
+ // Umlaufattributen angemessen zu umfliessen.
+ // Die letzte ausweichende Zeile, sollte in der Hoehe angepasst
+ // sein, damit nicht der Eindruck von "Rahmenabstaenden" aufkommt.
+ // 8221: Wichtig ist, dass Ascent == Height ist, weil die FlyPortionWerte
+ // im CalcLine in pCurr uebertragen werden und IsDummy() darauf
+ // angewiesen ist.
+ // Es gibt meines Wissens nur zwei Stellen, in denen DummyLines
+ // entstehen koennen: hier und in MakeFlyDummies.
+ // Ausgewertet wird IsDummy() in IsFirstTxtLine() und
+ // beim Zeilenwandern und im Zusammenhang mit DropCaps.
+ pFly->Height( KSHORT(aInter.Height()) );
+
+ // In nNextTop steckt jetzt die Unterkante des Rahmens, dem wir
+ // ausweichen oder die Oberkante des naechsten Rahmens, den wir
+ // beachten muessen. Wir koennen also jetzt getrost bis zu diesem
+ // Wert anwachsen, so sparen wir einige Leerzeilen.
+ long nNextTop = pTxtFly->GetNextTop();
+ if ( pFrm->IsVertical() )
+ nNextTop = pFrm->SwitchVerticalToHorizontal( nNextTop );
+ if( nNextTop > aInter.Bottom() )
+ {
+ SwTwips nH = nNextTop - aInter.Top();
+ if( nH < KSHRT_MAX )
+ pFly->Height( KSHORT( nH ) );
+ }
+ if( nAscent < pFly->Height() )
+ pFly->SetAscent( KSHORT(nAscent) );
+ else
+ pFly->SetAscent( pFly->Height() );
+ }
+ else
+ {
+ if( rInf.GetIdx() == rInf.GetTxt().Len() )
+ {
+ // Nicht nHeight nehmen, sonst haben wir einen Riesendescent
+ pFly->Height( pLast->Height() );
+ pFly->SetAscent( pLast->GetAscent() );
+ }
+ else
+ {
+ pFly->Height( KSHORT(aInter.Height()) );
+ if( nAscent < pFly->Height() )
+ pFly->SetAscent( KSHORT(nAscent) );
+ else
+ pFly->SetAscent( pFly->Height() );
+ }
+ }
+
+ rInf.SetFly( pFly );
+
+ if( pFly->Fix() < rInf.Width() )
+ rInf.Width( pFly->Fix() );
+
+ GETGRID( pFrm->FindPageFrm() )
+ if ( pGrid )
+ {
+ const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
+ const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
+
+ SWRECTFN( pPageFrm )
+
+ const long nGridOrigin = pBody ?
+ (pBody->*fnRect->fnGetPrtLeft)() :
+ (pPageFrm->*fnRect->fnGetPrtLeft)();
+
+ const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
+ const USHORT nGridWidth = GETGRIDWIDTH( pGrid, pDoc); //for textgrid refactor
+
+ SwTwips nStartX = GetLeftMargin();
+ if ( bVert )
+ {
+ Point aPoint( nStartX, 0 );
+ pFrm->SwitchHorizontalToVertical( aPoint );
+ nStartX = aPoint.Y();
+ }
+
+ const SwTwips nOfst = nStartX - nGridOrigin;
+ const SwTwips nTmpWidth = rInf.Width() + nOfst;
+
+ const ULONG i = nTmpWidth / nGridWidth + 1;
+
+ const long nNewWidth = ( i - 1 ) * nGridWidth - nOfst;
+ if ( nNewWidth > 0 )
+ rInf.Width( (USHORT)nNewWidth );
+ else
+ rInf.Width( 0 );
+ }
+ }
+}
+
+/*****************************************************************************
+ * SwTxtFormatter::NewFlyCntPortion
+ * legt eine neue Portion fuer ein zeichengebundenes Objekt an.
+ *****************************************************************************/
+
+SwFlyCntPortion *SwTxtFormatter::NewFlyCntPortion( SwTxtFormatInfo &rInf,
+ SwTxtAttr *pHint ) const
+{
+ SwFlyCntPortion *pRet = 0;
+ const SwFrm *pFrame = (SwFrm*)pFrm;
+
+ SwFlyInCntFrm *pFly;
+ SwFrmFmt* pFrmFmt = ((SwTxtFlyCnt*)pHint)->GetFlyCnt().GetFrmFmt();
+ if( RES_FLYFRMFMT == pFrmFmt->Which() )
+ pFly = ((SwTxtFlyCnt*)pHint)->GetFlyFrm(pFrame);
+ else
+ pFly = NULL;
+ // aBase bezeichnet die dokumentglobale Position,
+ // ab der die neue Extraportion plaziert wird.
+ // aBase.X() = Offset in der Zeile,
+ // hinter der aktuellen Portion
+ // aBase.Y() = LineIter.Y() + Ascent der aktuellen Portion
+
+ long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
+ // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
+ //SwLinePortion *pPos = pCurr->GetFirstPortion();
+ //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
+ pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
+
+ // Wenn der Ascent des Rahmens groesser als der Ascent der akt. Portion
+ // ist, wird dieser bei der Base-Berechnung verwendet, sonst wuerde
+ // der Rahmen zunaechst zu weit nach oben gesetzt, um dann doch wieder
+ // nach unten zu rutschen und dabei ein Repaint in einem Bereich ausloesen,
+ // indem er niemals wirklich war.
+ KSHORT nAscent = 0;
+
+ const bool bTxtFrmVertical = GetInfo().GetTxtFrm()->IsVertical();
+
+ const bool bUseFlyAscent = pFly && pFly->GetValidPosFlag() &&
+ 0 != ( bTxtFrmVertical ?
+ pFly->GetRefPoint().X() :
+ pFly->GetRefPoint().Y() );
+
+ if ( bUseFlyAscent )
+ nAscent = static_cast<USHORT>( Abs( int( bTxtFrmVertical ?
+ pFly->GetRelPos().X() :
+ pFly->GetRelPos().Y() ) ) );
+
+ // check if be prefer to use the ascent of the last portion:
+ if ( IsQuick() ||
+ !bUseFlyAscent ||
+ nAscent < rInf.GetLast()->GetAscent() )
+ {
+ nAscent = rInf.GetLast()->GetAscent();
+ }
+ else if( nAscent > nFlyAsc )
+ nFlyAsc = nAscent;
+
+ Point aBase( GetLeftMargin() + rInf.X(), Y() + nAscent );
+ objectpositioning::AsCharFlags nMode = IsQuick() ? AS_CHAR_QUICK : 0;
+ if( GetMulti() && GetMulti()->HasRotation() )
+ {
+ nMode |= AS_CHAR_ROTATE;
+ if( GetMulti()->IsRevers() )
+ nMode |= AS_CHAR_REVERSE;
+ }
+
+ Point aTmpBase( aBase );
+ if ( GetInfo().GetTxtFrm()->IsVertical() )
+ GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
+
+ if( pFly )
+ {
+ pRet = new SwFlyCntPortion( *GetInfo().GetTxtFrm(), pFly, aTmpBase,
+ nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
+ // Wir muessen sicherstellen, dass unser Font wieder im OutputDevice
+ // steht. Es koennte sein, dass der FlyInCnt frisch eingefuegt wurde,
+ // dann hat GetFlyFrm dazu gefuehrt, dass er neu angelegt wird.
+ // Dessen Frames werden sofort formatiert, die verstellen den Font
+ // und schon haben wir den Salat (3322).
+ rInf.SelectFont();
+ if( pRet->GetAscent() > nAscent )
+ {
+ aBase.Y() = Y() + pRet->GetAscent();
+ nMode |= AS_CHAR_ULSPACE;
+ if( !rInf.IsTest() )
+ aTmpBase = aBase;
+ if ( GetInfo().GetTxtFrm()->IsVertical() )
+ GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
+
+ pRet->SetBase( *rInf.GetTxtFrm(), aTmpBase, nTmpAscent,
+ nTmpDescent, nFlyAsc, nFlyDesc, nMode );
+ }
+ }
+ else
+ {
+ pRet = new SwFlyCntPortion( *rInf.GetTxtFrm(), (SwDrawContact*)pFrmFmt->FindContactObj(),
+ aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
+ }
+ return pRet;
+}
+
+
+
+/*************************************************************************
+ * SwTxtFly::SwTxtFly()
+ *************************************************************************/
+
+SwTxtFly::SwTxtFly( const SwTxtFly& rTxtFly )
+{
+ pPage = rTxtFly.pPage;
+ // --> OD 2006-08-15 #i68520#
+ mpCurrAnchoredObj = rTxtFly.mpCurrAnchoredObj;
+ // <--
+ pCurrFrm = rTxtFly.pCurrFrm;
+ pMaster = rTxtFly.pMaster;
+ // --> OD 2006-08-15 #i68520#
+ if( rTxtFly.mpAnchoredObjList )
+ {
+ mpAnchoredObjList = new SwAnchoredObjList( *(rTxtFly.mpAnchoredObjList) );
+ }
+ else
+ {
+ mpAnchoredObjList = NULL;
+ }
+ // <--
+
+ bOn = rTxtFly.bOn;
+ bLeftSide = rTxtFly.bLeftSide;
+ bTopRule = rTxtFly.bTopRule;
+}
+
+void SwTxtFly::CtorInitTxtFly( const SwTxtFrm *pFrm )
+{
+ mbIgnoreCurrentFrame = sal_False;
+ mbIgnoreContour = sal_False;
+ // --> OD 2004-12-17 #118809#
+ mbIgnoreObjsInHeaderFooter = sal_False;
+ // <--
+ pPage = pFrm->FindPageFrm();
+ const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
+ // --> OD 2006-08-15 #i68520#
+ mpCurrAnchoredObj = pTmp;
+ // <--
+ pCurrFrm = pFrm;
+ pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
+ // --> OD 2006-08-15 #i68520#
+ mpAnchoredObjList = NULL;
+ // <--
+ // Wenn wir nicht von einem Frame ueberlappt werden, oder wenn
+ // es gar keine FlyCollection gibt, dann schaltet wir uns fuer immer ab.
+ // Aber es koennte sein, dass waehrend der Formatierung eine Zeile
+ // hinzukommt, die in einen Frame hineinragt. Deswegen keine Optimierung
+ // per bOn = pSortedFlys && IsAnyFrm();
+ bOn = pPage->GetSortedObjs() != 0;
+ bTopRule = sal_True;
+ bLeftSide = sal_False;
+ nMinBottom = 0;
+ nIndex = ULONG_MAX;
+}
+
+/*************************************************************************
+ * SwTxtFly::_GetFrm()
+ *
+ * IN: dokumentglobal (rRect)
+ * OUT: framelokal (return-Wert)
+ * Diese Methode wird waehrend der Formatierung vom LineIter gerufen.
+ * 1. um die naechste FlyPortion vorzubereiten
+ * 2. um nach Aenderung der Zeilenhoehe neue Ueberlappungen festzustellen
+ *************************************************************************/
+
+SwRect SwTxtFly::_GetFrm( const SwRect &rRect, sal_Bool bTop ) const
+{
+ SwRect aRet;
+ if( ForEach( rRect, &aRet, sal_True ) )
+ {
+ SWRECTFN( pCurrFrm )
+ if( bTop )
+ (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );
+
+ // 8110: Bottom nicht immer anpassen.
+ const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
+ const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
+ if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
+ (aRet.*fnRect->fnGetHeight)() < 0 )
+ (aRet.*fnRect->fnSetBottom)( nRectBottom );
+ }
+ return aRet;
+}
+
+/*************************************************************************
+ * SwTxtFly::IsAnyFrm()
+ *
+ * IN: dokumentglobal
+ * fuer die Printarea des aktuellen Frame
+ *
+ * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax)
+ *
+ *************************************************************************/
+
+sal_Bool SwTxtFly::IsAnyFrm() const
+{
+ SWAP_IF_SWAPPED( pCurrFrm )
+
+ ASSERT( bOn, "IsAnyFrm: Why?" );
+ SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
+ pCurrFrm->Prt().SSize() );
+
+ const sal_Bool bRet = ForEach( aRect, NULL, sal_False );
+ UNDO_SWAP( pCurrFrm )
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFly::IsAnyObj()
+ *
+ * IN: dokumentglobal
+ * OUT: sal_True Wenn ein Rahmen oder DrawObj beruecksichtigt werden muss
+ * Nur wenn IsAnyObj sal_False liefert, koennen Optimierungen benutzt werden
+ * wie Paint/FormatEmpty fuer leere Absaetze
+ * und auch das virtuelle Outputdevice.
+ *************************************************************************/
+
+sal_Bool SwTxtFly::IsAnyObj( const SwRect &rRect ) const
+{
+ ASSERT ( bOn, "SwTxtFly::IsAnyObj: Who's knocking?" );
+
+ SwRect aRect( rRect );
+ if ( aRect.IsEmpty() )
+ aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
+ pCurrFrm->Prt().SSize() );
+
+ const SwSortedObjs *pSorted = pPage->GetSortedObjs();
+ if( pSorted ) // Eigentlich ist durch bOn sichergestellt, dass es an der
+ // Seite Objekte gibt, aber wer weiss, wer inzwischen etwas geloescht hat.
+ {
+ for ( MSHORT i = 0; i < pSorted->Count(); ++i )
+ {
+ const SwAnchoredObject* pObj = (*pSorted)[i];
+
+ const SwRect aBound( pObj->GetObjRectWithSpaces() );
+
+ // Optimierung
+ if( pObj->GetObjRect().Left() > aRect.Right() )
+ continue;
+
+ // --> OD 2006-08-15 #i68520#
+ if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
+ // <--
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+const SwCntntFrm* SwTxtFly::_GetMaster()
+{
+ pMaster = pCurrFrm;
+ while( pMaster->IsFollow() )
+ pMaster = (SwCntntFrm*)pMaster->FindMaster();
+ return pMaster;
+}
+
+/*************************************************************************
+ * SwTxtFly::DrawTextOpaque()
+ *
+ * IN: dokumentglobal
+ * DrawTextOpaque() wird von DrawText() gerufen.
+ * Die Clipregions werden so gesetzt, dass nur die Teile ausgegeben werden,
+ * die nicht in den Bereichen von FlyFrms liegen, die undurchsichtig und
+ * ueber dem aktuellen Frame liegen.
+ * Die On-Optimierung uebernimmt DrawText()!
+ *************************************************************************/
+
+sal_Bool SwTxtFly::DrawTextOpaque( SwDrawTextInfo &rInf )
+{
+ SwSaveClip aClipSave( rInf.GetpOut() );
+ SwRect aRect( rInf.GetPos(), rInf.GetSize() );
+ if( rInf.GetSpace() )
+ {
+ xub_StrLen nTmpLen = STRING_LEN == rInf.GetLen() ? rInf.GetText().Len() :
+ rInf.GetLen();
+ if( rInf.GetSpace() > 0 )
+ {
+ xub_StrLen nSpaceCnt = 0;
+ const xub_StrLen nEndPos = rInf.GetIdx() + nTmpLen;
+ for( xub_StrLen nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos )
+ {
+ if( CH_BLANK == rInf.GetText().GetChar( nPos ) )
+ ++nSpaceCnt;
+ }
+ if( nSpaceCnt )
+ aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
+ }
+ else
+ aRect.Width( aRect.Width() - nTmpLen * rInf.GetSpace() );
+ }
+
+ if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
+ {
+ SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
+ aRect.Intersection( aClipRect );
+ }
+
+ SwRegionRects aRegion( aRect );
+
+ sal_Bool bOpaque = sal_False;
+ // --> OD 2006-08-15 #i68520#
+ const UINT32 nCurrOrd = mpCurrAnchoredObj
+ ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
+ : SAL_MAX_UINT32;
+ // <--
+ ASSERT( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
+
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
+ if ( bOn && nCount > 0 )
+ // <--
+ {
+ MSHORT nHellId = pPage->GetShell()->getIDocumentDrawModelAccess()->GetHellId();
+ for( MSHORT i = 0; i < nCount; ++i )
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
+ if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
+ mpCurrAnchoredObj != pTmpAnchoredObj )
+ // <--
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj);
+ // <--
+ if( aRegion.GetOrigin().IsOver( pFly->Frm() ) )
+ {
+ const SwFrmFmt *pFmt = pFly->GetFmt();
+ const SwFmtSurround &rSur = pFmt->GetSurround();
+ const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
+ //Nur undurchsichtige und weiter oben liegende.
+ /// OD 08.10.2002 #103898# - add condition
+ /// <!(pFly->IsBackgroundTransparent() || pFly->IsShadowTransparent())>
+ if( !( pFly->IsBackgroundTransparent()
+ || pFly->IsShadowTransparent() ) &&
+ SURROUND_THROUGHT == rSur.GetSurround() &&
+ ( !rSur.IsAnchorOnly() ||
+ // --> OD 2006-08-15 #i68520#
+ GetMaster() == pFly->GetAnchorFrm() ||
+ // <--
+ ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
+ (FLY_AT_CHAR != rAnchor.GetAnchorId())
+ )
+ ) &&
+ // --> OD 2006-08-15 #i68520#
+ pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
+ nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
+ // <--
+ )
+ {
+ //Ausser der Inhalt ist Transparent
+ const SwNoTxtFrm *pNoTxt =
+ pFly->Lower() && pFly->Lower()->IsNoTxtFrm()
+ ? (SwNoTxtFrm*)pFly->Lower()
+ : 0;
+ if ( !pNoTxt ||
+ (!pNoTxt->IsTransparent() && !rSur.IsContour()) )
+ {
+ bOpaque = sal_True;
+ aRegion -= pFly->Frm();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
+ const Point &rOld = rInf.GetPos();
+ rInf.SetPos( aPos );
+
+ if( !bOpaque )
+ {
+ if( rInf.GetKern() )
+ rInf.GetFont()->_DrawStretchText( rInf );
+ else
+ rInf.GetFont()->_DrawText( rInf );
+ rInf.SetPos( rOld );
+ return sal_False;
+ }
+ else if( aRegion.Count() )
+ {
+ // Was fuer ein Aufwand ...
+ SwSaveClip aClipVout( rInf.GetpOut() );
+ for( MSHORT i = 0; i < aRegion.Count(); ++i )
+ {
+ SwRect &rRect = aRegion[i];
+ if( rRect != aRegion.GetOrigin() )
+ aClipVout.ChgClip( rRect );
+ if( rInf.GetKern() )
+ rInf.GetFont()->_DrawStretchText( rInf );
+ else
+ rInf.GetFont()->_DrawText( rInf );
+ }
+ }
+ rInf.SetPos( rOld );
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFly::DrawFlyRect()
+ *
+ * IN: windowlokal
+ * Zwei Feinheiten gilt es zu beachten:
+ * 1) DrawRect() oberhalb des ClipRects sind erlaubt !
+ * 2) FlyToRect() liefert groessere Werte als die Framedaten !
+ *************************************************************************/
+
+void SwTxtFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
+ const SwTxtPaintInfo &rInf, sal_Bool bNoGraphic )
+{
+ SwRegionRects aRegion( rRect );
+ ASSERT( !bTopRule, "DrawFlyRect: Wrong TopRule" );
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
+ if ( bOn && nCount > 0 )
+ // <--
+ {
+ MSHORT nHellId = pPage->GetShell()->getIDocumentDrawModelAccess()->GetHellId();
+ for( MSHORT i = 0; i < nCount; ++i )
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
+ if( mpCurrAnchoredObj != pAnchoredObjTmp &&
+ dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp) )
+ // <--
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwFmtSurround& rSur = pAnchoredObjTmp->GetFrmFmt().GetSurround();
+ // <--
+
+ // OD 24.01.2003 #106593# - correct clipping of fly frame area.
+ // Consider that fly frame background/shadow can be transparent
+ // and <SwAlignRect(..)> fly frame area
+ // --> OD 2006-08-15 #i68520#
+ const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
+ // <--
+ // --> OD 2005-06-08 #i47804# - consider transparent graphics
+ // and OLE objects.
+ bool bClipFlyArea =
+ ( ( SURROUND_THROUGHT == rSur.GetSurround() )
+ // --> OD 2006-08-15 #i68520#
+ ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
+ // <--
+ : !rSur.IsContour() ) &&
+ !pFly->IsBackgroundTransparent() &&
+ !pFly->IsShadowTransparent() &&
+ ( !pFly->Lower() ||
+ !pFly->Lower()->IsNoTxtFrm() ||
+ !static_cast<const SwNoTxtFrm*>(pFly->Lower())->IsTransparent() );
+ // <--
+ if ( bClipFlyArea )
+ {
+ // --> OD 2006-08-15 #i68520#
+ SwRect aFly( pAnchoredObjTmp->GetObjRect() );
+ // <--
+ // OD 24.01.2003 #106593#
+ ::SwAlignRect( aFly, pPage->GetShell() );
+ if( aFly.Width() > 0 && aFly.Height() > 0 )
+ aRegion -= aFly;
+ }
+ }
+ }
+ }
+
+ for( MSHORT i = 0; i < aRegion.Count(); ++i )
+ {
+ if ( bNoGraphic )
+ pOut->DrawRect( aRegion[i].SVRect() );
+ else
+ {
+ ASSERT( ((SvxBrushItem*)-1) != rInf.GetBrushItem(),
+ "DrawRect: Uninitialized BrushItem!" );
+ ::DrawGraphic( rInf.GetBrushItem(), pOut, rInf.GetBrushRect(),
+ aRegion[i] );
+ }
+ }
+}
+
+// --> OD 2004-10-06 #i26945# - change first parameter:
+// Now it's the <SwAnchoredObject> instance of the floating screen object
+sal_Bool SwTxtFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
+ const sal_Bool bInFtn,
+ const sal_Bool bInFooterOrHeader )
+// <--
+{
+ // --> OD 2006-08-15 #i68520#
+ // <mpCurrAnchoredObj> is set, if <pCurrFrm> is inside a fly frame
+ if( _pAnchoredObj != mpCurrAnchoredObj )
+ // <--
+ {
+ // --> OD 2004-10-06 #i26945#
+ const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
+ // <--
+ // #102344# Ignore connectors which have one or more connections
+ if(pNew && pNew->ISA(SdrEdgeObj))
+ {
+ if(((SdrEdgeObj*)pNew)->GetConnectedNode(TRUE)
+ || ((SdrEdgeObj*)pNew)->GetConnectedNode(FALSE))
+ {
+ return sal_False;
+ }
+ }
+
+ if( ( bInFtn || bInFooterOrHeader ) && bTopRule )
+ {
+ // --> OD 2004-10-06 #i26945#
+ const SwFrmFmt& rFrmFmt = _pAnchoredObj->GetFrmFmt();
+ const SwFmtAnchor& rNewA = rFrmFmt.GetAnchor();
+ // <--
+ if (FLY_AT_PAGE == rNewA.GetAnchorId())
+ {
+ if ( bInFtn )
+ return sal_False;
+
+ if ( bInFooterOrHeader )
+ {
+ SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() );
+ BOOL bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
+ aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
+ if( bVertPrt )
+ return sal_False;
+ }
+ }
+ }
+
+ // --> OD 2006-08-15 #i68520#
+ // bEvade: consider pNew, if we are not inside a fly
+ // consider pNew, if pNew is lower of <mpCurrAnchoredObj>
+ sal_Bool bEvade = !mpCurrAnchoredObj ||
+ Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);
+
+ if ( !bEvade )
+ {
+ // We are currently inside a fly frame and pNew is not
+ // inside this fly frame. We can do some more checks if
+ // we have to consider pNew.
+
+ // If bTopRule is not set, we ignore the frame types.
+ // We directly check the z-order
+ if ( !bTopRule )
+ bEvade = sal_True;
+ else
+ {
+ // innerhalb von verketteten Flys wird nur Lowern ausgewichen
+ // --> OD 2006-08-15 #i68520#
+ const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain();
+ // <--
+ if ( !rChain.GetPrev() && !rChain.GetNext() )
+ {
+ // --> OD 2004-10-06 #i26945#
+ const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
+ // <--
+ // --> OD 2006-08-15 #i68520#
+ const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor();
+ // <--
+
+ // If <mpCurrAnchoredObj> is anchored as character, its content
+ // does not wrap around pNew
+ if (FLY_AS_CHAR == rCurrA.GetAnchorId())
+ return sal_False;
+
+ // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
+ // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
+ // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
+ // some more checks
+ if (FLY_AT_PAGE == rNewA.GetAnchorId())
+ {
+ if (FLY_AT_PAGE == rCurrA.GetAnchorId())
+ {
+ bEvade = sal_True;
+ }
+ else
+ return sal_False;
+ }
+ else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
+ return sal_False; // Seitengebundene weichen nur seitengeb. aus
+ else if (FLY_AT_FLY == rNewA.GetAnchorId())
+ bEvade = sal_True; // Nicht seitengeb. weichen Rahmengeb. aus
+ else if( FLY_AT_FLY == rCurrA.GetAnchorId() )
+ return sal_False; // Rahmengebundene weichen abs.geb. nicht aus
+ // --> OD 2006-01-30 #i57062#
+ // In order to avoid loop situation, it's decided to adjust
+ // the wrapping behaviour of content of at-paragraph/at-character
+ // anchored objects to one in the page header/footer and
+ // the document body --> content of at-paragraph/at-character
+ // anchored objects doesn't wrap around each other.
+// else if( bInFooterOrHeader )
+// return sal_False; // In header or footer no wrapping
+// // if both bounded at paragraph
+// else // Zwei Flies mit (auto-)absatzgebunder Verankerung ...
+// // ... entscheiden nach der Reihenfolge ihrer Anker im Dok.
+// bEvade = rNewA.GetCntntAnchor()->nNode.GetIndex() <=
+// rCurrA.GetCntntAnchor()->nNode.GetIndex();
+ else
+ return sal_False;
+ // <--
+ }
+ }
+
+ // aber: es wird niemals einem hierarchisch untergeordnetem
+ // ausgewichen und ausserdem braucht nur bei Ueberlappung
+ // ausgewichen werden.
+ // --> OD 2006-08-15 #i68520#
+ bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
+ // <--
+ if( bEvade )
+ {
+ // --> OD 2006-08-15 #i68520#
+ SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
+ if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
+ bEvade = sal_False;
+ // <--
+ }
+ }
+
+ if ( bEvade )
+ {
+ // --> OD 2004-10-06 #i26945#
+ const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
+ // <--
+ ASSERT( FLY_AS_CHAR != rNewA.GetAnchorId(),
+ "Don't call GetTop with a FlyInCntFrm" );
+ if (FLY_AT_PAGE == rNewA.GetAnchorId())
+ return sal_True; // Seitengebundenen wird immer ausgewichen.
+
+ // Wenn absatzgebundene Flys in einem FlyCnt gefangen sind, so
+ // endet deren Einflussbereich an den Grenzen des FlyCnt!
+ // Wenn wir aber gerade den Text des FlyCnt formatieren, dann
+ // muss er natuerlich dem absatzgebundenen Frm ausweichen!
+ // pCurrFrm ist der Anker von pNew?
+ // --> OD 2004-10-06 #i26945#
+ const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
+ // <--
+ if( pTmp == pCurrFrm )
+ return sal_True;
+ if( pTmp->IsTxtFrm() && ( pTmp->IsInFly() || pTmp->IsInFtn() ) )
+ {
+ // --> OD 2004-10-06 #i26945#
+ Point aPos = _pAnchoredObj->GetObjRect().Pos();
+ // <--
+ pTmp = GetVirtualUpper( pTmp, aPos );
+ }
+ // --> OD 2004-10-06 #i26945#
+ // --> OD 2004-11-29 #115759#
+ // If <pTmp> is a text frame inside a table, take the upper
+ // of the anchor frame, which contains the anchor position.
+ else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() )
+ {
+ pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
+ ->GetAnchorFrmContainingAnchPos()->GetUpper();
+ }
+ // <--
+ // --> OD 2004-05-13 #i28701# - consider all objects in same context,
+ // if wrapping style is considered on object positioning.
+ // Thus, text will wrap around negative positioned objects.
+ // --> OD 2004-08-25 #i3317# - remove condition on checking,
+ // if wrappings style is considered on object postioning.
+ // Thus, text is wrapping around negative positioned objects.
+ // --> OD 2004-10-20 #i35640# - no consideration of negative
+ // positioned objects, if wrapping style isn't considered on
+ // object position and former text wrapping is applied.
+ // This condition is typically for documents imported from the
+ // OpenOffice.org file format.
+ const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
+ if ( ( pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
+ !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) &&
+ ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
+ {
+ return sal_True;
+ }
+ // <--
+
+ const SwFrm* pHeader = 0;
+ if ( pCurrFrm->GetNext() != pTmp &&
+ ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
+ // --> #i13832#, #i24135# wrap around objects in page header
+ ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
+ 0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
+ !pHeader->IsFooterFrm() &&
+ pCurrFrm->IsInDocBody() ) ) )
+ // <--
+ {
+ if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
+ return sal_True;
+
+ // Compare indices:
+ // Den Index des anderen erhalten wir immer ueber das Ankerattr.
+ ULONG nTmpIndex = rNewA.GetCntntAnchor()->nNode.GetIndex();
+ // Jetzt wird noch ueberprueft, ob der aktuelle Absatz vor dem
+ // Anker des verdraengenden Objekts im Text steht, dann wird
+ // nicht ausgewichen.
+ // Der Index wird moeglichst ueber einen SwFmtAnchor ermittelt,
+ // da sonst recht teuer.
+ if( ULONG_MAX == nIndex )
+ nIndex = pCurrFrm->GetNode()->GetIndex();
+
+ if( nIndex >= nTmpIndex )
+ return sal_True;
+ }
+ }
+ }
+ return sal_False;
+}
+// --> OD 2006-08-15 #i68520#
+struct AnchoredObjOrder
+{
+ sal_Bool mbR2L;
+ SwRectFn mfnRect;
+
+ AnchoredObjOrder( const sal_Bool bR2L,
+ SwRectFn fnRect )
+ : mbR2L( bR2L ),
+ mfnRect( fnRect )
+ {}
+
+ bool operator()( const SwAnchoredObject* pListedAnchoredObj,
+ const SwAnchoredObject* pNewAnchoredObj )
+ {
+ const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
+ const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
+ if ( ( mbR2L &&
+ ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
+ (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
+ ( !mbR2L &&
+ ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
+ (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
+ {
+ SwTwips nTopDiff =
+ (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
+ (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
+ if ( nTopDiff == 0 &&
+ ( ( mbR2L &&
+ ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
+ (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
+ ( !mbR2L &&
+ ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
+ (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
+ {
+ return true;
+ }
+ else if ( nTopDiff > 0 )
+ {
+ return true;
+ }
+ }
+ else if ( ( mbR2L &&
+ ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
+ (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
+ ( !mbR2L &&
+ ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
+ (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+};
+
+// --> OD 2006-08-15 #i68520#
+SwAnchoredObjList* SwTxtFly::InitAnchoredObjList()
+{
+ ASSERT( pCurrFrm, "InitFlyList: No Frame, no FlyList" );
+ // --> OD 2006-08-15 #i68520#
+ ASSERT( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
+ // <--
+
+ SWAP_IF_SWAPPED( pCurrFrm )
+
+ const SwSortedObjs *pSorted = pPage->GetSortedObjs();
+ const sal_uInt32 nCount = pSorted ? pSorted->Count() : 0;
+ // --> #108724# Page header/footer content doesn't have to wrap around
+ // floating screen objects
+ const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
+ const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
+ // --> OD 2005-01-12 #i40155# - check, if frame is marked not to wrap
+ const sal_Bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
+ ( !pCurrFrm->IsInFtn() && !bFooterHeader ) ) &&
+ !SwLayouter::FrmNotToWrap( *pCurrFrm->GetTxtNode()->getIDocumentLayoutAccess(), *pCurrFrm );
+ // <--
+
+ bOn = sal_False;
+
+ if( nCount && bWrapAllowed )
+ {
+ // --> OD 2006-08-15 #i68520#
+ mpAnchoredObjList = new SwAnchoredObjList();
+ // <--
+
+ // --> OD 2004-06-18 #i28701# - consider complete frame area for new
+ // text wrapping
+ SwRect aRect;
+ if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) )
+ {
+ aRect = pCurrFrm->Prt();
+ aRect += pCurrFrm->Frm().Pos();
+ }
+ else
+ {
+ aRect = pCurrFrm->Frm();
+ }
+ // Wir machen uns etwas kleiner als wir sind,
+ // damit Ein-Twip-Ueberlappungen ignoriert werden. (#49532)
+ SWRECTFN( pCurrFrm )
+ const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
+ const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
+ const sal_Bool bR2L = pCurrFrm->IsRightToLeft();
+
+ const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess();
+
+ for( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ // --> OD 2006-08-15 #i68520#
+// SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
+// const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
+
+// // OD 2004-01-15 #110582# - do not consider hidden objects
+// // OD 2004-05-13 #i28701# - check, if object has to be considered
+// // for text wrap.
+// if ( !pDoc->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
+// !pAnchoredObj->ConsiderForTextWrap() ||
+// nRight < (aBound.*fnRect->fnGetLeft)() ||
+// (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
+// (aBound.*fnRect->fnGetBottom)() ) > 0 ||
+// nLeft > (aBound.*fnRect->fnGetRight)() ||
+// // --> OD 2004-12-17 #118809# - If requested, do not consider
+// // objects in page header|footer for text frames not in page
+// // header|footer. This is requested for the calculation of
+// // the base offset for objects <SwTxtFrm::CalcBaseOfstForFly()>
+// ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
+// pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) ||
+// // <--
+// // --> FME 2004-07-14 #i20505# Do not consider oversized objects
+// (aBound.*fnRect->fnGetHeight)() >
+// 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
+// // <--
+// {
+// continue;
+// }
+ SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
+ if ( !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
+ !pAnchoredObj->ConsiderForTextWrap() ||
+ ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
+ pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
+ {
+ continue;
+ }
+
+ const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
+ if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
+ (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
+ (aBound.*fnRect->fnGetBottom)() ) > 0 ||
+ nLeft > (aBound.*fnRect->fnGetRight)() ||
+ (aBound.*fnRect->fnGetHeight)() >
+ 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
+ {
+ continue;
+ }
+ // <--
+
+ // --> OD 2004-10-06 #i26945# - pass <pAnchoredObj> to method
+ // <GetTop(..)> instead of only the <SdrObject> instance of the
+ // anchored object
+ if ( GetTop( pAnchoredObj, pCurrFrm->IsInFtn(), bFooterHeader ) )
+ // <--
+ {
+ // OD 11.03.2003 #107862# - adjust insert position:
+ // overlapping objects should be sorted from left to right and
+ // inside left to right sorting from top to bottom.
+ // If objects on the same position are found, they are sorted
+ // on its width.
+ // --> OD 2006-08-15 #i68520#
+// sal_uInt16 nPos = pFlyList->Count();
+// while ( nPos )
+// {
+// SdrObject* pTmpObj = (*pFlyList)[ --nPos ];
+// const SwRect aBoundRectOfTmpObj( GetBoundRect( pTmpObj ) );
+// if ( ( bR2L &&
+// ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ==
+// (aBound.*fnRect->fnGetRight)() ) ) ||
+// ( !bR2L &&
+// ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ==
+// (aBound.*fnRect->fnGetLeft)() ) ) )
+// {
+// SwTwips nTopDiff =
+// (*fnRect->fnYDiff)( (aBound.*fnRect->fnGetTop)(),
+// (aBoundRectOfTmpObj.*fnRect->fnGetTop)() );
+// if ( nTopDiff == 0 &&
+// ( ( bR2L &&
+// ( (aBound.*fnRect->fnGetLeft)() >
+// (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ) ) ||
+// ( !bR2L &&
+// ( (aBound.*fnRect->fnGetRight)() <
+// (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ) ) ) )
+// {
+// ++nPos;
+// break;
+// }
+// else if ( nTopDiff > 0 )
+// {
+// ++nPos;
+// break;
+// }
+// }
+// else if ( ( bR2L &&
+// ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() >
+// (aBound.*fnRect->fnGetRight)() ) ) ||
+// ( !bR2L &&
+// ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() <
+// (aBound.*fnRect->fnGetLeft)() ) ) )
+// {
+// ++nPos;
+// break;
+// }
+// }
+// SdrObject* pSdrObj = pAnchoredObj->DrawObj();
+// pFlyList->C40_INSERT( SdrObject, pSdrObj, nPos );
+ {
+ SwAnchoredObjList::iterator aInsPosIter =
+ std::lower_bound( mpAnchoredObjList->begin(),
+ mpAnchoredObjList->end(),
+ pAnchoredObj,
+ AnchoredObjOrder( bR2L, fnRect ) );
+
+ mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
+ }
+ // <--
+
+ const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
+ // --> OD 2006-08-15 #i68520#
+ if ( rFlyFmt.IsAnchorOnly() &&
+ pAnchoredObj->GetAnchorFrm() == GetMaster() )
+ // <--
+ {
+ const SwFmtVertOrient &rTmpFmt =
+ pAnchoredObj->GetFrmFmt().GetVertOrient();
+ if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
+ nMinBottom = ( bVert && nMinBottom ) ?
+ Min( nMinBottom, aBound.Left() ) :
+ Max( nMinBottom, (aBound.*fnRect->fnGetBottom)() );
+ }
+
+ bOn = sal_True;
+ }
+ }
+ if( nMinBottom )
+ {
+ SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
+ if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
+ nMinBottom = nMax;
+ }
+ }
+ else
+ {
+ // --> OD 2006-08-15 #i68520#
+ mpAnchoredObjList = new SwAnchoredObjList();
+ // <--
+ }
+
+ UNDO_SWAP( pCurrFrm )
+
+ // --> OD 2006-08-15 #i68520#
+ return mpAnchoredObjList;
+ // <--
+}
+// <--
+
+SwTwips SwTxtFly::CalcMinBottom() const
+{
+ SwTwips nRet = 0;
+ const SwSortedObjs *pDrawObj = GetMaster()->GetDrawObjs();
+ const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0;
+ if( nCount )
+ {
+ SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
+ for( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
+ const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
+ if( rFlyFmt.IsAnchorOnly() )
+ {
+ const SwFmtVertOrient &rTmpFmt =
+ pAnchoredObj->GetFrmFmt().GetVertOrient();
+ if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
+ {
+ const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
+ if( aBound.Top() < nEndOfFrm )
+ nRet = Max( nRet, aBound.Bottom() );
+ }
+ }
+ }
+ SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
+ pCurrFrm->GetUpper()->Prt().Bottom();
+ if( nRet > nMax )
+ nRet = nMax;
+ }
+ return nRet;
+}
+
+/*************************************************************************
+ * Hier erfolgt die Berechnung der Kontur ...
+ * CalcBoundRect(..) und andere
+ *************************************************************************/
+
+/*************************************************************************
+ * class SwContourCache
+ *************************************************************************/
+
+SwContourCache::SwContourCache() :
+ nPntCnt( 0 ), nObjCnt( 0 )
+{
+ memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) );
+ memset( pTextRanger, 0, sizeof(pTextRanger) );
+}
+
+SwContourCache::~SwContourCache()
+{
+ for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
+ ;
+}
+
+void SwContourCache::ClrObject( MSHORT nPos )
+{
+ ASSERT( pTextRanger[ nPos ], "ClrObject: Allready cleared. Good Bye!" );
+ nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
+ delete pTextRanger[ nPos ];
+ --nObjCnt;
+ memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1,
+ ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
+ memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
+ ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
+}
+
+void ClrContourCache( const SdrObject *pObj )
+{
+ if( pContourCache && pObj )
+ for( MSHORT i = 0; i < pContourCache->GetCount(); ++i )
+ if( pObj == pContourCache->GetObject( i ) )
+ {
+ pContourCache->ClrObject( i );
+ break;
+ }
+}
+
+void ClrContourCache()
+{
+ if( pContourCache )
+ {
+ for( MSHORT i = 0; i < pContourCache->GetCount();
+ delete pContourCache->pTextRanger[ i++ ] )
+ ;
+ pContourCache->nObjCnt = 0;
+ pContourCache->nPntCnt = 0;
+ }
+}
+
+/*************************************************************************
+ * SwContourCache::CalcBoundRect
+ * berechnet das Rechteck, welches vom Objekt in der angegebenen Zeile
+ * ueberdeckt wird.
+ * Bei _nicht_ konturumflossenen Objekten ist dies einfach die Ueber-
+ * lappung von BoundRect (inkl. Abstand!) und Zeile,
+ * bei Konturumfluss wird das Polypolygon des Objekts abgeklappert
+ *************************************************************************/
+// --> OD 2006-08-15 #i68520#
+const SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
+ const SwRect &rLine,
+ const SwTxtFrm* pFrm,
+ const long nXPos,
+ const sal_Bool bRight )
+{
+ SwRect aRet;
+ const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
+ if( pFmt->GetSurround().IsContour() &&
+ ( !pAnchoredObj->ISA(SwFlyFrm) ||
+ ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
+ static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) )
+ {
+ aRet = pAnchoredObj->GetObjRectWithSpaces();
+ if( aRet.IsOver( rLine ) )
+ {
+ if( !pContourCache )
+ pContourCache = new SwContourCache;
+
+ aRet = pContourCache->ContourRect(
+ pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
+ }
+ else
+ aRet.Width( 0 );
+ }
+ else
+ {
+ aRet = pAnchoredObj->GetObjRectWithSpaces();
+ }
+
+ return aRet;
+}
+// <--
+
+const SwRect SwContourCache::ContourRect( const SwFmt* pFmt,
+ const SdrObject* pObj, const SwTxtFrm* pFrm, const SwRect &rLine,
+ const long nXPos, const sal_Bool bRight )
+{
+ SwRect aRet;
+ MSHORT nPos = 0; // Suche im Cache ...
+ while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
+ ++nPos;
+ if( GetCount() == nPos ) // nicht gefunden
+ {
+ if( nObjCnt == POLY_CNT )
+ {
+ nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
+ delete pTextRanger[ nObjCnt ];
+ }
+ ::basegfx::B2DPolyPolygon aPolyPolygon;
+ ::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;
+
+ if ( pObj->ISA(SwVirtFlyDrawObj) )
+ {
+ // Vorsicht #37347: Das GetContour() fuehrt zum Laden der Grafik,
+ // diese aendert dadurch ggf. ihre Groesse, ruft deshalb ein
+ // ClrObject() auf.
+ PolyPolygon aPoly;
+ if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) )
+ aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)->
+ GetFlyFrm()->Frm().SVRect() );
+ aPolyPolygon.clear();
+ aPolyPolygon.append(aPoly.getB2DPolyPolygon());
+ }
+ else
+ {
+ if( !pObj->ISA( E3dObject ) )
+ {
+ aPolyPolygon = pObj->TakeXorPoly();
+ }
+
+ ::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour());
+ pPolyPolygon = new ::basegfx::B2DPolyPolygon(aContourPoly);
+ }
+ const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace();
+ const SvxULSpaceItem &rULSpace = pFmt->GetULSpace();
+ memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
+ memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
+ pSdrObj[ 0 ] = pObj; // Wg. #37347 darf das Object erst nach dem
+ // GetContour() eingetragen werden.
+ pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
+ (USHORT)rLRSpace.GetLeft(), (USHORT)rLRSpace.GetRight(),
+ pFmt->GetSurround().IsOutside(), sal_False, pFrm->IsVertical() );
+ pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
+ pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );
+
+ delete pPolyPolygon;
+ // UPPER_LOWER_TEST
+#ifdef DBG_UTIL
+ const SwRootFrm* pTmpRootFrm = pFmt->getIDocumentLayoutAccess()->GetRootFrm();
+ if( pTmpRootFrm->GetCurrShell() )
+ {
+ sal_Bool bT2 = pTmpRootFrm->GetCurrShell()->GetViewOptions()->IsTest2();
+ sal_Bool bT6 = pTmpRootFrm->GetCurrShell()->GetViewOptions()->IsTest6();
+ if( bT2 || bT6 )
+ {
+ if( bT2 )
+ pTextRanger[ 0 ]->SetFlag7( sal_True );
+ else
+ pTextRanger[ 0 ]->SetFlag6( sal_True );
+ }
+ }
+#endif
+ nPntCnt += pTextRanger[ 0 ]->GetPointCount();
+ while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
+ {
+ nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
+ delete pTextRanger[ nObjCnt ];
+ }
+ }
+ else if( nPos )
+ {
+ const SdrObject* pTmpObj = pSdrObj[ nPos ];
+ TextRanger* pTmpRanger = pTextRanger[ nPos ];
+ memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nPos * sizeof( SdrObject* ) );
+ memmove( pTextRanger + 1, pTextRanger, nPos * sizeof( TextRanger* ) );
+ pSdrObj[ 0 ] = pTmpObj;
+ pTextRanger[ 0 ] = pTmpRanger;
+ }
+ SWRECTFN( pFrm )
+ long nTmpTop = (rLine.*fnRect->fnGetTop)();
+ // fnGetBottom is top + height
+ long nTmpBottom = (rLine.*fnRect->fnGetBottom)();
+
+ Range aRange( Min( nTmpTop, nTmpBottom ), Max( nTmpTop, nTmpBottom ) );
+
+ SvLongs *pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );
+
+ MSHORT nCount;
+ if( 0 != ( nCount = pTmp->Count() ) )
+ {
+ MSHORT nIdx = 0;
+ while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
+ ++nIdx;
+ sal_Bool bOdd = nIdx % 2 ? sal_True : sal_False;
+ sal_Bool bSet = sal_True;
+ if( bOdd )
+ --nIdx; // innerhalb eines Intervalls
+ else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
+ {
+ if( nIdx )
+ nIdx -= 2; // ein Intervall nach links gehen
+ else
+ bSet = sal_False; // vor dem erstem Intervall
+ }
+
+ if( bSet && nIdx < nCount )
+ {
+ (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
+ (rLine.*fnRect->fnGetHeight)() );
+ (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
+ (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
+ }
+ }
+ return aRet;
+}
+
+/*************************************************************************
+ * SwContourCache::ShowContour()
+ * zeichnet die PolyPolygone des Caches zu Debugzwecken.
+ *************************************************************************/
+#ifdef DBG_UTIL
+
+void SwContourCache::ShowContour( OutputDevice* pOut, const SdrObject* pObj,
+ const Color& rClosedColor, const Color& rOpenColor )
+{
+ MSHORT nPos = 0; // Suche im Cache ...
+ while( nPos < POLY_CNT && pObj != pSdrObj[ nPos ] )
+ ++nPos;
+ if( POLY_CNT != nPos )
+ {
+ const PolyPolygon* pPol = pTextRanger[ nPos ]->GetLinePolygon();
+ if( !pPol )
+ pPol = &(pTextRanger[ nPos ]->GetPolyPolygon());
+ for( MSHORT i = 0; i < pPol->Count(); ++i )
+ {
+ pOut->SetLineColor( rOpenColor );
+ const Polygon& rPol = (*pPol)[ i ];
+ MSHORT nCount = rPol.GetSize();
+ if( nCount > 1 && rPol[ 0 ] == rPol[ nCount - 1 ] )
+ pOut->SetLineColor( rClosedColor );
+ pOut->DrawPolygon( rPol );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ static KSHORT nRadius = 0;
+ if( nRadius )
+ {
+ KSHORT nHalf = nRadius / 2;
+ Size aSz( nRadius, nRadius );
+ for( MSHORT i = 0; i < pPol->Count(); ++i )
+ {
+ const Polygon& rPol = (*pPol)[ i ];
+ MSHORT nCount = rPol.GetSize();
+ for( MSHORT k = 0; k < nCount; ++k )
+ {
+ Point aPt( rPol[ k ] );
+ aPt.X() -= nHalf;
+ aPt.Y() -= nHalf;
+ Rectangle aTmp( aPt, aSz );
+ pOut->DrawEllipse( aTmp );
+ }
+ }
+ }
+#endif
+ }
+}
+#endif
+
+/*************************************************************************
+ * SwTxtFly::ShowContour()
+ * zeichnet die PolyPolygone des Caches zu Debugzwecken.
+ *************************************************************************/
+#ifdef DBG_UTIL
+
+void SwTxtFly::ShowContour( OutputDevice* pOut )
+{
+ MSHORT nFlyCount;
+ if( bOn && ( 0 != ( nFlyCount = static_cast<USHORT>(GetAnchoredObjList()->size() ) ) ) )
+ {
+ Color aRedColor( COL_LIGHTRED );
+ Color aGreenColor( COL_LIGHTGREEN );
+ Color aSaveColor( pOut->GetLineColor() );
+ for( MSHORT j = 0; j < nFlyCount; ++j )
+ {
+ const SwAnchoredObject* pObj = (*mpAnchoredObjList)[ j ];
+ if( !pObj->GetFrmFmt().GetSurround().IsContour() )
+ {
+ Rectangle aRect = pObj->GetObjRectWithSpaces().SVRect();
+ pOut->DrawRect( aRect );
+ continue;
+ }
+ pContourCache->ShowContour( pOut, pObj->GetDrawObj(), aRedColor, aGreenColor );
+ }
+ pOut->SetLineColor( aSaveColor );
+ }
+}
+#endif
+
+/*************************************************************************
+ * SwTxtFly::ForEach()
+ *
+ * sucht nach dem ersten Objekt, welches mit dem Rechteck ueberlappt
+ *
+ *************************************************************************/
+
+sal_Bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, sal_Bool bAvoid ) const
+{
+ SWAP_IF_SWAPPED( pCurrFrm )
+
+ sal_Bool bRet = sal_False;
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
+ if ( bOn && nCount > 0 )
+ // <--
+ {
+ for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
+
+ SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
+ // <--
+
+ // Optimierung
+ SWRECTFN( pCurrFrm )
+ if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
+ break;
+ // --> OD 2006-08-15 #i68520#
+ if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
+ // <--
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) );
+ const SwFmtSurround &rSur = pFmt->GetSurround();
+ // <--
+ if( bAvoid )
+ {
+ // Wenn der Text drunter durchlaeuft, bleibt die
+ // Formatierung unbeeinflusst. Im LineIter::DrawText()
+ // muessen "nur" geschickt die ClippingRegions gesetzt werden ...
+ const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
+ if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
+ ( !rSur.IsAnchorOnly() ||
+ // --> OD 2006-08-15 #i68520#
+ GetMaster() == pAnchoredObj->GetAnchorFrm() ||
+ // <--
+ ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
+ (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
+ || aRect.Top() == WEIT_WECH )
+ continue;
+ }
+
+ // --> OD 2006-01-20 #i58642#
+ // Compare <GetMaster()> instead of <pCurrFrm> with the anchor
+ // frame of the anchored object, because a follow frame have
+ // to ignore the anchored objects of its master frame.
+ // Note: Anchored objects are always registered at the master
+ // frame, exception are as-character anchored objects,
+ // but these aren't handled here.
+ // --> OD 2006-08-15 #i68520#
+ if ( mbIgnoreCurrentFrame &&
+ GetMaster() == pAnchoredObj->GetAnchorFrm() )
+ continue;
+ // <--
+
+ if( pRect )
+ {
+ // --> OD 2006-08-15 #i68520#
+ SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
+ // <--
+ if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
+ continue;
+ if( !bRet ||
+ ( !pCurrFrm->IsRightToLeft() &&
+ ( (aFly.*fnRect->fnGetLeft)() <
+ (pRect->*fnRect->fnGetLeft)() ) ||
+ ( pCurrFrm->IsRightToLeft() &&
+ ( (aFly.*fnRect->fnGetRight)() >
+ (pRect->*fnRect->fnGetRight)() ) ) ) )
+ *pRect = aFly;
+ if( rSur.IsContour() )
+ {
+ bRet = sal_True;
+ continue;
+ }
+ }
+ bRet = sal_True;
+ break;
+ }
+ }
+ }
+
+ UNDO_SWAP( pCurrFrm )
+
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFly::GetPos()
+ *
+ * liefert die Position im sorted Array zurueck
+ *************************************************************************/
+
+// --> OD 2006-08-15 #i68520#
+SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
+{
+ SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
+ SwAnchoredObjList::size_type nRet = 0;
+ while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
+ ++nRet;
+ return nRet;
+}
+// <--
+
+/*************************************************************************
+ * SwTxtFly::CalcRightMargin()
+ *
+ * pObj ist das Object, der uns gerade ueberlappt.
+ * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird.
+ * Der rechte Rand ist der rechte Rand oder
+ * er wird durch das naechste Object, welches in die Zeile ragt, bestimmt.
+ *************************************************************************/
+// --> OD 2006-08-15 #i68520#
+void SwTxtFly::CalcRightMargin( SwRect &rFly,
+ SwAnchoredObjList::size_type nFlyPos,
+ const SwRect &rLine ) const
+{
+ // Normalerweise ist der rechte Rand der rechte Rand der Printarea.
+ ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
+ "SwTxtFly::CalcRightMargin with swapped frame" )
+ SWRECTFN( pCurrFrm )
+ // --> OD 2004-12-14 #118796# - correct determination of right of printing area
+ SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
+ // <--
+ SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
+ SwRect aLine( rLine );
+ (aLine.*fnRect->fnSetRight)( nRight );
+ (aLine.*fnRect->fnSetLeft)( (rFly.*fnRect->fnGetLeft)() );
+
+ // Es koennte aber sein, dass in die gleiche Zeile noch ein anderes
+ // Object hineinragt, welches _ueber_ uns liegt.
+ // Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden
+ // unsichtbar, das heisst, dass sie bei der Berechnung der Raender
+ // anderer Flys ebenfalls nicht auffallen.
+ // 3301: pNext->Frm().IsOver( rLine ) ist noetig
+ // --> OD 2006-08-15 #i68520#
+ SwSurround eSurroundForTextWrap;
+ // <--
+
+ sal_Bool bStop = sal_False;
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList::size_type nPos = 0;
+ // <--
+
+ // --> OD 2006-08-15 #i68520#
+ while( nPos < mpAnchoredObjList->size() && !bStop )
+ // <--
+ {
+ if( nPos == nFlyPos )
+ {
+ ++nPos;
+ continue;
+ }
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
+ if ( pNext == mpCurrAnchoredObj )
+ continue;
+ eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
+ if( SURROUND_THROUGHT == eSurroundForTextWrap )
+ continue;
+ // <--
+
+ const SwRect aTmp( SwContourCache::CalcBoundRect
+ ( pNext, aLine, pCurrFrm, nFlyRight, sal_True ) );
+ SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
+
+ // Optimierung:
+ // In nNextTop wird notiert, an welcher Y-Positon mit Aenderung der
+ // Rahmenverhaeltnisse gerechnet werden muss. Dies dient dazu, dass,
+ // obwohl nur die Rahmen in der aktuellen Zeilenhoehe betrachtet werden,
+ // bei Rahmen ohne Umlauf die Zeilenhoehe so erhoeht wird, dass mit einer
+ // einzigen Zeile die Unterkante das Rahmens oder ggf. die Oberkante des
+ // naechsten Rahmen erreicht wird.
+ // Insbesondere bei HTML-Dokumenten kommen oft (Dummy-)Absaetze in einer
+ // 2-Pt.-Schrift vor, bis diese einem groesseren Rahmen ausgewichen sind,
+ // erforderte es frueher Unmengen von Leerzeilen.
+ const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
+ if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 )
+ {
+ if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 )
+ SetNextTop( nTmpTop ); // Die Oberkante des "naechsten" Rahmens
+ }
+ else if( ! (aTmp.*fnRect->fnGetWidth)() ) // Typisch fuer Objekte mit Konturumlauf
+ { // Bei Objekten mit Konturumlauf, die vor der aktuellen Zeile beginnen
+ // und hinter ihr enden, trotzdem aber nicht mit ihr ueberlappen,
+ // muss die Optimierung ausgeschaltet werden, denn bereits in der
+ // naechsten Zeile kann sich dies aendern.
+ if( ! (aTmp.*fnRect->fnGetHeight)() ||
+ (*fnRect->fnYDiff)( (aTmp.*fnRect->fnGetBottom)(),
+ (aLine.*fnRect->fnGetTop)() ) > 0 )
+ SetNextTop( 0 );
+ }
+ if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
+ {
+ nFlyRight = nTmpRight;
+ if( SURROUND_RIGHT == eSurroundForTextWrap ||
+ SURROUND_PARALLEL == eSurroundForTextWrap )
+ {
+ // der FlyFrm wird ueberstimmt.
+ if( nRight > nFlyRight )
+ nRight = nFlyRight;
+ bStop = sal_True;
+ }
+ }
+ }
+ (rFly.*fnRect->fnSetRight)( nRight );
+}
+// <--
+
+/*************************************************************************
+ * SwTxtFly::CalcLeftMargin()
+ *
+ * pFly ist der FlyFrm, der uns gerade ueberlappt.
+ * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird.
+ * Der linke Rand ist der linke Rand der aktuellen PrintArea oder
+ * er wird durch den vorigen FlyFrm, der in die Zeile ragt, bestimmt.
+ *************************************************************************/
+// --> OD 2006-08-15 #i68520#
+void SwTxtFly::CalcLeftMargin( SwRect &rFly,
+ SwAnchoredObjList::size_type nFlyPos,
+ const SwRect &rLine ) const
+{
+ ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
+ "SwTxtFly::CalcLeftMargin with swapped frame" )
+ SWRECTFN( pCurrFrm )
+ // --> OD 2004-12-14 #118796# - correct determination of left of printing area
+ SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
+ // <--
+ const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();
+
+ if( nLeft > nFlyLeft )
+ nLeft = rFly.Left();
+
+ SwRect aLine( rLine );
+ (aLine.*fnRect->fnSetLeft)( nLeft );
+
+ // Es koennte aber sein, dass in die gleiche Zeile noch ein anderes
+ // Object hineinragt, welches _ueber_ uns liegt.
+ // Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden
+ // unsichtbar, das heisst, dass sie bei der Berechnung der Raender
+ // anderer Flys ebenfalls nicht auffallen.
+ // 3301: pNext->Frm().IsOver( rLine ) ist noetig
+
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList::size_type nMyPos = nFlyPos;
+ while( ++nFlyPos < mpAnchoredObjList->size() )
+ // <--
+ {
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
+ const SwRect aTmp( pNext->GetObjRectWithSpaces() );
+ // <--
+ if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
+ break;
+ }
+
+ while( nFlyPos )
+ {
+ if( --nFlyPos == nMyPos )
+ continue;
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
+ if( pNext == mpCurrAnchoredObj )
+ continue;
+ SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
+ if( SURROUND_THROUGHT == eSurroundForTextWrap )
+ continue;
+ // <--
+
+ const SwRect aTmp( SwContourCache::CalcBoundRect
+ ( pNext, aLine, pCurrFrm, nFlyLeft, sal_False ) );
+
+ if( (aTmp.*fnRect->fnGetLeft)() < nFlyLeft && aTmp.IsOver( aLine ) )
+ {
+ // --> OD 2004-12-14 #118796# - no '+1', because <..fnGetRight>
+ // returns the correct value.
+ SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
+ if ( nLeft <= nTmpRight )
+ nLeft = nTmpRight;
+ // <--
+
+ break;
+ }
+ }
+ (rFly.*fnRect->fnSetLeft)( nLeft );
+}
+// <--
+
+/*************************************************************************
+ * SwTxtFly::FlyToRect()
+ *
+ * IN: dokumentglobal (rRect)
+ * OUT: dokumentglobal (return-Wert)
+ * Liefert zu einem SwFlyFrm das von ihm in Anspruch genommene Rechteck
+ * unter Beruecksichtigung der eingestellten Attribute fuer den Abstand
+ * zum Text zurueck.
+ *************************************************************************/
+// --> OD 2006-08-15 #i68520#
+SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
+ const SwRect &rLine ) const
+{
+ SWRECTFN( pCurrFrm )
+
+ const long nXPos = pCurrFrm->IsRightToLeft() ?
+ rLine.Right() :
+ (rLine.*fnRect->fnGetLeft)();
+
+ SwRect aFly = mbIgnoreContour ?
+ pAnchoredObj->GetObjRectWithSpaces() :
+ SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
+ nXPos, ! pCurrFrm->IsRightToLeft() );
+
+ if( !aFly.Width() )
+ return aFly;
+
+ SetNextTop( (aFly.*fnRect->fnGetBottom)() ); // Damit die Zeile ggf. bis zur Unterkante
+ // des Rahmens waechst.
+ SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );
+
+ // Bei LEFT und RIGHT vergroessern wir das Rechteck.
+ // Hier gibt es einige Probleme, wenn mehrere Frames zu sehen sind.
+ // Zur Zeit wird nur der einfachste Fall angenommen:
+ // LEFT bedeutet, dass der Text links vom Frame fliessen soll,
+ // d.h. der Frame blaeht sich bis zum rechten Rand der Printarea
+ // oder bis zum naechsten Frame auf.
+ // Bei RIGHT ist es umgekehrt.
+ // Ansonsten wird immer der eingestellte Abstand zwischen Text
+ // und Frame aufaddiert.
+ switch( _GetSurroundForTextWrap( pAnchoredObj ) )
+ {
+ case SURROUND_LEFT :
+ {
+ CalcRightMargin( aFly, nFlyPos, rLine );
+ break;
+ }
+ case SURROUND_RIGHT :
+ {
+ CalcLeftMargin( aFly, nFlyPos, rLine );
+ break;
+ }
+ case SURROUND_NONE :
+ {
+ CalcRightMargin( aFly, nFlyPos, rLine );
+ CalcLeftMargin( aFly, nFlyPos, rLine );
+ break;
+ }
+ default:
+ break;
+ }
+ return aFly;
+}
+
+// --> OD 2006-08-15 #i68520#
+// new method <_GetSurroundForTextWrap(..)> replaces methods
+// <CalcSmart(..)> and <GetOrder(..)>
+/*************************************************************************
+ * SwTxtFly::CalcSmart()
+ *
+ * CalcSmart() liefert die Umlaufform zurueck.
+ *
+ * Auf beiden Seiten ist weniger als 2 cm Platz fuer den Text
+ * => kein Umlauf ( SURROUND_NONE )
+ * Auf genau einer Seite ist mehr als 2 cm Platz
+ * => Umlauf auf dieser Seite ( SURROUND_LEFT / SURROUND_RIGHT )
+ * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist breiter als 1,5 cm
+ * => Umlauf auf der breiteren Seite ( SURROUND_LEFT / SURROUND_RIGHT )
+ * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist schmaler als 1,5 cm
+ * => beidseitiger Umlauf ( SURROUND_PARALLEL )
+ *
+ *************************************************************************/
+
+// Umfluss nur auf Seiten mit mindestens 2 cm Platz fuer den Text
+#define TEXT_MIN 1134
+// Beidseitiger Umfluss bis zu einer Rahmenbreite von maximal 1,5 cm
+#define FRAME_MAX 850
+
+SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
+{
+ const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
+ const SwFmtSurround &rFlyFmt = pFmt->GetSurround();
+ SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround();
+
+ if( rFlyFmt.IsAnchorOnly() && pAnchoredObj->GetAnchorFrm() != GetMaster() )
+ {
+ const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
+ if ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
+ (FLY_AT_CHAR == rAnchor.GetAnchorId()))
+ {
+ return SURROUND_NONE;
+ }
+ }
+
+ // Beim Durchlauf und Nowrap wird smart ignoriert.
+ if( SURROUND_THROUGHT == eSurroundForTextWrap ||
+ SURROUND_NONE == eSurroundForTextWrap )
+ return eSurroundForTextWrap;
+
+ // left is left and right is right
+ if ( pCurrFrm->IsRightToLeft() )
+ {
+ if ( SURROUND_LEFT == eSurroundForTextWrap )
+ eSurroundForTextWrap = SURROUND_RIGHT;
+ else if ( SURROUND_RIGHT == eSurroundForTextWrap )
+ eSurroundForTextWrap = SURROUND_LEFT;
+ }
+
+ // "idealer Seitenumlauf":
+ if ( SURROUND_IDEAL == eSurroundForTextWrap )
+ {
+ SWRECTFN( pCurrFrm )
+ const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
+ const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
+ const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
+ long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
+ long nFlyRight = (aRect.*fnRect->fnGetRight)();
+
+ if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
+ eSurroundForTextWrap = SURROUND_PARALLEL;
+ else
+ {
+ long nLeft = nFlyLeft - nCurrLeft;
+ long nRight = nCurrRight - nFlyRight;
+ if( nFlyRight - nFlyLeft > FRAME_MAX )
+ {
+ if( nLeft < nRight )
+ nLeft = 0;
+ else
+ nRight = 0;
+ }
+ if( nLeft < TEXT_MIN )
+ nLeft = 0;
+ if( nRight < TEXT_MIN )
+ nRight = 0;
+ if( nLeft )
+ eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
+ else
+ eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
+ }
+ }
+
+ return eSurroundForTextWrap;
+}
+
+/*************************************************************************
+ * SwTxtFly::IsAnyFrm( SwRect )
+ *
+ * IN: dokumentglobal
+ *
+ * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax)
+ *
+ *************************************************************************/
+
+sal_Bool SwTxtFly::IsAnyFrm( const SwRect &rLine ) const
+{
+
+ SWAP_IF_SWAPPED( pCurrFrm )
+
+ ASSERT( bOn, "IsAnyFrm: Why?" );
+
+ const sal_Bool bRet = ForEach( rLine, NULL, sal_False );
+ UNDO_SWAP( pCurrFrm )
+ return bRet;
+}
diff --git a/sw/source/core/text/txtfly.hxx b/sw/source/core/text/txtfly.hxx
new file mode 100644
index 000000000000..8c128c52c015
--- /dev/null
+++ b/sw/source/core/text/txtfly.hxx
@@ -0,0 +1,259 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _TXTFLY_HXX
+#define _TXTFLY_HXX
+#include <svl/svarray.hxx>
+
+#include "swtypes.hxx"
+#include "swrect.hxx"
+
+class OutputDevice;
+class SwCntntFrm;
+class SwPageFrm;
+class SwTxtFly;
+class SdrObject;
+class SwTxtPaintInfo;
+class SwFmt;
+class TextRanger;
+class Color;
+// --> OD 2004-10-06 #i26945#
+class SwAnchoredObject;
+// <--
+
+// --> OD 2006-08-15 #i68520# - refactoring
+//typedef MSHORT _FlyCntnt;
+#include <fmtsrndenum.hxx>
+// <--
+
+// --> OD 2006-08-15 #i68520#
+//SV_DECL_PTRARR( SwFlyList, SdrObject*, 10, 10 )
+#include <vector>
+typedef std::vector< SwAnchoredObject* > SwAnchoredObjList;
+// <--
+
+/*************************************************************************
+ * class SwFlyIter
+ *************************************************************************/
+enum PAGESIDE { LEFT_SIDE, RIGHT_SIDE, DONTKNOW_SIDE };
+
+/*************************************************************************
+ * class SwContourCache
+ *************************************************************************/
+
+class SwDrawTextInfo;
+// Contour-Cache, globale Variable, in txtinit.cxx initialisiert/zerstoert
+// und in txtfly.cxx benutzt bei Konturumfluss
+class SwContourCache;
+extern SwContourCache *pContourCache;
+class SwTxtFrm;
+
+#define POLY_CNT 20
+#define POLY_MIN 5
+#define POLY_MAX 4000
+
+class SwContourCache
+{
+ friend void ClrContourCache();
+ const SdrObject *pSdrObj[ POLY_CNT ];
+ TextRanger *pTextRanger[ POLY_CNT ];
+ long nPntCnt;
+ MSHORT nObjCnt;
+ const SwRect ContourRect( const SwFmt* pFmt, const SdrObject* pObj,
+ const SwTxtFrm* pFrm, const SwRect &rLine, const long nXPos,
+ const sal_Bool bRight );
+
+public:
+ SwContourCache();
+ ~SwContourCache();
+ const SdrObject* GetObject( MSHORT nPos ){ return pSdrObj[ nPos ]; }
+ MSHORT GetCount() const { return nObjCnt; }
+ void ClrObject( MSHORT nPos );
+ // --> OD 2006-08-15 #i68520#
+ static const SwRect CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
+ const SwRect &rLine,
+ const SwTxtFrm* pFrm,
+ const long nXPos,
+ const sal_Bool bRight );
+ // <--
+#ifdef DBG_UTIL
+ void ShowContour( OutputDevice* pOut, const SdrObject* pObj,
+ const Color& rClosedColor, const Color& rOpenColor );
+#endif
+};
+
+/*************************************************************************
+ * class SwTxtFly
+ *************************************************************************/
+
+class SwTxtFly
+{
+ const SwPageFrm *pPage;
+ // --> OD 2006-08-15 #i68520#
+ const SwAnchoredObject* mpCurrAnchoredObj;
+ // <--
+
+ const SwTxtFrm *pCurrFrm;
+
+ const SwCntntFrm *pMaster;
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList* mpAnchoredObjList;
+ // <--
+
+ long nMinBottom;
+ long nNextTop; // Hier wird die Oberkante des "naechsten" Rahmens gespeichert
+ ULONG nIndex;
+ sal_Bool bOn : 1;
+ sal_Bool bLeftSide : 1;
+ sal_Bool bTopRule: 1;
+ sal_Bool mbIgnoreCurrentFrame: 1;
+ sal_Bool mbIgnoreContour: 1;
+ // --> OD 2004-12-17 #118809# - boolean, indicating if objects in page
+ // header|footer are considered for text frames not in page header|footer.
+ sal_Bool mbIgnoreObjsInHeaderFooter: 1;
+ // <--
+ SwRect _GetFrm( const SwRect &rPortion, sal_Bool bTop ) const;
+ // --> OD 2006-08-15 #i68520#
+ SwAnchoredObjList* InitAnchoredObjList();
+ inline SwAnchoredObjList* GetAnchoredObjList() const
+ {
+ return mpAnchoredObjList
+ ? mpAnchoredObjList
+ : const_cast<SwTxtFly*>(this)->InitAnchoredObjList();
+ }
+ // iterates over the anchored object list <mpAnchoredObjList>
+ sal_Bool ForEach( const SwRect &rRect, SwRect* pRect, sal_Bool bAvoid ) const;
+ SwSurround _GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const;
+ void CalcRightMargin( SwRect &rFly,
+ SwAnchoredObjList::size_type nPos,
+ const SwRect &rLine ) const;
+ void CalcLeftMargin( SwRect &rFly,
+ SwAnchoredObjList::size_type nPos,
+ const SwRect &rLine ) const;
+ SwAnchoredObjList::size_type GetPos( const SwAnchoredObject* pAnchoredObj ) const;
+ // <--
+ // --> OD 2004-10-06 #i26945# - change first parameter:
+ // Now it's the <SwAnchoredObject> instance of the floating screen object
+ sal_Bool GetTop( const SwAnchoredObject* _pAnchoredObj,
+ const sal_Bool bInFtn,
+ const sal_Bool bInFooterOrHeader );
+ // <--
+ SwTwips CalcMinBottom() const;
+ const SwCntntFrm* _GetMaster();
+
+public:
+ inline SwTxtFly()
+ {
+ mbIgnoreCurrentFrame = sal_False;
+ mbIgnoreCurrentFrame = sal_False;
+ // --> OD 2004-12-17 #118809#
+ mbIgnoreObjsInHeaderFooter = sal_False;
+ // <--
+ // --> OD 2006-08-15 #i68520#
+ mpCurrAnchoredObj = 0;
+ mpAnchoredObjList = 0;
+ // <--
+ pMaster = 0;
+ }
+ inline SwTxtFly( const SwTxtFrm *pFrm )
+ { CtorInitTxtFly( pFrm ); }
+
+ SwTxtFly( const SwTxtFly& rTxtFly );
+ // --> OD 2006-08-15 #i68520#
+ inline ~SwTxtFly() { delete mpAnchoredObjList; }
+ // <--
+ void CtorInitTxtFly( const SwTxtFrm *pFrm );
+ void SetTopRule(){ bTopRule = sal_False; }
+
+ inline SwRect GetFrm( const SwRect &rPortion, sal_Bool bTop = sal_True ) const;
+ inline sal_Bool IsOn() const { return bOn; }
+ inline sal_Bool Relax( const SwRect &rRect );
+ inline sal_Bool Relax();
+ inline SwTwips GetMinBottom() const
+ // --> OD 2006-08-15 #i68520#
+ { return mpAnchoredObjList ? nMinBottom : CalcMinBottom(); }
+ // <--
+ inline const SwCntntFrm* GetMaster() const
+ { return pMaster ? pMaster : ((SwTxtFly*)this)->_GetMaster(); }
+ inline long GetNextTop() const { return nNextTop; }
+ // Diese temporaere Variable darf auch in const-Methoden manipuliert werden
+ inline void SetNextTop( long nNew ) const
+ { ((SwTxtFly*)this)->nNextTop = nNew; }
+
+ // --> OD 2006-08-15 #i68520#
+ // determines the demanded rectangle for an anchored object,
+ // considering its surround for text wrapping.
+ SwRect AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
+ const SwRect& rRect ) const;
+ // <--
+
+ // Die Drawmethoden stellen sicher, dass ueberlappende Frames
+ // (ausser bei transparenten Frames) nicht uebergepinselt werden.
+ sal_Bool DrawTextOpaque( SwDrawTextInfo &rInf );
+
+ void DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
+ const SwTxtPaintInfo &rInf, sal_Bool bNoGraphic = sal_False );
+
+ // Liefert zurueck, ob die Zeile von einem Frame ueberlappt wird.
+ sal_Bool IsAnyFrm( const SwRect &rLine ) const;
+ sal_Bool IsAnyFrm() const;
+ //Das Rechteck kann leer sein, es gilt dann der Frm.
+ sal_Bool IsAnyObj( const SwRect& ) const;
+
+ void SetIgnoreCurrentFrame( sal_Bool bNew ) { mbIgnoreCurrentFrame = bNew; }
+ void SetIgnoreContour( sal_Bool bNew ) { mbIgnoreContour = bNew; }
+ // --> OD 2004-12-17 #118809#
+ inline void SetIgnoreObjsInHeaderFooter( const sal_Bool _bNew )
+ {
+ mbIgnoreObjsInHeaderFooter = _bNew;
+ }
+ // <--
+
+#ifdef DBG_UTIL
+ void ShowContour( OutputDevice* pOut );
+#endif
+};
+
+// Wenn in das rRect (meist die aktuelle Zeile) kein freifliegender
+// Frame ragt, dann schalten wir uns ab.
+// rRect ist dokumentglobal !
+inline sal_Bool SwTxtFly::Relax( const SwRect &rRect )
+{
+ return 0 != (bOn = bOn && IsAnyFrm( rRect ));
+}
+
+inline sal_Bool SwTxtFly::Relax()
+{
+ return 0 != (bOn = bOn && IsAnyFrm());
+}
+
+inline SwRect SwTxtFly::GetFrm( const SwRect &rRect, sal_Bool bTop ) const
+{
+ return bOn ? _GetFrm( rRect, bTop ) : SwRect();
+}
+
+
+#endif
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
new file mode 100644
index 000000000000..0861f98b2ddf
--- /dev/null
+++ b/sw/source/core/text/txtfrm.cxx
@@ -0,0 +1,2753 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+#include <hints.hxx>
+#include <svl/ctloptions.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/sfxuno.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/pgrditem.hxx>
+#include <swmodule.hxx>
+#include <SwSmartTagMgr.hxx>
+#include <doc.hxx> // GetDoc()
+#include <pagefrm.hxx> // InvalidateSpelling
+#include <rootfrm.hxx>
+#include <viewsh.hxx> // ViewShell
+#include <pam.hxx> // SwPosition
+#include <ndtxt.hxx> // SwTxtNode
+#include <txtatr.hxx>
+#include <paratr.hxx>
+#include <viewopt.hxx>
+#include <dflyobj.hxx>
+#include <flyfrm.hxx>
+#include <tabfrm.hxx>
+#include <frmtool.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <dbg_lay.hxx>
+#include <fmtfld.hxx>
+#include <fmtftn.hxx>
+#include <txtfld.hxx>
+#include <txtftn.hxx>
+#include <charatr.hxx>
+#include <ftninfo.hxx>
+#include <fmtline.hxx>
+#include <txtfrm.hxx> // SwTxtFrm
+#include <sectfrm.hxx> // SwSectFrm
+#include <txtcfg.hxx> // DBG_LOOP
+#include <itrform2.hxx> // Iteratoren
+#include <widorp.hxx> // SwFrmBreak
+#include <txtcache.hxx>
+#include <fntcache.hxx> // GetLineSpace benutzt pLastFont
+#include <SwGrammarMarkUp.hxx>
+#include <lineinfo.hxx>
+#include <SwPortionHandler.hxx>
+// OD 2004-01-15 #110582#
+#include <dcontact.hxx>
+// OD 2004-05-24 #i28701#
+#include <sortedobjs.hxx>
+// --> OD 2005-03-30 #???#
+#include <txtflcnt.hxx> // SwTxtFlyCnt
+#include <fmtflcnt.hxx> // SwFmtFlyCnt
+#include <fmtcntnt.hxx> // SwFmtCntnt
+// <--
+// --> OD 2008-01-31 #newlistlevelattrs#
+#include <numrule.hxx>
+// <--
+#include <swtable.hxx>
+#include <fldupde.hxx>
+#include <IGrammarContact.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <txtpaint.hxx> // DbgRect
+extern const sal_Char *GetPrepName( const enum PrepareHint ePrep );
+#endif
+
+
+TYPEINIT1( SwTxtFrm, SwCntntFrm );
+
+// Switches width and height of the text frame
+void SwTxtFrm::SwapWidthAndHeight()
+{
+ if ( ! bIsSwapped )
+ {
+ const long nPrtOfstX = Prt().Pos().X();
+ Prt().Pos().X() = Prt().Pos().Y();
+ Prt().Pos().Y() = Frm().Width() - ( nPrtOfstX + Prt().Width() );
+ }
+ else
+ {
+ const long nPrtOfstY = Prt().Pos().Y();
+ Prt().Pos().Y() = Prt().Pos().X();
+ Prt().Pos().X() = Frm().Height() - ( nPrtOfstY + Prt().Height() );
+ }
+
+ const long nFrmWidth = Frm().Width();
+ Frm().Width( Frm().Height() );
+ Frm().Height( nFrmWidth );
+ const long nPrtWidth = Prt().Width();
+ Prt().Width( Prt().Height() );
+ Prt().Height( nPrtWidth );
+
+ bIsSwapped = ! bIsSwapped;
+}
+
+// Calculates the coordinates of a rectangle when switching from
+// horizontal to vertical layout.
+void SwTxtFrm::SwitchHorizontalToVertical( SwRect& rRect ) const
+{
+ // calc offset inside frame
+ const long nOfstX = rRect.Left() - Frm().Left();
+ const long nOfstY = rRect.Top() + rRect.Height() - Frm().Top();
+ const long nWidth = rRect.Width();
+ const long nHeight = rRect.Height();
+
+ if ( bIsSwapped )
+ rRect.Left( Frm().Left() + Frm().Height() - nOfstY );
+ else
+ // frame is rotated
+ rRect.Left( Frm().Left() + Frm().Width() - nOfstY );
+
+ rRect.Top( Frm().Top() + nOfstX );
+ rRect.Width( nHeight );
+ rRect.Height( nWidth );
+}
+
+// Calculates the coordinates of a point when switching from
+// horizontal to vertical layout.
+void SwTxtFrm::SwitchHorizontalToVertical( Point& rPoint ) const
+{
+ // calc offset inside frame
+ const long nOfstX = rPoint.X() - Frm().Left();
+ const long nOfstY = rPoint.Y() - Frm().Top();
+
+ if ( bIsSwapped )
+ rPoint.X() = Frm().Left() + Frm().Height() - nOfstY;
+ else
+ // calc rotated coords
+ rPoint.X() = Frm().Left() + Frm().Width() - nOfstY;
+
+ rPoint.Y() = Frm().Top() + nOfstX;
+}
+
+// Calculates the a limit value when switching from
+// horizontal to vertical layout.
+long SwTxtFrm::SwitchHorizontalToVertical( long nLimit ) const
+{
+ Point aTmp( 0, nLimit );
+ SwitchHorizontalToVertical( aTmp );
+ return aTmp.X();
+}
+
+// Calculates the coordinates of a rectangle when switching from
+// vertical to horizontal layout.
+void SwTxtFrm::SwitchVerticalToHorizontal( SwRect& rRect ) const
+{
+ long nOfstX;
+
+ // calc offset inside frame
+ if ( bIsSwapped )
+ nOfstX = Frm().Left() + Frm().Height() - ( rRect.Left() + rRect.Width() );
+ else
+ nOfstX = Frm().Left() + Frm().Width() - ( rRect.Left() + rRect.Width() );
+
+ const long nOfstY = rRect.Top() - Frm().Top();
+ const long nWidth = rRect.Height();
+ const long nHeight = rRect.Width();
+
+ // calc rotated coords
+ rRect.Left( Frm().Left() + nOfstY );
+ rRect.Top( Frm().Top() + nOfstX );
+ rRect.Width( nWidth );
+ rRect.Height( nHeight );
+}
+
+// Calculates the coordinates of a point when switching from
+// vertical to horizontal layout.
+void SwTxtFrm::SwitchVerticalToHorizontal( Point& rPoint ) const
+{
+ long nOfstX;
+
+ // calc offset inside frame
+ if ( bIsSwapped )
+ nOfstX = Frm().Left() + Frm().Height() - rPoint.X();
+ else
+ nOfstX = Frm().Left() + Frm().Width() - rPoint.X();
+
+ const long nOfstY = rPoint.Y() - Frm().Top();
+
+ // calc rotated coords
+ rPoint.X() = Frm().Left() + nOfstY;
+ rPoint.Y() = Frm().Top() + nOfstX;
+}
+
+// Calculates the a limit value when switching from
+// vertical to horizontal layout.
+long SwTxtFrm::SwitchVerticalToHorizontal( long nLimit ) const
+{
+ Point aTmp( nLimit, 0 );
+ SwitchVerticalToHorizontal( aTmp );
+ return aTmp.Y();
+}
+
+SwFrmSwapper::SwFrmSwapper( const SwTxtFrm* pTxtFrm, sal_Bool bSwapIfNotSwapped )
+ : pFrm( pTxtFrm ), bUndo( sal_False )
+{
+ if ( pFrm->IsVertical() &&
+ ( ( bSwapIfNotSwapped && ! pFrm->IsSwapped() ) ||
+ ( ! bSwapIfNotSwapped && pFrm->IsSwapped() ) ) )
+ {
+ bUndo = sal_True;
+ ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
+ }
+}
+
+SwFrmSwapper::~SwFrmSwapper()
+{
+ if ( bUndo )
+ ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
+}
+
+void SwTxtFrm::SwitchLTRtoRTL( SwRect& rRect ) const
+{
+ SWAP_IF_NOT_SWAPPED( this )
+
+ long nWidth = rRect.Width();
+ rRect.Left( 2 * ( Frm().Left() + Prt().Left() ) +
+ Prt().Width() - rRect.Right() - 1 );
+
+ rRect.Width( nWidth );
+
+ UNDO_SWAP( this )
+}
+
+void SwTxtFrm::SwitchLTRtoRTL( Point& rPoint ) const
+{
+ SWAP_IF_NOT_SWAPPED( this )
+
+ rPoint.X() = 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rPoint.X() - 1;
+
+ UNDO_SWAP( this )
+}
+
+SwLayoutModeModifier::SwLayoutModeModifier( const OutputDevice& rOutp ) :
+ rOut( rOutp ), nOldLayoutMode( rOutp.GetLayoutMode() )
+{
+}
+
+SwLayoutModeModifier::~SwLayoutModeModifier()
+{
+ ((OutputDevice&)rOut).SetLayoutMode( nOldLayoutMode );
+}
+
+void SwLayoutModeModifier::Modify( sal_Bool bChgToRTL )
+{
+ ((OutputDevice&)rOut).SetLayoutMode( bChgToRTL ?
+ TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL :
+ TEXT_LAYOUT_BIDI_STRONG );
+}
+
+void SwLayoutModeModifier::SetAuto()
+{
+ const ULONG nNewLayoutMode = nOldLayoutMode & ~TEXT_LAYOUT_BIDI_STRONG;
+ ((OutputDevice&)rOut).SetLayoutMode( nNewLayoutMode );
+}
+
+SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) :
+ rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() )
+{
+ LanguageType eLang = eCurLang;
+ const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals();
+
+ if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals )
+ eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
+ else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals )
+ eLang = LANGUAGE_ENGLISH;
+ else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals )
+ eLang = (LanguageType)::GetAppLanguage();
+
+ ((OutputDevice&)rOut).SetDigitLanguage( eLang );
+}
+
+SwDigitModeModifier::~SwDigitModeModifier()
+{
+ ((OutputDevice&)rOut).SetDigitLanguage( nOldLanguageType );
+}
+
+/*************************************************************************
+ * SwTxtFrm::Init()
+ *************************************************************************/
+
+void SwTxtFrm::Init()
+{
+ ASSERT( !IsLocked(), "+SwTxtFrm::Init: this ist locked." );
+ if( !IsLocked() )
+ {
+ ClearPara();
+ ResetBlinkPor();
+ //Die Flags direkt setzen um ResetPreps und damit ein unnuetzes GetPara
+ //einzusparen.
+ // Nicht bOrphan, bLocked oder bWait auf sal_False setzen !
+ // bOrphan = bFlag7 = bFlag8 = sal_False;
+ }
+}
+
+/*************************************************************************
+|* SwTxtFrm::CTORen/DTOR
+|*************************************************************************/
+
+void SwTxtFrm::InitCtor()
+{
+ nCacheIdx = MSHRT_MAX;
+ nOfst = 0;
+ nAllLines = 0;
+ nThisLines = 0;
+ mnFlyAnchorOfst = 0;
+ mnFlyAnchorOfstNoWrap = 0;
+ mnFtnLine = 0;
+ // OD 2004-03-17 #i11860#
+ mnHeightOfLastLine = 0;
+ // --> OD 2008-01-31 #newlistlevelattrs#
+ mnAdditionalFirstLineOffset = 0;
+ // <--
+
+ nType = FRMC_TXT;
+ bLocked = bFormatted = bWidow = bUndersized = bJustWidow =
+ bEmpty = bInFtnConnect = bFtn = bRepaint = bBlinkPor =
+ bFieldFollow = bHasAnimation = bIsSwapped = sal_False;
+ // OD 14.03.2003 #i11760#
+ mbFollowFormatAllowed = sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFrm::SwTxtFrm()
+ *************************************************************************/
+SwTxtFrm::SwTxtFrm(SwTxtNode * const pNode)
+ : SwCntntFrm(pNode)
+{
+ InitCtor();
+}
+
+/*************************************************************************
+ * SwTxtFrm::~SwTxtFrm()
+ *************************************************************************/
+SwTxtFrm::~SwTxtFrm()
+{
+ // Remove associated SwParaPortion from pTxtCache
+ ClearPara();
+}
+
+const XubString& SwTxtFrm::GetTxt() const
+{
+ return GetTxtNode()->GetTxt();
+}
+
+void SwTxtFrm::ResetPreps()
+{
+ if ( GetCacheIdx() != MSHRT_MAX )
+ {
+ SwParaPortion *pPara;
+ if( 0 != (pPara = GetPara()) )
+ pPara->ResetPreps();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::IsHiddenNow()
+ *************************************************************************/
+sal_Bool SwTxtFrm::IsHiddenNow() const
+{
+ SwFrmSwapper aSwapper( this, sal_True );
+
+ if( !Frm().Width() && IsValid() && GetUpper()->IsValid() )
+ //bei Stackueberlauf (StackHack) invalid!
+ {
+// ASSERT( false, "SwTxtFrm::IsHiddenNow: thin frame" );
+ return sal_True;
+ }
+
+ const bool bHiddenCharsHidePara = GetTxtNode()->HasHiddenCharAttribute( true );
+ const bool bHiddenParaField = GetTxtNode()->HasHiddenParaField();
+ const ViewShell* pVsh = GetShell();
+
+ if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) )
+ {
+ if (
+ ( bHiddenParaField &&
+ ( !pVsh->GetViewOptions()->IsShowHiddenPara() &&
+ !pVsh->GetViewOptions()->IsFldName() ) ) ||
+ ( bHiddenCharsHidePara &&
+ !pVsh->GetViewOptions()->IsShowHiddenChar() ) )
+ {
+ return sal_True;
+ }
+ }
+
+ return sal_False;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::HideHidden()
+ *************************************************************************/
+// Entfernt die Anhaengsel des Textfrms wenn dieser hidden ist
+
+void SwTxtFrm::HideHidden()
+{
+ ASSERT( !GetFollow() && IsHiddenNow(),
+ "HideHidden on visible frame of hidden frame has follow" );
+
+ const xub_StrLen nEnd = STRING_LEN;
+ HideFootnotes( GetOfst(), nEnd );
+ // OD 2004-01-15 #110582#
+ HideAndShowObjects();
+
+ //Die Formatinfos sind jetzt obsolete
+ ClearPara();
+}
+
+/*************************************************************************
+ * SwTxtFrm::HideFootnotes()
+ *************************************************************************/
+void SwTxtFrm::HideFootnotes( xub_StrLen nStart, xub_StrLen nEnd )
+{
+ const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( pHints )
+ {
+ const USHORT nSize = pHints->Count();
+ SwPageFrm *pPage = 0;
+ for ( USHORT i = 0; i < nSize; ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ if ( pHt->Which() == RES_TXTATR_FTN )
+ {
+ const xub_StrLen nIdx = *pHt->GetStart();
+ if ( nEnd < nIdx )
+ break;
+ if( nStart <= nIdx )
+ {
+ if( !pPage )
+ pPage = FindPageFrm();
+ pPage->RemoveFtn( this, (SwTxtFtn*)pHt );
+ }
+ }
+ }
+ }
+}
+
+// --> OD 2005-03-30 #120729# - hotfix: WW8 documents contain at its end hidden,
+// as-character anchored graphics, which are used for a graphic bullet list.
+// As long as these graphic bullet list aren't imported, do not hide a
+// at-character anchored object, if
+// (a) the document is an imported WW8 document -
+// checked by checking certain compatibility options -,
+// (b) the paragraph is the last content in the document and
+// (c) the anchor character is an as-character anchored graphic.
+bool lcl_HideObj( const SwTxtFrm& _rFrm,
+ const RndStdIds _eAnchorType,
+ const xub_StrLen _nObjAnchorPos,
+ SwAnchoredObject* _pAnchoredObj )
+{
+ bool bRet( true );
+
+ if (_eAnchorType == FLY_AT_CHAR)
+ {
+ const IDocumentSettingAccess* pIDSA = _rFrm.GetTxtNode()->getIDocumentSettingAccess();
+ if ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
+ !pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING) &&
+ !pIDSA->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) &&
+ pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
+ _rFrm.IsInDocBody() && !_rFrm.FindNextCnt() )
+ {
+ const xub_Unicode cAnchorChar =
+ _rFrm.GetTxtNode()->GetTxt().GetChar( _nObjAnchorPos );
+ if ( cAnchorChar == CH_TXTATR_BREAKWORD )
+ {
+ const SwTxtAttr* const pHint(
+ _rFrm.GetTxtNode()->GetTxtAttrForCharAt(_nObjAnchorPos,
+ RES_TXTATR_FLYCNT) );
+ if ( pHint )
+ {
+ const SwFrmFmt* pFrmFmt =
+ static_cast<const SwTxtFlyCnt*>(pHint)->GetFlyCnt().GetFrmFmt();
+ if ( pFrmFmt->Which() == RES_FLYFRMFMT )
+ {
+ SwNodeIndex nCntntIndex = *(pFrmFmt->GetCntnt().GetCntntIdx());
+ nCntntIndex++;
+ if ( nCntntIndex.GetNode().IsNoTxtNode() )
+ {
+ bRet = false;
+ // set needed data structure values for object positioning
+ SWRECTFN( (&_rFrm) );
+ SwRect aLastCharRect( _rFrm.Frm() );
+ (aLastCharRect.*fnRect->fnSetWidth)( 1 );
+ _pAnchoredObj->maLastCharRect = aLastCharRect;
+ _pAnchoredObj->mnLastTopOfLine = (aLastCharRect.*fnRect->fnGetTop)();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+// <--
+/*************************************************************************
+ * SwTxtFrm::HideAndShowObjects()
+ *************************************************************************/
+/** method to hide/show objects
+
+ OD 2004-01-15 #110582#
+ method hides respectively shows objects, which are anchored at paragraph,
+ at/as a character of the paragraph, corresponding to the paragraph and
+ paragraph portion visibility.
+
+ - is called from HideHidden() - should hide objects in hidden paragraphs and
+ - from _Format() - should hide/show objects in partly visible paragraphs
+
+ @author OD
+*/
+void SwTxtFrm::HideAndShowObjects()
+{
+ if ( GetDrawObjs() )
+ {
+ if ( IsHiddenNow() )
+ {
+ // complete paragraph is hidden. Thus, hide all objects
+ for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
+ {
+ SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
+ SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
+ // --> OD 2005-03-30 #120729# - hotfix: do not hide object
+ // under certain conditions
+ const RndStdIds eAnchorType( pContact->GetAnchorId() );
+ const xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
+ if ((eAnchorType != FLY_AT_CHAR) ||
+ lcl_HideObj( *this, eAnchorType, nObjAnchorPos,
+ (*GetDrawObjs())[i] ))
+ {
+ pContact->MoveObjToInvisibleLayer( pObj );
+ }
+ // <--
+ }
+ }
+ else
+ {
+ // paragraph is visible, but can contain hidden text portion.
+ // first we check if objects are allowed to be hidden:
+ const SwTxtNode& rNode = *GetTxtNode();
+ const ViewShell* pVsh = GetShell();
+ const bool bShouldBeHidden = !pVsh || !pVsh->GetWin() ||
+ !pVsh->GetViewOptions()->IsShowHiddenChar();
+
+ // Thus, show all objects, which are anchored at paragraph and
+ // hide/show objects, which are anchored at/as character, according
+ // to the visibility of the anchor character.
+ for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
+ {
+ SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
+ SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
+ // --> OD 2005-03-30 #120729# - determine anchor type only once
+ const RndStdIds eAnchorType( pContact->GetAnchorId() );
+ // <--
+
+ if (eAnchorType == FLY_AT_PARA)
+ {
+ pContact->MoveObjToVisibleLayer( pObj );
+ }
+ else if ((eAnchorType == FLY_AT_CHAR) ||
+ (eAnchorType == FLY_AS_CHAR))
+ {
+ xub_StrLen nHiddenStart;
+ xub_StrLen nHiddenEnd;
+ xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
+ SwScriptInfo::GetBoundsOfHiddenRange( rNode, nObjAnchorPos, nHiddenStart, nHiddenEnd, 0 );
+ // --> OD 2005-03-30 #120729# - hotfix: do not hide object
+ // under certain conditions
+ if ( nHiddenStart != STRING_LEN && bShouldBeHidden &&
+ lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) )
+ // <--
+ pContact->MoveObjToInvisibleLayer( pObj );
+ else
+ pContact->MoveObjToVisibleLayer( pObj );
+ }
+ else
+ {
+ ASSERT( false,
+ "<SwTxtFrm::HideAndShowObjects()> - object not anchored at/inside paragraph!?" );
+ }
+ }
+ }
+ }
+
+ if ( IsFollow() )
+ {
+ FindMaster()->HideAndShowObjects();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindBrk()
+ *
+ * Liefert die erste Trennmoeglichkeit in der aktuellen Zeile zurueck.
+ * Die Methode wird in SwTxtFrm::Format() benutzt, um festzustellen, ob
+ * die Vorgaengerzeile mitformatiert werden muss.
+ * nFound ist <= nEndLine.
+ *************************************************************************/
+
+xub_StrLen SwTxtFrm::FindBrk( const XubString &rTxt,
+ const xub_StrLen nStart,
+ const xub_StrLen nEnd ) const
+{
+ // --> OD 2009-12-28 #i104291# - applying patch to avoid overflow.
+ unsigned long nFound = nStart;
+ const xub_StrLen nEndLine = Min( nEnd, rTxt.Len() );
+
+ // Wir ueberlesen erst alle Blanks am Anfang der Zeile (vgl. Bug 2235).
+ while( nFound <= nEndLine &&
+ ' ' == rTxt.GetChar( static_cast<xub_StrLen>(nFound) ) )
+ {
+ nFound++;
+ }
+
+ // Eine knifflige Sache mit den TxtAttr-Dummy-Zeichen (hier "$"):
+ // "Dr.$Meyer" am Anfang der zweiten Zeile. Dahinter ein Blank eingegeben
+ // und das Wort rutscht nicht in die erste Zeile, obwohl es ginge.
+ // Aus diesem Grund nehmen wir das Dummy-Zeichen noch mit.
+ while( nFound <= nEndLine &&
+ ' ' != rTxt.GetChar( static_cast<xub_StrLen>(nFound) ) )
+ {
+ nFound++;
+ }
+
+ return nFound <= STRING_LEN
+ ? static_cast<xub_StrLen>(nFound)
+ : STRING_LEN;
+ // <--
+}
+
+/*************************************************************************
+ * SwTxtFrm::IsIdxInside()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::IsIdxInside( const xub_StrLen nPos, const xub_StrLen nLen ) const
+{
+ if( GetOfst() > nPos + nLen ) // d.h., der Bereich liegt komplett vor uns.
+ return sal_False;
+
+ if( !GetFollow() ) // der Bereich liegt nicht komplett vor uns,
+ return sal_True; // nach uns kommt niemand mehr.
+
+ const xub_StrLen nMax = GetFollow()->GetOfst();
+
+ // der Bereich liegt nicht komplett hinter uns bzw.
+ // unser Text ist geloescht worden.
+ if( nMax > nPos || nMax > GetTxt().Len() )
+ return sal_True;
+
+ // changes made in the first line of a follow can modify the master
+ const SwParaPortion* pPara = GetFollow()->GetPara();
+ return pPara && ( nPos <= nMax + pPara->GetLen() );
+}
+
+/*************************************************************************
+ * SwTxtFrm::InvalidateRange()
+ *************************************************************************/
+inline void SwTxtFrm::InvalidateRange(const SwCharRange &aRange, const long nD)
+{
+ if ( IsIdxInside( aRange.Start(), aRange.Len() ) )
+ _InvalidateRange( aRange, nD );
+}
+
+/*************************************************************************
+ * SwTxtFrm::_InvalidateRange()
+ *************************************************************************/
+
+void SwTxtFrm::_InvalidateRange( const SwCharRange &aRange, const long nD)
+{
+ if ( !HasPara() )
+ { InvalidateSize();
+ return;
+ }
+
+ SetWidow( sal_False );
+ SwParaPortion *pPara = GetPara();
+
+ sal_Bool bInv = sal_False;
+ if( 0 != nD )
+ {
+ //Auf nDelta werden die Differenzen zwischen alter und
+ //neuer Zeilenlaenge aufaddiert, deshalb ist es negativ,
+ //wenn Zeichen eingefuegt wurden, positiv, wenn Zeichen
+ //geloescht wurden.
+ *(pPara->GetDelta()) += nD;
+ bInv = sal_True;
+ }
+ SwCharRange &rReformat = *(pPara->GetReformat());
+ if(aRange != rReformat) {
+ if( STRING_LEN == rReformat.Len() )
+ rReformat = aRange;
+ else
+ rReformat += aRange;
+ bInv = sal_True;
+ }
+ if(bInv)
+ {
+// 90365: nD is passed to a follow two times
+// if( GetFollow() )
+// ((SwTxtFrm*)GetFollow())->InvalidateRange( aRange, nD );
+ InvalidateSize();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcLineSpace()
+ *************************************************************************/
+
+void SwTxtFrm::CalcLineSpace()
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::CalcLineSpace with swapped frame!" )
+
+ if( IsLocked() || !HasPara() )
+ return;
+
+ SwParaPortion *pPara;
+ if( GetDrawObjs() ||
+ GetTxtNode()->GetSwAttrSet().GetLRSpace().IsAutoFirst() ||
+ ( pPara = GetPara() )->IsFixLineHeight() )
+ {
+ Init();
+ return;
+ }
+
+ Size aNewSize( Prt().SSize() );
+
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+ if( aLine.GetDropLines() )
+ {
+ Init();
+ return;
+ }
+
+ aLine.Top();
+ aLine.RecalcRealHeight();
+
+ aNewSize.Height() = (aLine.Y() - Frm().Top()) + aLine.GetLineHeight();
+
+ SwTwips nDelta = aNewSize.Height() - Prt().Height();
+ // 4291: Unterlauf bei Flys
+ if( aInf.GetTxtFly()->IsOn() )
+ {
+ SwRect aTmpFrm( Frm() );
+ if( nDelta < 0 )
+ aTmpFrm.Height( Prt().Height() );
+ else
+ aTmpFrm.Height( aNewSize.Height() );
+ if( aInf.GetTxtFly()->Relax( aTmpFrm ) )
+ {
+ Init();
+ return;
+ }
+ }
+
+ if( nDelta )
+ {
+ SwTxtFrmBreak aBreak( this );
+ if( GetFollow() || aBreak.IsBreakNow( aLine ) )
+ {
+ // Wenn es einen Follow() gibt, oder wenn wir an dieser
+ // Stelle aufbrechen muessen, so wird neu formatiert.
+ Init();
+ }
+ else
+ {
+ // Alles nimmt seinen gewohnten Gang ...
+ pPara->SetPrepAdjust();
+ pPara->SetPrep();
+ }
+ }
+}
+
+//
+// SET_WRONG( nPos, nCnt, bMove )
+//
+#define SET_WRONG( nPos, nCnt, bMove ) \
+{ \
+ lcl_SetWrong( *this, nPos, nCnt, bMove ); \
+}
+
+void lcl_SetWrong( SwTxtFrm& rFrm, xub_StrLen nPos, long nCnt, bool bMove )
+{
+ if ( !rFrm.IsFollow() )
+ {
+ SwTxtNode* pTxtNode = rFrm.GetTxtNode();
+ IGrammarContact* pGrammarContact = getGrammarContact( *pTxtNode );
+ SwGrammarMarkUp* pWrongGrammar = pGrammarContact ?
+ pGrammarContact->getGrammarCheck( *pTxtNode, false ) :
+ pTxtNode->GetGrammarCheck();
+ bool bGrammarProxy = pWrongGrammar != pTxtNode->GetGrammarCheck();
+ if( bMove )
+ {
+ if( pTxtNode->GetWrong() )
+ pTxtNode->GetWrong()->Move( nPos, nCnt );
+ if( pWrongGrammar )
+ pWrongGrammar->MoveGrammar( nPos, nCnt );
+ if( bGrammarProxy && pTxtNode->GetGrammarCheck() )
+ pTxtNode->GetGrammarCheck()->MoveGrammar( nPos, nCnt );
+ if( pTxtNode->GetSmartTags() )
+ pTxtNode->GetSmartTags()->Move( nPos, nCnt );
+ }
+ else
+ {
+ xub_StrLen nLen = (xub_StrLen)nCnt;
+ if( pTxtNode->GetWrong() )
+ pTxtNode->GetWrong()->Invalidate( nPos, nLen );
+ if( pWrongGrammar )
+ pWrongGrammar->Invalidate( nPos, nLen );
+ if( pTxtNode->GetSmartTags() )
+ pTxtNode->GetSmartTags()->Invalidate( nPos, nLen );
+ }
+ if ( !pTxtNode->GetWrong() && !pTxtNode->IsWrongDirty() )
+ {
+ pTxtNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
+ pTxtNode->GetWrong()->SetInvalid( nPos, nPos + (USHORT)( nCnt > 0 ? nCnt : 1 ) );
+ }
+ if ( !pTxtNode->GetSmartTags() && !pTxtNode->IsSmartTagDirty() )
+ {
+ // SMARTTAGS
+ pTxtNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) );
+ pTxtNode->GetSmartTags()->SetInvalid( nPos, nPos + (USHORT)( nCnt > 0 ? nCnt : 1 ) );
+ }
+ pTxtNode->SetWrongDirty( true );
+ pTxtNode->SetGrammarCheckDirty( true );
+ pTxtNode->SetWordCountDirty( true );
+ pTxtNode->SetAutoCompleteWordDirty( true );
+ // SMARTTAGS
+ pTxtNode->SetSmartTagDirty( true );
+ }
+
+ SwRootFrm *pRootFrm = rFrm.FindRootFrm();
+ if (pRootFrm)
+ {
+ pRootFrm->SetNeedGrammarCheck( TRUE );
+ }
+
+ SwPageFrm *pPage = rFrm.FindPageFrm();
+ if( pPage )
+ {
+ pPage->InvalidateSpelling();
+ pPage->InvalidateAutoCompleteWords();
+ pPage->InvalidateWordCount();
+ pPage->InvalidateSmartTags();
+ }
+}
+
+//
+// SET_SCRIPT_INVAL( nPos )
+//
+
+#define SET_SCRIPT_INVAL( nPos )\
+ lcl_SetScriptInval( *this, nPos );
+
+void lcl_SetScriptInval( SwTxtFrm& rFrm, xub_StrLen nPos )
+{
+ if( rFrm.GetPara() )
+ rFrm.GetPara()->GetScriptInfo().SetInvalidity( nPos );
+}
+
+void lcl_ModifyOfst( SwTxtFrm* pFrm, xub_StrLen nPos, xub_StrLen nLen )
+{
+ while( pFrm && pFrm->GetOfst() <= nPos )
+ pFrm = pFrm->GetFollow();
+ while( pFrm )
+ {
+ pFrm->ManipOfst( pFrm->GetOfst() + nLen );
+ pFrm = pFrm->GetFollow();
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::Modify()
+ *************************************************************************/
+
+void SwTxtFrm::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew )
+{
+ const MSHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
+
+ //Wuensche die FrmAttribute betreffen werden von der Basisklasse
+ //verarbeitet.
+ if( IsInRange( aFrmFmtSetRange, nWhich ) || RES_FMT_CHG == nWhich )
+ {
+ SwCntntFrm::Modify( pOld, pNew );
+ if( nWhich == RES_FMT_CHG && GetShell() )
+ {
+ // Collection hat sich geaendert
+ Prepare( PREP_CLEAR );
+ _InvalidatePrt();
+ SET_WRONG( 0, STRING_LEN, false );
+ SetDerivedR2L( sal_False );
+ CheckDirChange();
+ // OD 09.12.2002 #105576# - Force complete paint due to existing
+ // indents.
+ SetCompletePaint();
+ InvalidateLineNum();
+ }
+ return;
+ }
+
+ // Im gelockten Zustand werden keine Bestellungen angenommen.
+ if( IsLocked() )
+ return;
+
+ // Dies spart Stack, man muss nur aufpassen,
+ // dass sie Variablen gesetzt werden.
+ xub_StrLen nPos, nLen;
+ sal_Bool bSetFldsDirty = sal_False;
+ sal_Bool bRecalcFtnFlag = sal_False;
+
+ switch( nWhich )
+ {
+ case RES_LINENUMBER:
+ {
+ InvalidateLineNum();
+ }
+ break;
+ case RES_INS_TXT:
+ {
+ nPos = ((SwInsTxt*)pNew)->nPos;
+ nLen = ((SwInsTxt*)pNew)->nLen;
+ if( IsIdxInside( nPos, nLen ) )
+ {
+ if( !nLen )
+ {
+ // 6969: Aktualisierung der NumPortions auch bei leeren Zeilen!
+ if( nPos )
+ InvalidateSize();
+ else
+ Prepare( PREP_CLEAR );
+ }
+ else
+ _InvalidateRange( SwCharRange( nPos, nLen ), nLen );
+ }
+ SET_WRONG( nPos, nLen, true )
+ SET_SCRIPT_INVAL( nPos )
+ bSetFldsDirty = sal_True;
+ if( HasFollow() )
+ lcl_ModifyOfst( this, nPos, nLen );
+ }
+ break;
+ case RES_DEL_CHR:
+ {
+ nPos = ((SwDelChr*)pNew)->nPos;
+ InvalidateRange( SwCharRange( nPos, 1 ), -1 );
+ SET_WRONG( nPos, -1, true )
+ SET_SCRIPT_INVAL( nPos )
+ bSetFldsDirty = bRecalcFtnFlag = sal_True;
+ if( HasFollow() )
+ lcl_ModifyOfst( this, nPos, STRING_LEN );
+ }
+ break;
+ case RES_DEL_TXT:
+ {
+ nPos = ((SwDelTxt*)pNew)->nStart;
+ nLen = ((SwDelTxt*)pNew)->nLen;
+ long m = nLen;
+ m *= -1;
+ if( IsIdxInside( nPos, nLen ) )
+ {
+ if( !nLen )
+ InvalidateSize();
+ else
+ InvalidateRange( SwCharRange( nPos, 1 ), m );
+ }
+ SET_WRONG( nPos, m, true )
+ SET_SCRIPT_INVAL( nPos )
+ bSetFldsDirty = bRecalcFtnFlag = sal_True;
+ if( HasFollow() )
+ lcl_ModifyOfst( this, nPos, nLen );
+ }
+ break;
+ case RES_UPDATE_ATTR:
+ {
+ nPos = ((SwUpdateAttr*)pNew)->nStart;
+ nLen = ((SwUpdateAttr*)pNew)->nEnd - nPos;
+ if( IsIdxInside( nPos, nLen ) )
+ {
+ // Es muss in jedem Fall neu formatiert werden,
+ // auch wenn der invalidierte Bereich null ist.
+ // Beispiel: leere Zeile, 14Pt einstellen !
+ // if( !nLen ) nLen = 1;
+
+ // 6680: FtnNummern muessen formatiert werden.
+ if( !nLen )
+ nLen = 1;
+
+ _InvalidateRange( SwCharRange( nPos, nLen) );
+ MSHORT nTmp = ((SwUpdateAttr*)pNew)->nWhichAttr;
+
+ if( ! nTmp || RES_TXTATR_CHARFMT == nTmp || RES_TXTATR_AUTOFMT == nTmp ||
+ RES_FMT_CHG == nTmp || RES_ATTRSET_CHG == nTmp )
+ {
+ SET_WRONG( nPos, nPos + nLen, false )
+ SET_SCRIPT_INVAL( nPos )
+ }
+ }
+
+ // --> OD 2010-02-16 #i104008#
+ if ( GetShell() )
+ {
+ GetShell()->InvalidateAccessibleParaAttrs( *this );
+ }
+ // <--
+ }
+ break;
+ case RES_OBJECTDYING:
+ break;
+
+ case RES_PARATR_LINESPACING:
+ {
+ CalcLineSpace();
+ InvalidateSize();
+ _InvalidatePrt();
+ if( IsInSct() && !GetPrev() )
+ {
+ SwSectionFrm *pSect = FindSctFrm();
+ if( pSect->ContainsAny() == this )
+ pSect->InvalidatePrt();
+ }
+
+ // OD 09.01.2004 #i11859# - correction:
+ // (1) Also invalidate next frame on next page/column.
+ // (2) Skip empty sections and hidden paragraphs
+ // Thus, use method <InvalidateNextPrtArea()>
+ InvalidateNextPrtArea();
+
+ SetCompletePaint();
+ }
+ break;
+ case RES_TXTATR_FIELD:
+ {
+ nPos = *((SwFmtFld*)pNew)->GetTxtFld()->GetStart();
+ if( IsIdxInside( nPos, 1 ) )
+ {
+ if( pNew == pOld )
+ {
+ // Nur repainten
+ // opt: invalidate aufs Window ?
+ InvalidatePage();
+ SetCompletePaint();
+ }
+ else
+ _InvalidateRange( SwCharRange( nPos, 1 ) );
+ }
+ bSetFldsDirty = sal_True;
+ // ST2
+ if ( SwSmartTagMgr::Get().IsSmartTagsEnabled() )
+ SET_WRONG( nPos, nPos + 1, false )
+ }
+ break;
+ case RES_TXTATR_FTN :
+ {
+ nPos = *((SwFmtFtn*)pNew)->GetTxtFtn()->GetStart();
+ if( IsInFtn() || IsIdxInside( nPos, 1 ) )
+ Prepare( PREP_FTN, ((SwFmtFtn*)pNew)->GetTxtFtn() );
+ break;
+ }
+
+ case RES_ATTRSET_CHG:
+ {
+ InvalidateLineNum();
+
+ SwAttrSet& rNewSet = *((SwAttrSetChg*)pNew)->GetChgSet();
+ const SfxPoolItem* pItem;
+ int nClear = 0;
+ MSHORT nCount = rNewSet.Count();
+
+ if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FTN,
+ sal_False, &pItem ))
+ {
+ nPos = *((SwFmtFtn*)pItem)->GetTxtFtn()->GetStart();
+ if( IsIdxInside( nPos, 1 ) )
+ Prepare( PREP_FTN, pNew );
+ nClear = 0x01;
+ --nCount;
+ }
+
+ if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FIELD,
+ sal_False, &pItem ))
+ {
+ nPos = *((SwFmtFld*)pItem)->GetTxtFld()->GetStart();
+ if( IsIdxInside( nPos, 1 ) )
+ {
+ const SfxPoolItem& rOldItem = ((SwAttrSetChg*)pOld)->
+ GetChgSet()->Get( RES_TXTATR_FIELD );
+ if( pItem == &rOldItem )
+ {
+ // Nur repainten
+ // opt: invalidate aufs Window ?
+ InvalidatePage();
+ SetCompletePaint();
+ }
+ else
+ _InvalidateRange( SwCharRange( nPos, 1 ) );
+ }
+ nClear |= 0x02;
+ --nCount;
+ }
+ sal_Bool bLineSpace = SFX_ITEM_SET == rNewSet.GetItemState(
+ RES_PARATR_LINESPACING, sal_False ),
+ bRegister = SFX_ITEM_SET == rNewSet.GetItemState(
+ RES_PARATR_REGISTER, sal_False );
+ if ( bLineSpace || bRegister )
+ {
+ Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
+ CalcLineSpace();
+ InvalidateSize();
+ _InvalidatePrt();
+
+ // OD 09.01.2004 #i11859# - correction:
+ // (1) Also invalidate next frame on next page/column.
+ // (2) Skip empty sections and hidden paragraphs
+ // Thus, use method <InvalidateNextPrtArea()>
+ InvalidateNextPrtArea();
+
+ SetCompletePaint();
+ nClear |= 0x04;
+ if ( bLineSpace )
+ {
+ --nCount;
+ if( IsInSct() && !GetPrev() )
+ {
+ SwSectionFrm *pSect = FindSctFrm();
+ if( pSect->ContainsAny() == this )
+ pSect->InvalidatePrt();
+ }
+ }
+ if ( bRegister )
+ --nCount;
+ }
+ if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_SPLIT,
+ sal_False ))
+ {
+ if ( GetPrev() )
+ CheckKeep();
+ Prepare( PREP_CLEAR );
+ InvalidateSize();
+ nClear |= 0x08;
+ --nCount;
+ }
+
+ if( SFX_ITEM_SET == rNewSet.GetItemState( RES_BACKGROUND, sal_False)
+ && !IsFollow() && GetDrawObjs() )
+ {
+ SwSortedObjs *pObjs = GetDrawObjs();
+ for ( int i = 0; GetDrawObjs() && i < int(pObjs->Count()); ++i )
+ {
+ SwAnchoredObject* pAnchoredObj = (*pObjs)[MSHORT(i)];
+ if ( pAnchoredObj->ISA(SwFlyFrm) )
+ {
+ SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
+ if( !pFly->IsFlyInCntFrm() )
+ {
+ const SvxBrushItem &rBack =
+ pFly->GetAttrSet()->GetBackground();
+ // OD 20.08.2002 #99657# #GetTransChg#
+ // following condition determines, if the fly frame
+ // "inherites" the background color of text frame.
+ // This is the case, if fly frame background
+ // color is "no fill"/"auto fill" and if the fly frame
+ // has no background graphic.
+ // Thus, check complete fly frame background
+ // color and *not* only its transparency value
+ if ( (rBack.GetColor() == COL_TRANSPARENT) &&
+ //if( rBack.GetColor().GetTransparency() &&
+ rBack.GetGraphicPos() == GPOS_NONE )
+ {
+ pFly->SetCompletePaint();
+ pFly->InvalidatePage();
+ }
+ }
+ }
+ }
+ }
+
+ if ( SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_TXTATR_CHARFMT, sal_False ) )
+ {
+ SET_WRONG( 0, STRING_LEN, false )
+ SET_SCRIPT_INVAL( 0 )
+ }
+ else if ( SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_CHRATR_LANGUAGE, sal_False ) ||
+ SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_CHRATR_CJK_LANGUAGE, sal_False ) ||
+ SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_CHRATR_CTL_LANGUAGE, sal_False ) )
+ SET_WRONG( 0, STRING_LEN, false )
+ else if ( SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_CHRATR_FONT, sal_False ) ||
+ SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_CHRATR_CJK_FONT, sal_False ) ||
+ SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_CHRATR_CTL_FONT, sal_False ) )
+ SET_SCRIPT_INVAL( 0 )
+ else if ( SFX_ITEM_SET ==
+ rNewSet.GetItemState( RES_FRAMEDIR, sal_False ) )
+ {
+ SetDerivedR2L( sal_False );
+ CheckDirChange();
+ // OD 09.12.2002 #105576# - Force complete paint due to existing
+ // indents.
+ SetCompletePaint();
+ }
+
+
+ if( nCount )
+ {
+ if( GetShell() )
+ {
+ Prepare( PREP_CLEAR );
+ _InvalidatePrt();
+ }
+
+ if( nClear )
+ {
+ SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
+ SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
+
+ if( 0x01 & nClear )
+ {
+ aOldSet.ClearItem( RES_TXTATR_FTN );
+ aNewSet.ClearItem( RES_TXTATR_FTN );
+ }
+ if( 0x02 & nClear )
+ {
+ aOldSet.ClearItem( RES_TXTATR_FIELD );
+ aNewSet.ClearItem( RES_TXTATR_FIELD );
+ }
+ if ( 0x04 & nClear )
+ {
+ if ( bLineSpace )
+ {
+ aOldSet.ClearItem( RES_PARATR_LINESPACING );
+ aNewSet.ClearItem( RES_PARATR_LINESPACING );
+ }
+ if ( bRegister )
+ {
+ aOldSet.ClearItem( RES_PARATR_REGISTER );
+ aNewSet.ClearItem( RES_PARATR_REGISTER );
+ }
+ }
+ if ( 0x08 & nClear )
+ {
+ aOldSet.ClearItem( RES_PARATR_SPLIT );
+ aNewSet.ClearItem( RES_PARATR_SPLIT );
+ }
+ SwCntntFrm::Modify( &aOldSet, &aNewSet );
+ }
+ else
+ SwCntntFrm::Modify( pOld, pNew );
+ }
+
+ // --> OD 2009-01-06 #i88069#
+ if ( GetShell() )
+ {
+ GetShell()->InvalidateAccessibleParaAttrs( *this );
+ }
+ // <--
+ }
+ break;
+
+/* Seit dem neuen Blocksatz muessen wir immer neu formatieren:
+ case RES_PARATR_ADJUST:
+ {
+ if( GetShell() )
+ {
+ Prepare( PREP_CLEAR );
+ }
+ break;
+ }
+*/
+ // 6870: SwDocPosUpdate auswerten.
+ case RES_DOCPOS_UPDATE:
+ {
+ if( pOld && pNew )
+ {
+ const SwDocPosUpdate *pDocPos = (const SwDocPosUpdate*)pOld;
+ if( pDocPos->nDocPos <= aFrm.Top() )
+ {
+ const SwFmtFld *pFld = (const SwFmtFld *)pNew;
+ InvalidateRange(
+ SwCharRange( *pFld->GetTxtFld()->GetStart(), 1 ) );
+ }
+ }
+ break;
+ }
+ case RES_PARATR_SPLIT:
+ if ( GetPrev() )
+ CheckKeep();
+ Prepare( PREP_CLEAR );
+ bSetFldsDirty = sal_True;
+ break;
+ case RES_FRAMEDIR :
+ SetDerivedR2L( sal_False );
+ CheckDirChange();
+ break;
+ default:
+ {
+ Prepare( PREP_CLEAR );
+ _InvalidatePrt();
+ if ( !nWhich )
+ {
+ //Wird z.B. bei HiddenPara mit 0 gerufen.
+ SwFrm *pNxt;
+ if ( 0 != (pNxt = FindNext()) )
+ pNxt->InvalidatePrt();
+ }
+ }
+ } // switch
+
+ if( bSetFldsDirty )
+ GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( sal_True, GetNode(), 1 );
+
+ if ( bRecalcFtnFlag )
+ CalcFtnFlag();
+}
+
+sal_Bool SwTxtFrm::GetInfo( SfxPoolItem &rHnt ) const
+{
+ if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && ! IsFollow() )
+ {
+ SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
+ const SwPageFrm *pPage = FindPageFrm();
+ if ( pPage )
+ {
+ if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
+ {
+ //Das sollte er sein (kann allenfalls temporaer anders sein,
+ // sollte uns das beunruhigen?)
+ rInfo.SetInfo( pPage, this );
+ return sal_False;
+ }
+ if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
+ (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
+ {
+ //Das koennte er sein.
+ rInfo.SetInfo( pPage, this );
+ }
+ }
+ }
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFrm::PrepWidows()
+ *************************************************************************/
+
+void SwTxtFrm::PrepWidows( const MSHORT nNeed, sal_Bool bNotify )
+{
+ ASSERT(GetFollow() && nNeed, "+SwTxtFrm::Prepare: lost all friends");
+
+ SwParaPortion *pPara = GetPara();
+ if ( !pPara )
+ return;
+ pPara->SetPrepWidows( sal_True );
+
+ // These two lines of code have been deleted for #102340#.
+ // Obviously the widow control does not work if we have a
+ // pMaster->pFollow->pFollow situation:
+
+ // returnen oder nicht ist hier die Frage.
+ // Ohne IsLocked() ist 5156 gefaehrlich,
+ // ohne IsFollow() werden die Orphans unterdrueckt: 6968.
+ // Abfrage auf IsLocked erst hier, weil das Flag gesetzt werden soll.
+// if( IsLocked() && IsFollow() )
+// return;
+
+ MSHORT nHave = nNeed;
+
+ // Wir geben ein paar Zeilen ab und schrumpfen im CalcPreps()
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwTxtSizeInfo aInf( this );
+ SwTxtMargin aLine( this, &aInf );
+ aLine.Bottom();
+ xub_StrLen nTmpLen = aLine.GetCurr()->GetLen();
+ while( nHave && aLine.PrevLine() )
+ {
+ if( nTmpLen )
+ --nHave;
+ nTmpLen = aLine.GetCurr()->GetLen();
+ }
+ // In dieser Ecke tummelten sich einige Bugs: 7513, 7606.
+ // Wenn feststeht, dass Zeilen abgegeben werden koennen,
+ // muss der Master darueber hinaus die Widow-Regel ueberpruefen.
+ if( !nHave )
+ {
+ sal_Bool bSplit;
+ if( !IsFollow() ) //Nur ein Master entscheidet ueber Orphans
+ {
+ const WidowsAndOrphans aWidOrp( this );
+ bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() &&
+ aLine.GetLineNr() >= aLine.GetDropLines() );
+ }
+ else
+ bSplit = sal_True;
+
+ if( bSplit )
+ {
+ GetFollow()->SetOfst( aLine.GetEnd() );
+ aLine.TruncLines( sal_True );
+ if( pPara->IsFollowField() )
+ GetFollow()->SetFieldFollow( sal_True );
+ }
+ }
+ if ( bNotify )
+ {
+ _InvalidateSize();
+ InvalidatePage();
+ }
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::Prepare
+ *************************************************************************/
+
+sal_Bool lcl_ErgoVadis( SwTxtFrm* pFrm, xub_StrLen &rPos, const PrepareHint ePrep )
+{
+ const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
+ if( ePrep == PREP_ERGOSUM )
+ {
+ if( !rFtnInfo.aErgoSum.Len() )
+ return sal_False;;
+ rPos = pFrm->GetOfst();
+ }
+ else
+ {
+ if( !rFtnInfo.aQuoVadis.Len() )
+ return sal_False;
+ if( pFrm->HasFollow() )
+ rPos = pFrm->GetFollow()->GetOfst();
+ else
+ rPos = pFrm->GetTxt().Len();
+ if( rPos )
+ --rPos; // unser letztes Zeichen
+ }
+ return sal_True;
+}
+
+void SwTxtFrm::Prepare( const PrepareHint ePrep, const void* pVoid,
+ sal_Bool bNotify )
+{
+ SwFrmSwapper aSwapper( this, sal_False );
+
+#if OSL_DEBUG_LEVEL > 1
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+#endif
+
+ if ( IsEmpty() )
+ {
+ switch ( ePrep )
+ {
+ case PREP_BOSS_CHGD:
+ SetInvalidVert( TRUE ); // Test
+ case PREP_WIDOWS_ORPHANS:
+ case PREP_WIDOWS:
+ case PREP_FTN_GONE : return;
+
+ case PREP_POS_CHGD :
+ {
+ // Auch in (spaltigen) Bereichen ist ein InvalidateSize notwendig,
+ // damit formatiert wird und ggf. das bUndersized gesetzt wird.
+ if( IsInFly() || IsInSct() )
+ {
+ SwTwips nTmpBottom = GetUpper()->Frm().Top() +
+ GetUpper()->Prt().Bottom();
+ if( nTmpBottom < Frm().Bottom() )
+ break;
+ }
+ // Gibt es ueberhaupt Flys auf der Seite ?
+ SwTxtFly aTxtFly( this );
+ if( aTxtFly.IsOn() )
+ {
+ // Ueberlappt irgendein Fly ?
+ aTxtFly.Relax();
+ if ( aTxtFly.IsOn() || IsUndersized() )
+ break;
+ }
+ if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue())
+ break;
+
+ GETGRID( FindPageFrm() )
+ if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
+ break;
+
+ // --> OD 2004-07-16 #i28701# - consider anchored objects
+ if ( GetDrawObjs() )
+ break;
+ // <--
+
+ return;
+ }
+ default:
+ break;
+ }
+ }
+
+ if( !HasPara() && PREP_MUST_FIT != ePrep )
+ {
+ SetInvalidVert( TRUE ); // Test
+ ASSERT( !IsLocked(), "SwTxtFrm::Prepare: three of a perfect pair" );
+ if ( bNotify )
+ InvalidateSize();
+ else
+ _InvalidateSize();
+ return;
+ }
+
+ //Objekt mit Locking aus dem Cache holen.
+ SwTxtLineAccess aAccess( this );
+ SwParaPortion *pPara = aAccess.GetPara();
+
+ switch( ePrep )
+ {
+ case PREP_MOVEFTN : Frm().Height(0);
+ Prt().Height(0);
+ _InvalidatePrt();
+ _InvalidateSize();
+ // KEIN break
+ case PREP_ADJUST_FRM : pPara->SetPrepAdjust( sal_True );
+ if( IsFtnNumFrm() != pPara->IsFtnNum() ||
+ IsUndersized() )
+ {
+ InvalidateRange( SwCharRange( 0, 1 ), 1);
+ if( GetOfst() && !IsFollow() )
+ _SetOfst( 0 );
+ }
+ break;
+ case PREP_MUST_FIT : pPara->SetPrepMustFit( sal_True );
+ /* no break here */
+ case PREP_WIDOWS_ORPHANS : pPara->SetPrepAdjust( sal_True );
+ break;
+
+ case PREP_WIDOWS :
+ // MustFit ist staerker als alles anderes
+ if( pPara->IsPrepMustFit() )
+ return;
+ // Siehe Kommentar in WidowsAndOrphans::FindOrphans und CalcPreps()
+ PrepWidows( *(const MSHORT *)pVoid, bNotify );
+ break;
+
+ case PREP_FTN :
+ {
+ SwTxtFtn *pFtn = (SwTxtFtn *)pVoid;
+ if( IsInFtn() )
+ {
+ // Bin ich der erste TxtFrm einer Fussnote ?
+ if( !GetPrev() )
+ // Wir sind also ein TxtFrm der Fussnote, die
+ // die Fussnotenzahl zur Anzeige bringen muss.
+ // Oder den ErgoSum-Text...
+ InvalidateRange( SwCharRange( 0, 1 ), 1);
+
+ if( !GetNext() )
+ {
+ // Wir sind der letzte Ftn, jetzt muessten die
+ // QuoVadis-Texte geupdated werden.
+ const SwFtnInfo &rFtnInfo = GetNode()->GetDoc()->GetFtnInfo();
+ if( !pPara->UpdateQuoVadis( rFtnInfo.aQuoVadis ) )
+ {
+ xub_StrLen nPos = pPara->GetParLen();
+ if( nPos )
+ --nPos;
+ InvalidateRange( SwCharRange( nPos, 1 ), 1);
+ }
+ }
+ }
+ else
+ {
+ // Wir sind also der TxtFrm _mit_ der Fussnote
+ const xub_StrLen nPos = *pFtn->GetStart();
+ InvalidateRange( SwCharRange( nPos, 1 ), 1);
+ }
+ break;
+ }
+ case PREP_BOSS_CHGD :
+ {
+ // Test
+ {
+ SetInvalidVert( FALSE );
+ BOOL bOld = IsVertical();
+ SetInvalidVert( TRUE );
+ if( bOld != IsVertical() )
+ InvalidateRange( SwCharRange( GetOfst(), STRING_LEN ) );
+ }
+
+ if( HasFollow() )
+ {
+ xub_StrLen nNxtOfst = GetFollow()->GetOfst();
+ if( nNxtOfst )
+ --nNxtOfst;
+ InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1);
+ }
+ if( IsInFtn() )
+ {
+ xub_StrLen nPos;
+ if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) )
+ InvalidateRange( SwCharRange( nPos, 1 ), 0 );
+ if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) )
+ InvalidateRange( SwCharRange( nPos, 1 ), 0 );
+ }
+ // 4739: Wenn wir ein Seitennummernfeld besitzen, muessen wir
+ // die Stellen invalidieren.
+ SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( pHints )
+ {
+ const USHORT nSize = pHints->Count();
+ const xub_StrLen nEnd = GetFollow() ?
+ GetFollow()->GetOfst() : STRING_LEN;
+ for ( USHORT i = 0; i < nSize; ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ const xub_StrLen nStart = *pHt->GetStart();
+ if( nStart >= GetOfst() )
+ {
+ if( nStart >= nEnd )
+ i = nSize; // fuehrt das Ende herbei
+ else
+ {
+ // 4029: wenn wir zurueckfliessen und eine Ftn besitzen, so
+ // fliesst die Ftn in jedem Fall auch mit. Damit sie nicht im
+ // Weg steht, schicken wir uns ein ADJUST_FRM.
+ // pVoid != 0 bedeutet MoveBwd()
+ const MSHORT nWhich = pHt->Which();
+ if( RES_TXTATR_FIELD == nWhich ||
+ (HasFtn() && pVoid && RES_TXTATR_FTN == nWhich))
+ InvalidateRange( SwCharRange( nStart, 1 ), 1 );
+ }
+ }
+ }
+ }
+ // A new boss, a new chance for growing
+ if( IsUndersized() )
+ {
+ _InvalidateSize();
+ InvalidateRange( SwCharRange( GetOfst(), 1 ), 1);
+ }
+ break;
+ }
+
+ case PREP_POS_CHGD :
+ {
+ if ( GetValidPrtAreaFlag() )
+ {
+ GETGRID( FindPageFrm() )
+ if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
+ InvalidatePrt();
+ }
+
+ // Falls wir mit niemandem ueberlappen:
+ // Ueberlappte irgendein Fly _vor_ der Positionsaenderung ?
+ sal_Bool bFormat = pPara->HasFly();
+ if( !bFormat )
+ {
+ if( IsInFly() )
+ {
+ SwTwips nTmpBottom = GetUpper()->Frm().Top() +
+ GetUpper()->Prt().Bottom();
+ if( nTmpBottom < Frm().Bottom() )
+ bFormat = sal_True;
+ }
+ if( !bFormat )
+ {
+ if ( GetDrawObjs() )
+ {
+ const sal_uInt32 nCnt = GetDrawObjs()->Count();
+ for ( MSHORT i = 0; i < nCnt; ++i )
+ {
+ SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
+ // --> OD 2004-07-16 #i28701# - consider all
+ // to-character anchored objects
+ if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
+ == FLY_AT_CHAR )
+ {
+ bFormat = sal_True;
+ break;
+ }
+ }
+ }
+ if( !bFormat )
+ {
+ // Gibt es ueberhaupt Flys auf der Seite ?
+ SwTxtFly aTxtFly( this );
+ if( aTxtFly.IsOn() )
+ {
+ // Ueberlappt irgendein Fly ?
+ aTxtFly.Relax();
+ bFormat = aTxtFly.IsOn() || IsUndersized();
+ }
+ }
+ }
+ }
+
+ if( bFormat )
+ {
+ if( !IsLocked() )
+ {
+ if( pPara->GetRepaint()->HasArea() )
+ SetCompletePaint();
+ Init();
+ pPara = 0;
+ _InvalidateSize();
+ }
+ }
+ else
+ {
+ if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
+ Prepare( PREP_REGISTER, 0, bNotify );
+ // Durch Positionsverschiebungen mit Ftns muessen die
+ // Frames neu adjustiert werden.
+ else if( HasFtn() )
+ {
+ Prepare( PREP_ADJUST_FRM, 0, bNotify );
+ _InvalidateSize();
+ }
+ else
+ return; // damit kein SetPrep() erfolgt.
+ }
+ break;
+ }
+ case PREP_REGISTER:
+ if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
+ {
+ pPara->SetPrepAdjust( sal_True );
+ CalcLineSpace();
+ InvalidateSize();
+ _InvalidatePrt();
+ SwFrm* pNxt;
+ if ( 0 != ( pNxt = GetIndNext() ) )
+ {
+ pNxt->_InvalidatePrt();
+ if ( pNxt->IsLayoutFrm() )
+ pNxt->InvalidatePage();
+ }
+ SetCompletePaint();
+ }
+ break;
+ case PREP_FTN_GONE :
+ {
+ // Wenn ein Follow uns ruft, weil eine Fussnote geloescht wird, muss unsere
+ // letzte Zeile formatiert werden, damit ggf. die erste Zeile des Follows
+ // hochrutschen kann, die extra auf die naechste Seite gerutscht war, um mit
+ // der Fussnote zusammen zu sein, insbesondere bei spaltigen Bereichen.
+ ASSERT( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" );
+ xub_StrLen nPos = GetFollow()->GetOfst();
+ if( IsFollow() && GetOfst() == nPos ) // falls wir gar keine Textmasse besitzen,
+ FindMaster()->Prepare( PREP_FTN_GONE ); // rufen wir das Prepare unseres Masters
+ if( nPos )
+ --nPos; // das Zeichen vor unserem Follow
+ InvalidateRange( SwCharRange( nPos, 1 ), 0 );
+ return;
+ }
+ case PREP_ERGOSUM:
+ case PREP_QUOVADIS:
+ {
+ xub_StrLen nPos;
+ if( lcl_ErgoVadis( this, nPos, ePrep ) )
+ InvalidateRange( SwCharRange( nPos, 1 ), 0 );
+ }
+ break;
+ case PREP_FLY_ATTR_CHG:
+ {
+ if( pVoid )
+ {
+ xub_StrLen nWhere = CalcFlyPos( (SwFrmFmt*)pVoid );
+ ASSERT( STRING_LEN != nWhere, "Prepare: Why me?" );
+ InvalidateRange( SwCharRange( nWhere, 1 ) );
+ return;
+ }
+ // else ... Laufe in den Default-Switch
+ }
+ case PREP_CLEAR:
+ default:
+ {
+ if( IsLocked() )
+ {
+ if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep )
+ {
+ xub_StrLen nLen = ( GetFollow() ? GetFollow()->GetOfst() :
+ STRING_LEN ) - GetOfst();
+ InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 );
+ }
+ }
+ else
+ {
+ if( pPara->GetRepaint()->HasArea() )
+ SetCompletePaint();
+ Init();
+ pPara = 0;
+ if( GetOfst() && !IsFollow() )
+ _SetOfst( 0 );
+ if ( bNotify )
+ InvalidateSize();
+ else
+ _InvalidateSize();
+ }
+ return; // damit kein SetPrep() erfolgt.
+ }
+ }
+ if( pPara )
+ pPara->SetPrep( sal_True );
+}
+
+/* -----------------11.02.99 17:56-------------------
+ * Kleine Hilfsklasse mit folgender Funktion:
+ * Sie soll eine Probeformatierung vorbereiten.
+ * Der Frame wird in Groesse und Position angepasst, sein SwParaPortion zur Seite
+ * gestellt und eine neue erzeugt, dazu wird formatiert mit gesetztem bTestFormat.
+ * Im Dtor wird der TxtFrm wieder in seinen alten Zustand zurueckversetzt.
+ *
+ * --------------------------------------------------*/
+
+class SwTestFormat
+{
+ SwTxtFrm *pFrm;
+ SwParaPortion *pOldPara;
+ SwRect aOldFrm, aOldPrt;
+public:
+ SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPrv, SwTwips nMaxHeight );
+ ~SwTestFormat();
+};
+
+SwTestFormat::SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPre, SwTwips nMaxHeight )
+ : pFrm( pTxtFrm )
+{
+ aOldFrm = pFrm->Frm();
+ aOldPrt = pFrm->Prt();
+
+ SWRECTFN( pFrm )
+ SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)();
+
+ pFrm->Frm() = pFrm->GetUpper()->Prt();
+ pFrm->Frm() += pFrm->GetUpper()->Frm().Pos();
+
+ (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight );
+ if( pFrm->GetPrev() )
+ (pFrm->Frm().*fnRect->fnSetPosY)(
+ (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() -
+ ( bVert ? nMaxHeight + 1 : 0 ) );
+
+ SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
+ const SwBorderAttrs &rAttrs = *aAccess.Get();
+ (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) );
+
+ if( pPre )
+ {
+ SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre );
+ (pFrm->Prt().*fnRect->fnSetPosY)( nUpper );
+ }
+ (pFrm->Prt().*fnRect->fnSetHeight)(
+ Max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() -
+ (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) );
+ (pFrm->Prt().*fnRect->fnSetWidth)(
+ (pFrm->Frm().*fnRect->fnGetWidth)() -
+ // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
+ ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) );
+ pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL;
+ pFrm->SetPara( new SwParaPortion(), sal_False );
+
+ ASSERT( ! pFrm->IsSwapped(), "A frame is swapped before _Format" );
+
+ if ( pFrm->IsVertical() )
+ pFrm->SwapWidthAndHeight();
+
+ SwTxtFormatInfo aInf( pFrm, sal_False, sal_True, sal_True );
+ SwTxtFormatter aLine( pFrm, &aInf );
+
+ pFrm->_Format( aLine, aInf );
+
+ if ( pFrm->IsVertical() )
+ pFrm->SwapWidthAndHeight();
+
+ ASSERT( ! pFrm->IsSwapped(), "A frame is swapped after _Format" );
+}
+
+SwTestFormat::~SwTestFormat()
+{
+ pFrm->Frm() = aOldFrm;
+ pFrm->Prt() = aOldPrt;
+ pFrm->SetPara( pOldPara );
+}
+
+sal_Bool SwTxtFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, sal_Bool &bSplit )
+{
+ PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 )
+
+ if( IsLocked() && GetUpper()->Prt().Width() <= 0 )
+ return sal_False;
+
+ SwTestFormat aSave( this, pPrv, rMaxHeight );
+
+ return SwTxtFrm::WouldFit( rMaxHeight, bSplit, sal_True );
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::WouldFit()
+ *************************************************************************/
+
+/* SwTxtFrm::WouldFit()
+ * sal_True: wenn ich aufspalten kann.
+ * Es soll und braucht nicht neu formatiert werden.
+ * Wir gehen davon aus, dass bereits formatiert wurde und dass
+ * die Formatierungsdaten noch aktuell sind.
+ * Wir gehen davon aus, dass die Framebreiten des evtl. Masters und
+ * Follows gleich sind. Deswegen wird kein FindBreak() mit FindOrphans()
+ * gerufen.
+ * Die benoetigte Hoehe wird von nMaxHeight abgezogen!
+ */
+
+sal_Bool SwTxtFrm::WouldFit( SwTwips &rMaxHeight, sal_Bool &bSplit, sal_Bool bTst )
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::WouldFit with swapped frame" );
+ SWRECTFN( this );
+
+ if( IsLocked() )
+ return sal_False;
+
+ //Kann gut sein, dass mir der IdleCollector mir die gecachten
+ //Informationen entzogen hat.
+ if( !IsEmpty() )
+ GetFormatted();
+
+ // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph
+ // can *not* be applied, if test format is in progress. The test format doesn't
+ // adjust the frame and the printing area - see method <SwTxtFrm::_Format(..)>,
+ // which is called in <SwTxtFrm::TestFormat(..)>
+ if ( IsEmpty() && !bTst )
+ {
+ bSplit = sal_False;
+ SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height();
+ if( rMaxHeight < nHeight )
+ return sal_False;
+ else
+ {
+ rMaxHeight -= nHeight;
+ return sal_True;
+ }
+ }
+
+ // In sehr unguenstigen Faellen kann GetPara immer noch 0 sein.
+ // Dann returnen wir sal_True, um auf der neuen Seite noch einmal
+ // anformatiert zu werden.
+ ASSERT( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" );
+ if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) )
+ return sal_True;
+
+ // Da das Orphan-Flag nur sehr fluechtig existiert, wird als zweite
+ // Bedingung ueberprueft, ob die Rahmengroesse durch CalcPreps
+ // auf riesengross gesetzt wird, um ein MoveFwd zu erzwingen.
+ if( IsWidow() || ( bVert ?
+ ( 0 == Frm().Left() ) :
+ ( LONG_MAX - 20000 < Frm().Bottom() ) ) )
+ {
+ SetWidow(sal_False);
+ if ( GetFollow() )
+ {
+ // Wenn wir hier durch eine Widow-Anforderung unseres Follows gelandet
+ // sind, wird ueberprueft, ob es ueberhaupt einen Follow mit einer
+ // echten Hoehe gibt, andernfalls (z.B. in neu angelegten SctFrms)
+ // ignorieren wir das IsWidow() und pruefen doch noch, ob wir
+ // genung Platz finden.
+ if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) ||
+ ( bVert && 0 < Frm().Left() ) ) &&
+ ( GetFollow()->IsVertical() ?
+ !GetFollow()->Frm().Width() :
+ !GetFollow()->Frm().Height() ) )
+ {
+ SwTxtFrm* pFoll = GetFollow()->GetFollow();
+ while( pFoll &&
+ ( pFoll->IsVertical() ?
+ !pFoll->Frm().Width() :
+ !pFoll->Frm().Height() ) )
+ pFoll = pFoll->GetFollow();
+ if( pFoll )
+ return sal_False;
+ }
+ else
+ return sal_False;
+ }
+ }
+
+ SWAP_IF_NOT_SWAPPED( this );
+
+ SwTxtSizeInfo aInf( this );
+ SwTxtMargin aLine( this, &aInf );
+
+ WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit );
+
+ sal_Bool bRet = sal_True;
+
+ aLine.Bottom();
+ // Ist Aufspalten ueberhaupt notwendig?
+ if ( 0 != ( bSplit = !aFrmBreak.IsInside( aLine ) ) )
+ bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst );
+ else
+ {
+ //Wir brauchen die Gesamthoehe inklusive der aktuellen Zeile
+ aLine.Top();
+ do
+ {
+ rMaxHeight -= aLine.GetLineHeight();
+ } while ( aLine.Next() );
+ }
+
+ UNDO_SWAP( this )
+
+ return bRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::GetParHeight()
+ *************************************************************************/
+
+KSHORT SwTxtFrm::GetParHeight() const
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::GetParHeight with swapped frame" )
+
+ if( !HasPara() )
+ { // Fuer nichtleere Absaetze ist dies ein Sonderfall, da koennen wir
+ // bei UnderSized ruhig nur 1 Twip mehr anfordern.
+ KSHORT nRet = (KSHORT)Prt().SSize().Height();
+ if( IsUndersized() )
+ {
+ if( IsEmpty() )
+ nRet = (KSHORT)EmptyHeight();
+ else
+ ++nRet;
+ }
+ return nRet;
+ }
+
+ // FME, OD 08.01.2004 #i11859# - refactoring and improve code
+ const SwLineLayout* pLineLayout = GetPara();
+ KSHORT nHeight = pLineLayout->GetRealHeight();
+ if( GetOfst() && !IsFollow() ) // Ist dieser Absatz gescrollt? Dann ist unsere
+ nHeight *= 2; // bisherige Hoehe mind. eine Zeilenhoehe zu gering
+ // OD 2004-03-04 #115793#
+ while ( pLineLayout && pLineLayout->GetNext() )
+ {
+ pLineLayout = pLineLayout->GetNext();
+ nHeight = nHeight + pLineLayout->GetRealHeight();
+ }
+
+ return nHeight;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::GetFormatted()
+ *************************************************************************/
+
+// returnt this _immer_ im formatierten Zustand!
+SwTxtFrm* SwTxtFrm::GetFormatted( bool bForceQuickFormat )
+{
+ SWAP_IF_SWAPPED( this )
+
+ //Kann gut sein, dass mir der IdleCollector mir die gecachten
+ //Informationen entzogen hat. Calc() ruft unser Format.
+ //Nicht bei leeren Absaetzen!
+ if( !HasPara() && !(IsValid() && IsEmpty()) )
+ {
+ // Calc() muss gerufen werden, weil unsere Frameposition
+ // nicht stimmen muss.
+ const sal_Bool bFormat = GetValidSizeFlag();
+ Calc();
+ // Es kann durchaus sein, dass Calc() das Format()
+ // nicht anstiess (weil wir einst vom Idle-Zerstoerer
+ // aufgefordert wurden unsere Formatinformationen wegzuschmeissen).
+ // 6995: Optimierung mit FormatQuick()
+ if( bFormat && !FormatQuick( bForceQuickFormat ) )
+ Format();
+ }
+
+ UNDO_SWAP( this )
+
+ return this;
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcFitToContent()
+ *************************************************************************/
+
+SwTwips SwTxtFrm::CalcFitToContent()
+{
+ // --> FME 2004-07-16 #i31490#
+ // If we are currently locked, we better return with a
+ // fairly reasonable value:
+ if ( IsLocked() )
+ return Prt().Width();
+ // <--
+
+ SwParaPortion* pOldPara = GetPara();
+ SwParaPortion *pDummy = new SwParaPortion();
+ SetPara( pDummy, false );
+ const SwPageFrm* pPage = FindPageFrm();
+
+ const Point aOldFrmPos = Frm().Pos();
+ const SwTwips nOldFrmWidth = Frm().Width();
+ const SwTwips nOldPrtWidth = Prt().Width();
+ const SwTwips nPageWidth = GetUpper()->IsVertical() ?
+ pPage->Prt().Height() :
+ pPage->Prt().Width();
+
+ Frm().Width( nPageWidth );
+ Prt().Width( nPageWidth );
+
+ // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
+ if ( IsRightToLeft() )
+ Frm().Pos().X() += nOldFrmWidth - nPageWidth;
+
+ // --> FME 2004-07-16 #i31490#
+ SwTxtFrmLocker aLock( this );
+ // <--
+
+ SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
+ aInf.SetIgnoreFly( sal_True );
+ SwTxtFormatter aLine( this, &aInf );
+ SwHookOut aHook( aInf );
+
+ // --> OD 2005-09-06 #i54031# - assure mininum of MINLAY twips.
+ const SwTwips nMax = Max( (SwTwips)MINLAY,
+ aLine._CalcFitToContent() + 1 );
+ // <--
+
+ Frm().Width( nOldFrmWidth );
+ Prt().Width( nOldPrtWidth );
+
+ // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
+ if ( IsRightToLeft() )
+ Frm().Pos() = aOldFrmPos;
+
+
+ SetPara( pOldPara );
+
+ return nMax;
+}
+
+/** simulate format for a list item paragraph, whose list level attributes
+ are in LABEL_ALIGNMENT mode, in order to determine additional first
+ line offset for the real text formatting due to the value of label
+ adjustment attribute of the list level.
+
+ OD 2008-01-31 #newlistlevelattrs#
+
+ @author OD
+*/
+void SwTxtFrm::CalcAdditionalFirstLineOffset()
+{
+ if ( IsLocked() )
+ return;
+
+ // reset additional first line offset
+ mnAdditionalFirstLineOffset = 0;
+
+ const SwTxtNode* pTxtNode( GetTxtNode() );
+ if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->IsCountedInList() &&
+ pTxtNode->GetNumRule() )
+ {
+ const SwNumFmt& rNumFmt =
+ pTxtNode->GetNumRule()->Get( static_cast<USHORT>(pTxtNode->GetActualListLevel()) );
+ if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ // keep current paragraph portion and apply dummy paragraph portion
+ SwParaPortion* pOldPara = GetPara();
+ SwParaPortion *pDummy = new SwParaPortion();
+ SetPara( pDummy, false );
+
+ // lock paragraph
+ SwTxtFrmLocker aLock( this );
+
+ // simulate text formatting
+ SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
+ aInf.SetIgnoreFly( sal_True );
+ SwTxtFormatter aLine( this, &aInf );
+ SwHookOut aHook( aInf );
+ aLine._CalcFitToContent();
+
+ // determine additional first line offset
+ const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion();
+ if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFtnNumPortion() )
+ {
+ SwTwips nNumberPortionWidth( pFirstPortion->Width() );
+
+ const SwLinePortion* pPortion = pFirstPortion->GetPortion();
+ while ( pPortion &&
+ pPortion->InNumberGrp() && !pPortion->IsFtnNumPortion())
+ {
+ nNumberPortionWidth += pPortion->Width();
+ pPortion = pPortion->GetPortion();
+ }
+
+ if ( ( IsRightToLeft() &&
+ rNumFmt.GetNumAdjust() == SVX_ADJUST_LEFT ) ||
+ ( !IsRightToLeft() &&
+ rNumFmt.GetNumAdjust() == SVX_ADJUST_RIGHT ) )
+ {
+ mnAdditionalFirstLineOffset = -nNumberPortionWidth;
+ }
+ else if ( rNumFmt.GetNumAdjust() == SVX_ADJUST_CENTER )
+ {
+ mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2);
+ }
+ }
+
+ // restore paragraph portion
+ SetPara( pOldPara );
+ }
+ }
+}
+
+/** determine height of last line for the calculation of the proportional line
+ spacing
+
+ OD 08.01.2004 #i11859#
+ OD 2004-03-17 #i11860# - method <GetHeightOfLastLineForPropLineSpacing()>
+ replace by method <_CalcHeightOfLastLine()>. Height of last line will be
+ stored in new member <mnHeightOfLastLine> and can be accessed via method
+ <GetHeightOfLastLine()>
+ OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont>
+ in order to force the usage of the former algorithm to determine the
+ height of the last line, which uses the font.
+
+ @author OD
+*/
+void SwTxtFrm::_CalcHeightOfLastLine( const bool _bUseFont )
+{
+ // --> OD 2006-11-13 #i71281#
+ // invalidate printing area, if height of last line changes
+ const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine );
+ // <--
+ // determine output device
+ ViewShell* pVsh = GetShell();
+ ASSERT( pVsh, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no ViewShell" );
+ // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
+ // There could be no <ViewShell> instance in the case of loading a binary
+ // StarOffice file format containing an embedded Writer document.
+ if ( !pVsh )
+ {
+ return;
+ }
+ OutputDevice* pOut = pVsh->GetOut();
+ const IDocumentSettingAccess* pIDSA = GetTxtNode()->getIDocumentSettingAccess();
+ if ( !pIDSA->get(IDocumentSettingAccess::BROWSE_MODE) ||
+ pVsh->GetViewOptions()->IsPrtFormat() )
+ {
+ pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
+ }
+ ASSERT( pOut, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no OutputDevice" );
+ // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
+ if ( !pOut )
+ {
+ return;
+ }
+ // <--
+
+ // determine height of last line
+
+ if ( _bUseFont || pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING ) )
+ {
+ // former determination of last line height for proprotional line
+ // spacing - take height of font set at the paragraph
+ SwFont aFont( GetAttrSet(), pIDSA );
+
+ // Wir muessen dafuer sorgen, dass am OutputDevice der Font
+ // korrekt restauriert wird, sonst droht ein Last!=Owner.
+ if ( pLastFont )
+ {
+ SwFntObj *pOldFont = pLastFont;
+ pLastFont = NULL;
+ aFont.SetFntChg( sal_True );
+ aFont.ChgPhysFnt( pVsh, *pOut );
+ mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
+ pLastFont->Unlock();
+ pLastFont = pOldFont;
+ pLastFont->SetDevFont( pVsh, *pOut );
+ }
+ else
+ {
+ Font aOldFont = pOut->GetFont();
+ aFont.SetFntChg( sal_True );
+ aFont.ChgPhysFnt( pVsh, *pOut );
+ mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
+ pLastFont->Unlock();
+ pLastFont = NULL;
+ pOut->SetFont( aOldFont );
+ }
+ }
+ else
+ {
+ // new determination of last line height - take actually height of last line
+ // --> OD 2008-05-06 #i89000#
+ // assure same results, if paragraph is undersized
+ if ( IsUndersized() )
+ {
+ mnHeightOfLastLine = 0;
+ }
+ else
+ {
+ bool bCalcHeightOfLastLine = true;
+ if ( !HasPara() )
+ {
+ if ( IsEmpty() )
+ {
+ mnHeightOfLastLine = EmptyHeight();
+ bCalcHeightOfLastLine = false;
+ }
+ }
+
+ if ( bCalcHeightOfLastLine )
+ {
+ ASSERT( HasPara(),
+ "<SwTxtFrm::_CalcHeightOfLastLine()> - missing paragraph portions." );
+ const SwLineLayout* pLineLayout = GetPara();
+ while ( pLineLayout && pLineLayout->GetNext() )
+ {
+ // iteration to last line
+ pLineLayout = pLineLayout->GetNext();
+ }
+ if ( pLineLayout )
+ {
+ SwTwips nAscent, nDescent, nDummy1, nDummy2;
+ // --> OD 2005-05-20 #i47162# - suppress consideration of
+ // fly content portions and the line portion.
+ pLineLayout->MaxAscentDescent( nAscent, nDescent,
+ nDummy1, nDummy2,
+ 0, true );
+ // <--
+ // --> OD 2006-11-22 #i71281#
+ // Suppress wrong invalidation of printing area, if method is
+ // called recursive.
+ // Thus, member <mnHeightOfLastLine> is only set directly, if
+ // no recursive call is needed.
+ // mnHeightOfLastLine = nAscent + nDescent;
+ const SwTwips nNewHeightOfLastLine = nAscent + nDescent;
+ // --> OD 2005-05-20 #i47162# - if last line only contains
+ // fly content portions, <mnHeightOfLastLine> is zero.
+ // In this case determine height of last line by the font
+ if ( nNewHeightOfLastLine == 0 )
+ {
+ _CalcHeightOfLastLine( true );
+ }
+ else
+ {
+ mnHeightOfLastLine = nNewHeightOfLastLine;
+ }
+ // <--
+ // <--
+ }
+ }
+ }
+ // <--
+ }
+ // --> OD 2006-11-13 #i71281#
+ // invalidate printing area, if height of last line changes
+ if ( mnHeightOfLastLine != mnOldHeightOfLastLine )
+ {
+ InvalidatePrt();
+ }
+ // <--
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetLineSpace()
+ *************************************************************************/
+// OD 07.01.2004 #i11859# - change return data type
+// add default parameter <_bNoPropLineSpacing> to control, if the
+// value of a proportional line spacing is returned or not
+// OD 07.01.2004 - trying to describe purpose of method:
+// Method returns the value of the inter line spacing for a text frame.
+// Such a value exists for proportional line spacings ("1,5 Lines",
+// "Double", "Proportional" and for leading line spacing ("Leading").
+// By parameter <_bNoPropLineSpace> (default value false) it can be
+// controlled, if the value of a proportional line spacing is returned.
+long SwTxtFrm::GetLineSpace( const bool _bNoPropLineSpace ) const
+{
+ long nRet = 0;
+
+ const SwAttrSet* pSet = GetAttrSet();
+ const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
+
+ switch( rSpace.GetInterLineSpaceRule() )
+ {
+ case SVX_INTER_LINE_SPACE_PROP:
+ {
+ // OD 07.01.2004 #i11859#
+ if ( _bNoPropLineSpace )
+ {
+ break;
+ }
+
+ // OD 2004-03-17 #i11860# - use method <GetHeightOfLastLine()>
+ nRet = GetHeightOfLastLine();
+
+ long nTmp = nRet;
+ nTmp *= rSpace.GetPropLineSpace();
+ nTmp /= 100;
+ nTmp -= nRet;
+ if ( nTmp > 0 )
+ nRet = nTmp;
+ else
+ nRet = 0;
+ }
+ break;
+ case SVX_INTER_LINE_SPACE_FIX:
+ {
+ if ( rSpace.GetInterLineSpace() > 0 )
+ nRet = rSpace.GetInterLineSpace();
+ }
+ break;
+ default:
+ break;
+ }
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::FirstLineHeight()
+ *************************************************************************/
+
+KSHORT SwTxtFrm::FirstLineHeight() const
+{
+ if ( !HasPara() )
+ {
+ if( IsEmpty() && IsValid() )
+ return IsVertical() ? (KSHORT)Prt().Width() : (KSHORT)Prt().Height();
+ return KSHRT_MAX;
+ }
+ const SwParaPortion *pPara = GetPara();
+ if ( !pPara )
+ return KSHRT_MAX;
+
+ return pPara->Height();
+}
+
+MSHORT SwTxtFrm::GetLineCount( xub_StrLen nPos )
+{
+ MSHORT nRet = 0;
+ SwTxtFrm *pFrm = this;
+ do
+ {
+ pFrm->GetFormatted();
+ if( !pFrm->HasPara() )
+ break;
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtMargin aLine( pFrm, &aInf );
+ if( STRING_LEN == nPos )
+ aLine.Bottom();
+ else
+ aLine.CharToLine( nPos );
+ nRet = nRet + aLine.GetLineNr();
+ pFrm = pFrm->GetFollow();
+ } while ( pFrm && pFrm->GetOfst() <= nPos );
+ return nRet;
+}
+
+void SwTxtFrm::ChgThisLines()
+{
+ //not necassary to format here (GerFormatted etc.), because we have to come from there!
+
+ ULONG nNew = 0;
+ const SwLineNumberInfo &rInf = GetNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo();
+ if ( GetTxt().Len() && HasPara() )
+ {
+ SwTxtSizeInfo aInf( this );
+ SwTxtMargin aLine( this, &aInf );
+ if ( rInf.IsCountBlankLines() )
+ {
+ aLine.Bottom();
+ nNew = (ULONG)aLine.GetLineNr();
+ }
+ else
+ {
+ do
+ {
+ if( aLine.GetCurr()->HasCntnt() )
+ ++nNew;
+ } while ( aLine.NextLine() );
+ }
+ }
+ else if ( rInf.IsCountBlankLines() )
+ nNew = 1;
+
+ if ( nNew != nThisLines )
+ {
+ if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
+ {
+ nAllLines -= nThisLines;
+ nThisLines = nNew;
+ nAllLines += nThisLines;
+ SwFrm *pNxt = GetNextCntntFrm();
+ while( pNxt && pNxt->IsInTab() )
+ {
+ if( 0 != (pNxt = pNxt->FindTabFrm()) )
+ pNxt = pNxt->FindNextCnt();
+ }
+ if( pNxt )
+ pNxt->InvalidateLineNum();
+
+ //Extend repaint to the bottom.
+ if ( HasPara() )
+ {
+ SwRepaint *pRepaint = GetPara()->GetRepaint();
+ pRepaint->Bottom( Max( pRepaint->Bottom(),
+ Frm().Top()+Prt().Bottom()));
+ }
+ }
+ else //Paragraphs which are not counted should not manipulate the AllLines.
+ nThisLines = nNew;
+ }
+}
+
+
+void SwTxtFrm::RecalcAllLines()
+{
+ ValidateLineNum();
+
+ const SwAttrSet *pAttrSet = GetAttrSet();
+
+ if ( !IsInTab() )
+ {
+ const ULONG nOld = GetAllLines();
+ const SwFmtLineNumber &rLineNum = pAttrSet->GetLineNumber();
+ ULONG nNewNum;
+ const bool bRestart = GetTxtNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo().IsRestartEachPage();
+
+ if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() )
+ nNewNum = rLineNum.GetStartValue() - 1;
+ //If it is a follow or not has not be considered if it is a restart at each page; the
+ //restart should also take affekt at follows.
+ else if ( bRestart && FindPageFrm()->FindFirstBodyCntnt() == this )
+ {
+ nNewNum = 0;
+ }
+ else
+ {
+ SwCntntFrm *pPrv = GetPrevCntntFrm();
+ while ( pPrv &&
+ (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) )
+ pPrv = pPrv->GetPrevCntntFrm();
+
+ // --> FME 2007-06-22 #i78254# Restart line numbering at page change:
+ // First body content may be in table!
+ if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() )
+ pPrv = 0;
+ // <--
+
+ nNewNum = pPrv ? ((SwTxtFrm*)pPrv)->GetAllLines() : 0;
+ }
+ if ( rLineNum.IsCount() )
+ nNewNum += GetThisLines();
+
+ if ( nOld != nNewNum )
+ {
+ nAllLines = nNewNum;
+ SwCntntFrm *pNxt = GetNextCntntFrm();
+ while ( pNxt &&
+ (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) )
+ pNxt = pNxt->GetNextCntntFrm();
+ if ( pNxt )
+ {
+ if ( pNxt->GetUpper() != GetUpper() )
+ pNxt->InvalidateLineNum();
+ else
+ pNxt->_InvalidateLineNum();
+ }
+ }
+ }
+}
+
+void SwTxtFrm::VisitPortions( SwPortionHandler& rPH ) const
+{
+ const SwParaPortion* pPara = GetPara();
+
+ if( pPara )
+ {
+ if ( IsFollow() )
+ rPH.Skip( GetOfst() );
+
+ const SwLineLayout* pLine = pPara;
+ while ( pLine )
+ {
+ const SwLinePortion* pPor = pLine->GetFirstPortion();
+ while ( pPor )
+ {
+ pPor->HandlePortion( rPH );
+ pPor = pPor->GetPortion();
+ }
+
+ rPH.LineBreak();
+ pLine = pLine->GetNext();
+ }
+ }
+
+ rPH.Finish();
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::GetScriptInfo()
+ *************************************************************************/
+
+const SwScriptInfo* SwTxtFrm::GetScriptInfo() const
+{
+ const SwParaPortion* pPara = GetPara();
+ return pPara ? &pPara->GetScriptInfo() : 0;
+}
+
+/*************************************************************************
+ * lcl_CalcFlyBasePos()
+ * Helper function for SwTxtFrm::CalcBasePosForFly()
+ *************************************************************************/
+
+SwTwips lcl_CalcFlyBasePos( const SwTxtFrm& rFrm, SwRect aFlyRect,
+ SwTxtFly& rTxtFly )
+{
+ SWRECTFN( (&rFrm) )
+ SwTwips nRet = rFrm.IsRightToLeft() ?
+ (rFrm.Frm().*fnRect->fnGetRight)() :
+ (rFrm.Frm().*fnRect->fnGetLeft)();
+
+ do
+ {
+ SwRect aRect = rTxtFly.GetFrm( aFlyRect );
+ if ( 0 != (aRect.*fnRect->fnGetWidth)() )
+ {
+ if ( rFrm.IsRightToLeft() )
+ {
+ if ( (aRect.*fnRect->fnGetRight)() -
+ (aFlyRect.*fnRect->fnGetRight)() >= 0 )
+ {
+ (aFlyRect.*fnRect->fnSetRight)(
+ (aRect.*fnRect->fnGetLeft)() );
+ nRet = (aRect.*fnRect->fnGetLeft)();
+ }
+ else
+ break;
+ }
+ else
+ {
+ if ( (aFlyRect.*fnRect->fnGetLeft)() -
+ (aRect.*fnRect->fnGetLeft)() >= 0 )
+ {
+ (aFlyRect.*fnRect->fnSetLeft)(
+ (aRect.*fnRect->fnGetRight)() + 1 );
+ nRet = (aRect.*fnRect->fnGetRight)();
+ }
+ else
+ break;
+ }
+ }
+ else
+ break;
+ }
+ while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 );
+
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcBasePosForFly()
+ *************************************************************************/
+
+void SwTxtFrm::CalcBaseOfstForFly()
+{
+ ASSERT( !IsVertical() || !IsSwapped(),
+ "SwTxtFrm::CalcBasePosForFly with swapped frame!" )
+
+ const SwNode* pNode = GetTxtNode();
+ if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_FLY_OFFSETS) )
+ return;
+
+ SWRECTFN( this )
+
+ SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+
+ // Get first 'real' line and adjust position and height of line rectangle
+ // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour,
+ // if no 'real' line exists (empty paragraph with and without a dummy portion)
+ {
+ SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)();
+ const SwLineLayout* pLay = GetPara();
+ SwTwips nLineHeight = 200;
+ while( pLay && pLay->IsDummy() && pLay->GetNext() )
+ {
+ nTop += pLay->Height();
+ pLay = pLay->GetNext();
+ }
+ if ( pLay )
+ {
+ nLineHeight = pLay->Height();
+ }
+ (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight );
+ }
+
+ SwTxtFly aTxtFly( this );
+ aTxtFly.SetIgnoreCurrentFrame( sal_True );
+ aTxtFly.SetIgnoreContour( sal_True );
+ // --> OD 2004-12-17 #118809# - ignore objects in page header|footer for
+ // text frames not in page header|footer
+ aTxtFly.SetIgnoreObjsInHeaderFooter( sal_True );
+ // <--
+ SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
+ aTxtFly.SetIgnoreCurrentFrame( sal_False );
+ SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
+
+ // make values relative to frame start position
+ SwTwips nLeft = IsRightToLeft() ?
+ (Frm().*fnRect->fnGetRight)() :
+ (Frm().*fnRect->fnGetLeft)();
+
+ mnFlyAnchorOfst = nRet1 - nLeft;
+ mnFlyAnchorOfstNoWrap = nRet2 - nLeft;
+}
diff --git a/sw/source/core/text/txtftn.cxx b/sw/source/core/text/txtftn.cxx
new file mode 100644
index 000000000000..2b655847ad05
--- /dev/null
+++ b/sw/source/core/text/txtftn.cxx
@@ -0,0 +1,1699 @@
+/*************************************************************************
+ *
+ * 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 "viewsh.hxx"
+#include "doc.hxx"
+#include "pagefrm.hxx"
+#include "ndtxt.hxx"
+#include "txtatr.hxx"
+#include <SwPortionHandler.hxx>
+#include <txtftn.hxx>
+#include <flyfrm.hxx>
+#include <fmtftn.hxx>
+#include <ftninfo.hxx>
+#include <charfmt.hxx>
+#include <dflyobj.hxx>
+#include <rowfrm.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <breakit.hxx>
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <tabfrm.hxx>
+// OD 2004-05-24 #i28701#
+#include <sortedobjs.hxx>
+
+#include "txtcfg.hxx"
+#include "swfont.hxx" // new SwFont
+#include "porftn.hxx"
+#include "porfly.hxx"
+#include "porlay.hxx"
+#include "txtfrm.hxx"
+#include "itrform2.hxx"
+#include "ftnfrm.hxx" // FindQuoVadisFrm(),
+#include "pagedesc.hxx"
+#include "redlnitr.hxx" // SwRedlnItr
+#include "sectfrm.hxx" // SwSectionFrm
+#include "layouter.hxx" // Endnote-Collection
+#include "frmtool.hxx"
+#include "ndindex.hxx"
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * _IsFtnNumFrm()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::_IsFtnNumFrm() const
+{
+ const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster();
+ while( pFtn && !pFtn->ContainsCntnt() )
+ pFtn = pFtn->GetMaster();
+ return !pFtn;
+}
+
+/*************************************************************************
+ * FindFtn()
+ *************************************************************************/
+
+// Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn
+
+SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn )
+{
+ SwTxtFrm *pFrm = this;
+ const sal_Bool bFwd = *pFtn->GetStart() >= GetOfst();
+ while( pFrm )
+ {
+ if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) )
+ return pFrm;
+ pFrm = bFwd ? pFrm->GetFollow() :
+ pFrm->IsFollow() ? pFrm->FindMaster() : 0;
+ }
+ return pFrm;
+}
+
+/*************************************************************************
+ * CalcFtnFlag()
+ *************************************************************************/
+
+#ifndef DBG_UTIL
+void SwTxtFrm::CalcFtnFlag()
+#else
+void SwTxtFrm::CalcFtnFlag( xub_StrLen nStop )//Fuer den Test von SplitFrm
+#endif
+{
+ bFtn = sal_False;
+
+ const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( !pHints )
+ return;
+
+ const USHORT nSize = pHints->Count();
+
+#ifndef DBG_UTIL
+ const xub_StrLen nEnd = GetFollow() ? GetFollow()->GetOfst() : STRING_LEN;
+#else
+ const xub_StrLen nEnd = nStop != STRING_LEN ? nStop
+ : GetFollow() ? GetFollow()->GetOfst() : STRING_LEN;
+#endif
+
+ for ( USHORT i = 0; i < nSize; ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ if ( pHt->Which() == RES_TXTATR_FTN )
+ {
+ const xub_StrLen nIdx = *pHt->GetStart();
+ if ( nEnd < nIdx )
+ break;
+ if( GetOfst() <= nIdx )
+ {
+ bFtn = sal_True;
+ break;
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * CalcPrepFtnAdjust()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::CalcPrepFtnAdjust()
+{
+ ASSERT( HasFtn(), "Wer ruft mich da?" );
+ SwFtnBossFrm *pBoss = FindFtnBossFrm( sal_True );
+ const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this );
+ if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos &&
+ ( !pBoss->GetUpper()->IsSctFrm() ||
+ !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) )
+ {
+ const SwFtnContFrm *pCont = pBoss->FindFtnCont();
+ sal_Bool bReArrange = sal_True;
+
+ SWRECTFN( this )
+ if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
+ (Frm().*fnRect->fnGetBottom)() ) > 0 )
+ {
+ pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), sal_False,
+ pFtn->GetAttr() );
+ ValidateBodyFrm();
+ ValidateFrm();
+ pFtn = pBoss->FindFirstFtn( this );
+ }
+ else
+ bReArrange = sal_False;
+ if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) )
+ {
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+ aLine.TruncLines();
+ SetPara( 0 ); //Wird ggf. geloescht!
+ ResetPreps();
+ return sal_False;
+ }
+ }
+ return sal_True;
+}
+
+
+/*************************************************************************
+ * lcl_GetFtnLower()
+ *
+ * Local helper function. Checks if nLower should be taken as the boundary
+ * for the footnote.
+ *************************************************************************/
+
+SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower )
+{
+ // nLower is an absolute value. It denotes the bottom of the line
+ // containing the footnote.
+ SWRECTFN( pFrm )
+
+ ASSERT( !pFrm->IsVertical() || !pFrm->IsSwapped(),
+ "lcl_GetFtnLower with swapped frame" );
+
+ SwTwips nAdd;
+ SwTwips nRet = nLower;
+
+ //
+ // Check if text is inside a table.
+ //
+ if ( pFrm->IsInTab() )
+ {
+ //
+ // If pFrm is inside a table, we have to check if
+ // a) The table is not allowed to split or
+ // b) The table row is not allowed to split
+ //
+ // Inside a table, there are no footnotes,
+ // see SwFrm::FindFtnBossFrm. So we don't have to check
+ // the case that pFrm is inside a (footnote collecting) section
+ // within the table.
+ //
+ const SwFrm* pRow = pFrm;
+ while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
+ pRow = pRow->GetUpper();
+ const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper();
+
+ ASSERT( pTabFrm && pRow &&
+ pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" )
+
+ const BOOL bDontSplit = !pTabFrm->IsFollow() &&
+ !pTabFrm->IsLayoutSplitAllowed();
+
+ SwTwips nMin = 0;
+ if ( bDontSplit )
+ nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)();
+ else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() )
+ nMin = (pRow->Frm().*fnRect->fnGetBottom)();
+
+ if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 )
+ nRet = nMin;
+
+ nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)();
+ }
+ else
+ nAdd = (pFrm->*fnRect->fnGetBottomMargin)();
+
+ if( nAdd > 0 )
+ {
+ if ( bVert )
+ nRet -= nAdd;
+ else
+ nRet += nAdd;
+ }
+
+ // #i10770#: If there are fly frames anchored at previous paragraphs,
+ // the deadline should consider their lower borders.
+ const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower();
+ ASSERT( pStartFrm, "Upper has no lower" )
+ SwTwips nFlyLower = bVert ? LONG_MAX : 0;
+ while ( pStartFrm != pFrm )
+ {
+ ASSERT( pStartFrm, "Frame chain is broken" )
+ if ( pStartFrm->GetDrawObjs() )
+ {
+ const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
+ for ( USHORT i = 0; i < rObjs.Count(); ++i )
+ {
+ SwAnchoredObject* pAnchoredObj = rObjs[i];
+ SwRect aRect( pAnchoredObj->GetObjRect() );
+
+ if ( !pAnchoredObj->ISA(SwFlyFrm) ||
+ static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() )
+ {
+ const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
+ if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 )
+ nFlyLower = nBottom;
+ }
+ }
+ }
+
+ pStartFrm = pStartFrm->GetNext();
+ }
+
+ if ( bVert )
+ nRet = Min( nRet, nFlyLower );
+ else
+ nRet = Max( nRet, nFlyLower );
+
+ return nRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::GetFtnLine()
+ *************************************************************************/
+
+SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::GetFtnLine with swapped frame" )
+
+ SwTxtFrm *pThis = (SwTxtFrm*)this;
+
+ if( !HasPara() )
+ {
+ // #109071# GetFormatted() does not work here, bacause most probably
+ // the frame is currently locked. We return the previous value.
+ return pThis->mnFtnLine > 0 ?
+ pThis->mnFtnLine :
+ IsVertical() ? Frm().Left() : Frm().Bottom();
+ }
+
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwTxtInfo aInf( pThis );
+ SwTxtIter aLine( pThis, &aInf );
+ const xub_StrLen nPos = *pFtn->GetStart();
+ aLine.CharToLine( nPos );
+
+ SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
+ if( IsVertical() )
+ nRet = SwitchHorizontalToVertical( nRet );
+
+ UNDO_SWAP( this )
+
+ nRet = lcl_GetFtnLower( pThis, nRet );
+
+ pThis->mnFtnLine = nRet;
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetFtnRstHeight()
+ *************************************************************************/
+
+// Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich.
+// Sie wird eingeschraenkt durch den unteren Rand der Zeile mit
+// der Ftn-Referenz.
+
+SwTwips SwTxtFrm::_GetFtnFrmHeight() const
+{
+ ASSERT( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" );
+
+ const SwFtnFrm *pFtnFrm = FindFtnFrm();
+ const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef();
+ const SwFtnBossFrm *pBoss = FindFtnBossFrm();
+ if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()->
+ GetFtn().IsEndNote() ) )
+ return 0;
+
+ SWAP_IF_SWAPPED( this )
+
+ SwTwips nHeight = pRef->IsInFtnConnect() ?
+ 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() );
+ if( nHeight )
+ {
+ // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich
+ // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text
+ // eingeben.
+ const SwFrm *pCont = pFtnFrm->GetUpper();
+ //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf.
+ SWRECTFN( pCont )
+ SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
+ (Frm().*fnRect->fnGetTop)() );
+
+#ifdef DBG_UTIL
+ if( nTmp < 0 )
+ {
+ sal_Bool bInvalidPos = sal_False;
+ const SwLayoutFrm* pTmp = GetUpper();
+ while( !bInvalidPos && pTmp )
+ {
+ bInvalidPos = !pTmp->GetValidPosFlag() ||
+ !pTmp->Lower()->GetValidPosFlag();
+ if( pTmp == pCont )
+ break;
+ pTmp = pTmp->GetUpper();
+ }
+ ASSERT( bInvalidPos, "Hanging below FtnCont" );
+ }
+#endif
+
+ if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
+ {
+ //Wachstumspotential den Containers.
+ if ( !pRef->IsInFtnConnect() )
+ {
+ SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight );
+ nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True );
+ }
+ else
+ nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True );
+
+ nHeight += nTmp;
+ if( nHeight < 0 )
+ nHeight = 0;
+ }
+ else
+ { // The container has to shrink
+ nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight);
+ if( nTmp > 0 )
+ nHeight = nTmp;
+ else
+ nHeight = 0;
+ }
+ }
+
+ UNDO_SWAP( this )
+
+ return nHeight;
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindQuoVadisFrm()
+ *************************************************************************/
+
+SwTxtFrm *SwTxtFrm::FindQuoVadisFrm()
+{
+ // Erstmal feststellen, ob wir in einem FtnFrm stehen:
+ if( GetIndPrev() || !IsInFtn() )
+ return 0;
+
+ // Zum Vorgaenger-FtnFrm
+ SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster();
+ if( !pFtnFrm )
+ return 0;
+
+ // Nun den letzten Cntnt:
+ const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt();
+ if( !pCnt )
+ return NULL;
+ const SwCntntFrm *pLast;
+ do
+ { pLast = pCnt;
+ pCnt = pCnt->GetNextCntntFrm();
+ } while( pCnt && pFtnFrm->IsAnLower( pCnt ) );
+ return (SwTxtFrm*)pLast;
+}
+
+/*************************************************************************
+ * SwTxtFrm::RemoveFtn()
+ *************************************************************************/
+
+void SwTxtFrm::RemoveFtn( const xub_StrLen nStart, const xub_StrLen nLen )
+{
+ if ( !IsFtnAllowed() )
+ return;
+
+ SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( !pHints )
+ return;
+
+ sal_Bool bRollBack = nLen != STRING_LEN;
+ USHORT nSize = pHints->Count();
+ xub_StrLen nEnd;
+ SwTxtFrm* pSource;
+ if( bRollBack )
+ {
+ nEnd = nStart + nLen;
+ pSource = GetFollow();
+ if( !pSource )
+ return;
+ }
+ else
+ {
+ nEnd = STRING_LEN;
+ pSource = this;
+ }
+
+ if( nSize )
+ {
+ SwPageFrm* pUpdate = NULL;
+ sal_Bool bRemove = sal_False;
+ SwFtnBossFrm *pFtnBoss = 0;
+ SwFtnBossFrm *pEndBoss = 0;
+ sal_Bool bFtnEndDoc
+ = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos;
+ for ( USHORT i = nSize; i; )
+ {
+ SwTxtAttr *pHt = pHints->GetTextHint(--i);
+ if ( RES_TXTATR_FTN != pHt->Which() )
+ continue;
+
+ const xub_StrLen nIdx = *pHt->GetStart();
+ if( nStart > nIdx )
+ break;
+
+ if( nEnd >= nIdx )
+ {
+ SwTxtFtn *pFtn = (SwTxtFtn*)pHt;
+ sal_Bool bEndn = pFtn->GetFtn().IsEndNote();
+
+ if( bEndn )
+ {
+ if( !pEndBoss )
+ pEndBoss = pSource->FindFtnBossFrm();
+ }
+ else
+ {
+ if( !pFtnBoss )
+ {
+ pFtnBoss = pSource->FindFtnBossFrm( sal_True );
+ if( pFtnBoss->GetUpper()->IsSctFrm() )
+ {
+ SwSectionFrm* pSect = (SwSectionFrm*)
+ pFtnBoss->GetUpper();
+ if( pSect->IsFtnAtEnd() )
+ bFtnEndDoc = sal_False;
+ }
+ }
+ }
+
+ // Wir loeschen nicht, sondern wollen die Ftn verschieben.
+ // Drei Faelle koennen auftreten:
+ // 1) Es gibt weder Follow noch PrevFollow
+ // -> RemoveFtn() (vielleicht sogar ein ASSERT wert)
+ // 2) nStart > GetOfst, ich habe einen Follow
+ // -> Ftn wandert in den Follow
+ // 3) nStart < GetOfst, ich bin ein Follow
+ // -> Ftn wandert in den PrevFollow
+ // beide muessen auf einer Seite/in einer Spalte stehen.
+
+ SwFtnFrm *pFtnFrm = bEndn ? pEndBoss->FindFtn( pSource, pFtn ) :
+ pFtnBoss->FindFtn( pSource, pFtn );
+
+ if( pFtnFrm )
+ {
+ const sal_Bool bEndDoc = bEndn ? sal_True : bFtnEndDoc;
+ if( bRollBack )
+ {
+ while ( pFtnFrm )
+ {
+ pFtnFrm->SetRef( this );
+ pFtnFrm = pFtnFrm->GetFollow();
+ SetFtn( sal_True );
+ }
+ }
+ else if( GetFollow() )
+ {
+ SwCntntFrm *pDest = GetFollow();
+ while( pDest->GetFollow() && ((SwTxtFrm*)pDest->
+ GetFollow())->GetOfst() <= nIdx )
+ pDest = pDest->GetFollow();
+ ASSERT( !pDest->FindFtnBossFrm( !bEndn )->FindFtn(
+ pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists");
+
+ //Nicht ummelden sondern immer Moven.
+ // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)>
+ if ( bEndDoc ||
+ !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) )
+ )
+ {
+ SwPageFrm* pTmp = pFtnFrm->FindPageFrm();
+ if( pUpdate && pUpdate != pTmp )
+ pUpdate->UpdateFtnNum();
+ pUpdate = pTmp;
+ while ( pFtnFrm )
+ {
+ pFtnFrm->SetRef( pDest );
+ pFtnFrm = pFtnFrm->GetFollow();
+ }
+ }
+ else
+ {
+ if( bEndn )
+ pEndBoss->MoveFtns( this, pDest, pFtn );
+ else
+ pFtnBoss->MoveFtns( this, pDest, pFtn );
+ bRemove = sal_True;
+ }
+ ((SwTxtFrm*)pDest)->SetFtn( sal_True );
+
+ ASSERT( pDest->FindFtnBossFrm( !bEndn )->FindFtn( pDest,
+ pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed");
+ }
+ else
+ {
+ if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
+ !SwLayouter::Collecting( GetNode()->GetDoc(),
+ pEndBoss->FindSctFrm(), NULL ) ) )
+ {
+ if( bEndn )
+ pEndBoss->RemoveFtn( this, pFtn );
+ else
+ pFtnBoss->RemoveFtn( this, pFtn );
+ bRemove = bRemove || !bEndDoc;
+ ASSERT( bEndn ? !pEndBoss->FindFtn( this, pFtn ) :
+ !pFtnBoss->FindFtn( this, pFtn ),
+ "SwTxtFrm::RemoveFtn: can't get off that footnote" );
+ }
+ }
+ }
+ }
+ }
+ if( pUpdate )
+ pUpdate->UpdateFtnNum();
+ // Wir bringen die Oszillation zum stehen:
+ if( bRemove && !bFtnEndDoc && HasPara() )
+ {
+ ValidateBodyFrm();
+ ValidateFrm();
+ }
+ }
+ // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen,
+ // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset
+ // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist
+ // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig
+ // der Follow-Offset manipuliert.
+ xub_StrLen nOldOfst = STRING_LEN;
+ if( HasFollow() && nStart > GetOfst() )
+ {
+ nOldOfst = GetFollow()->GetOfst();
+ GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
+ }
+ pSource->CalcFtnFlag();
+ if( nOldOfst < STRING_LEN )
+ GetFollow()->ManipOfst( nOldOfst );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::ConnectFtn()
+ *************************************************************************/
+// sal_False, wenn irgendetwas schief gegangen ist.
+// Es gibt eigentlich nur zwei Moeglichkeiten:
+// a) Die Ftn ist bereits vorhanden
+// => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde
+// b) Die Ftn ist nicht vorhanden
+// => dann wird sie fuer uns angelegt.
+// Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht,
+// spielt in diesem Zusammenhang keine Rolle.
+// Optimierungen bei Endnoten.
+// Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die
+// Ftn verschoben werden.
+
+void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine )
+{
+ ASSERT( !IsVertical() || !IsSwapped(),
+ "SwTxtFrm::ConnectFtn with swapped frame" );
+
+ bFtn = sal_True;
+ bInFtnConnect = sal_True; //Bloss zuruecksetzen!
+ sal_Bool bEnd = pFtn->GetFtn().IsEndNote();
+
+ //
+ // We want to store this value, because it is needed as a fallback
+ // in GetFtnLine(), if there is no paragraph information available
+ //
+ mnFtnLine = nDeadLine;
+
+ // Wir brauchen immer einen Boss (Spalte/Seite)
+ SwSectionFrm *pSect;
+ SwCntntFrm *pCntnt = this;
+ if( bEnd && IsInSct() )
+ {
+ pSect = FindSctFrm();
+ if( pSect->IsEndnAtEnd() )
+ pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE );
+ if( !pCntnt )
+ pCntnt = this;
+ }
+
+ SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd );
+
+#if OSL_DEBUG_LEVEL > 1
+ SwTwips nRstHeight = GetRstHeight();
+#endif
+
+ pSect = pBoss->FindSctFrm();
+ sal_Bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
+ ( !( pSect && pSect->IsFtnAtEnd() ) &&
+ FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos );
+ //Ftn kann beim Follow angemeldet sein.
+ SwCntntFrm *pSrcFrm = FindFtnRef( pFtn );
+
+ if( bDocEnd )
+ {
+ if( pSect && pSrcFrm )
+ {
+ SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
+ if( pFtnFrm && pFtnFrm->IsInSct() )
+ {
+ pBoss->RemoveFtn( pSrcFrm, pFtn );
+ pSrcFrm = 0;
+ }
+ }
+ }
+ else if( bEnd && pSect )
+ {
+ SwFtnFrm *pFtnFrm = pSrcFrm ? pBoss->FindFtn( pSrcFrm, pFtn ) : NULL;
+ if( pFtnFrm && !pFtnFrm->GetUpper() )
+ pFtnFrm = NULL;
+ SwDoc *pDoc = GetNode()->GetDoc();
+ if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) )
+ {
+ if( !pSrcFrm )
+ {
+ SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,pFtn);
+ SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 );
+ ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
+ GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
+ }
+ else if( pSrcFrm != this )
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ bInFtnConnect = sal_False;
+ return;
+ }
+ else if( pSrcFrm )
+ {
+ SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
+ if( !pFtnBoss->IsInSct() ||
+ pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
+ {
+ pBoss->RemoveFtn( pSrcFrm, pFtn );
+ pSrcFrm = 0;
+ }
+ }
+ }
+
+ if( bDocEnd || bEnd )
+ {
+ if( !pSrcFrm )
+ pBoss->AppendFtn( this, pFtn );
+ else if( pSrcFrm != this )
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ bInFtnConnect = sal_False;
+ return;
+ }
+
+ SwSaveFtnHeight aHeight( pBoss, nDeadLine );
+
+ if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden.
+ pBoss->AppendFtn( this, pFtn );
+ else
+ {
+ SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
+ SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
+
+ sal_Bool bBrutal = sal_False;
+
+ if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte.
+ {
+ SwFrm *pCont = pFtnFrm->GetUpper();
+
+ SWRECTFN ( pCont )
+ long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
+ nDeadLine );
+
+ if( nDiff >= 0 )
+ {
+ //Wenn die Fussnote bei einem Follow angemeldet ist, so ist
+ //es jetzt an der Zeit sie umzumelden.
+ if ( pSrcFrm != this )
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ //Es steht Platz zur Verfuegung, also kann die Fussnote evtl.
+ //wachsen.
+ if ( pFtnFrm->GetFollow() && nDiff > 0 )
+ {
+ SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
+ pBoss->RearrangeFtns( nDeadLine, sal_False, pFtn );
+ ValidateBodyFrm();
+ ValidateFrm();
+ ViewShell *pSh = GetShell();
+ if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
+ //Damit uns nix durch die Lappen geht.
+ pSh->InvalidateWindows( pCont->Frm() );
+ }
+ bInFtnConnect = sal_False;
+ return;
+ }
+ else
+ bBrutal = sal_True;
+ }
+ else
+ {
+ // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig.
+ SwFrm* pTmp = this;
+ while( pTmp->GetNext() && pSrcFrm != pTmp )
+ pTmp = pTmp->GetNext();
+ if( pSrcFrm == pTmp )
+ bBrutal = sal_True;
+ else
+ { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf
+ // der Seite schon einen FtnContainer gibt, hilft nur die brutale
+ // Methode
+ if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() )
+ bBrutal = sal_True;
+ // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)>
+ else if ( !pFtnFrm->GetPrev() ||
+ pFtnBoss->IsBefore( pBoss )
+ )
+ {
+ SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd );
+ pSrcBoss->MoveFtns( pSrcFrm, this, pFtn );
+ }
+ else
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ }
+ }
+
+ // Die brutale Loesung: Fussnote entfernen und appenden.
+ // Es muss SetFtnDeadLine() gerufen werden, weil nach
+ // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche
+ // eingestellt werden kann.
+ if( bBrutal )
+ {
+ pBoss->RemoveFtn( pSrcFrm, pFtn, sal_False );
+ SwSaveFtnHeight *pHeight = bEnd ? NULL :
+ new SwSaveFtnHeight( pBoss, nDeadLine );
+ pBoss->AppendFtn( this, pFtn );
+ delete pHeight;
+ }
+ }
+
+ // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen,
+ // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch
+ // nicht kalkuliert worden ist.
+ if( !pSect || !pSect->Growable() )
+ {
+ // Umgebung validieren, um Oszillationen zu verhindern.
+ SwSaveFtnHeight aNochmal( pBoss, nDeadLine );
+ ValidateBodyFrm();
+ pBoss->RearrangeFtns( nDeadLine, sal_True );
+ ValidateFrm();
+ }
+ else if( pSect->IsFtnAtEnd() )
+ {
+ ValidateBodyFrm();
+ ValidateFrm();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ // pFtnFrm kann sich durch Calc veraendert haben ...
+ SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn );
+ if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) )
+ {
+ int bla = 5;
+ (void)bla;
+ }
+ nRstHeight = GetRstHeight();
+#endif
+ bInFtnConnect = sal_False;
+ return;
+}
+
+
+
+/*************************************************************************
+ * SwTxtFormatter::NewFtnPortion()
+ *************************************************************************/
+
+// Die Portion fuer die Ftn-Referenz im Text
+SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf,
+ SwTxtAttr *pHint )
+{
+ ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
+ "NewFtnPortion with unswapped frame" );
+
+ if( !pFrm->IsFtnAllowed() )
+ return 0;
+
+ SwTxtFtn *pFtn = (SwTxtFtn*)pHint;
+ SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
+ SwDoc *pDoc = pFrm->GetNode()->GetDoc();
+
+ if( rInf.IsTest() )
+ return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFrm, pFtn );
+
+ SWAP_IF_SWAPPED( pFrm )
+
+ KSHORT nReal;
+ {
+ KSHORT nOldReal = pCurr->GetRealHeight();
+ KSHORT nOldAscent = pCurr->GetAscent();
+ KSHORT nOldHeight = pCurr->Height();
+ ((SwTxtFormatter*)this)->CalcRealHeight();
+ nReal = pCurr->GetRealHeight();
+ if( nReal < nOldReal )
+ nReal = nOldReal;
+ pCurr->SetRealHeight( nOldReal );
+ pCurr->Height( nOldHeight );
+ pCurr->SetAscent( nOldAscent );
+ }
+
+ SwTwips nLower = Y() + nReal;
+
+ const bool bVertical = pFrm->IsVertical();
+ if( bVertical )
+ nLower = pFrm->SwitchHorizontalToVertical( nLower );
+
+ nLower = lcl_GetFtnLower( pFrm, nLower );
+
+ //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix
+ //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die
+ //Ftn wegwerfen und neu erzeugen.
+
+ if( !rInf.IsQuick() )
+ pFrm->ConnectFtn( pFtn, nLower );
+
+ SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn );
+ SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() );
+ SwFtnFrm *pFtnFrm = NULL;
+ if( pScrFrm )
+ pFtnFrm = pBoss->FindFtn( pScrFrm, pFtn );
+
+ // Wir erkundigen uns, ob durch unser Append irgendeine
+ // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet
+ // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten
+ // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr.
+ // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die
+ // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte.
+ // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt,
+ // so sollte die Ftn2-Referenz auch auf die naechste wandern.
+ if( !rFtn.IsEndNote() )
+ {
+ SwSectionFrm *pSct = pBoss->FindSctFrm();
+ sal_Bool bAtSctEnd = pSct && pSct->IsFtnAtEnd();
+ if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd )
+ {
+ SwFrm* pFtnCont = pBoss->FindFtnCont();
+ // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine
+ // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte
+ // ist, duerfen wir ausweichen
+ if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
+ ( !bAtSctEnd && pFrm->GetIndPrev() ) ||
+ ( pSct && pBoss->GetPrev() ) ) )
+ {
+ if( !pFtnCont )
+ {
+ rInf.SetStop( sal_True );
+ UNDO_SWAP( pFrm )
+ return 0;
+ }
+ else
+ {
+ // Es darf keine Fussnotencontainer in spaltigen Bereichen und
+ // gleichzeitig auf der Seite/Seitenspalte geben
+ if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich?
+ {
+ SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( sal_True );
+ SwFtnContFrm* pFtnC = pTmp->FindFtnCont();
+ if( pFtnC )
+ {
+ SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower();
+ if( pTmpFrm && *pTmpFrm < pFtn )
+ {
+ rInf.SetStop( sal_True );
+ UNDO_SWAP( pFrm )
+ return 0;
+ }
+ }
+ }
+ // Ist dies die letzte passende Zeile?
+ SwTwips nTmpBot = Y() + nReal * 2;
+
+ if( bVertical )
+ nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
+
+ SWRECTFN( pFtnCont )
+
+ const long nDiff = (*fnRect->fnYDiff)(
+ (pFtnCont->Frm().*fnRect->fnGetTop)(),
+ nTmpBot );
+
+ if( pScrFrm && nDiff < 0 )
+ {
+ if( pFtnFrm )
+ {
+ SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
+ if( pFtnBoss != pBoss )
+ {
+ // Wir sind in der letzte Zeile und die Fussnote
+ // ist auf eine andere Seite gewandert, dann wollen
+ // wir mit ...
+ rInf.SetStop( sal_True );
+ UNDO_SWAP( pFrm )
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // Endlich: FtnPortion anlegen und raus hier...
+ SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ),
+ pFrm, pFtn, nReal );
+ rInf.SetFtnInside( sal_True );
+
+ UNDO_SWAP( pFrm )
+
+ return pRet;
+ }
+
+/*************************************************************************
+ * SwTxtFormatter::NewFtnNumPortion()
+ *************************************************************************/
+
+// Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich
+
+SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const
+{
+ ASSERT( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(),
+ "This is the wrong place for a ftnnumber" );
+ if( rInf.GetTxtStart() != nStart ||
+ rInf.GetTxtStart() != rInf.GetIdx() )
+ return 0;
+
+ const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm();
+ const SwTxtFtn* pFtn = pFtnFrm->GetAttr();
+
+ // Aha, wir sind also im Fussnotenbereich
+ SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
+
+ SwDoc *pDoc = pFrm->GetNode()->GetDoc();
+ XubString aFtnTxt( rFtn.GetViewNumStr( *pDoc, sal_True ));
+
+ const SwEndNoteInfo* pInfo;
+ if( rFtn.IsEndNote() )
+ pInfo = &pDoc->GetEndNoteInfo();
+ else
+ pInfo = &pDoc->GetFtnInfo();
+ const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet();
+
+ const SwAttrSet* pParSet = &rInf.GetCharAttr();
+ const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess();
+ SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
+
+ // --> FME 2005-02-17 #i37142#
+ // Underline style of paragraph font should not be considered
+ // Overline style of paragraph font should not be considered
+ // Weight style of paragraph font should not be considered
+ // Posture style of paragraph font should not be considered
+ // See also #i18463# and SwTxtFormatter::NewNumberPortion()
+ pNumFnt->SetUnderline( UNDERLINE_NONE );
+ pNumFnt->SetOverline( UNDERLINE_NONE );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
+ // <--
+
+ pNumFnt->SetDiffFnt(&rSet, pIDSA );
+ pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
+
+ SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt );
+ pNewPor->SetLeft( !pFrm->IsRightToLeft() );
+ return pNewPor;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewErgoSumPortion()
+ *************************************************************************/
+
+XubString lcl_GetPageNumber( const SwPageFrm* pPage )
+{
+ ASSERT( pPage, "GetPageNumber: Homeless TxtFrm" );
+ MSHORT nVirtNum = pPage->GetVirtPageNum();
+ const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
+ return rNum.GetNumStr( nVirtNum );
+}
+
+SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const
+{
+ // Wir koennen nicht davon ausgehen, dass wir ein Follow sind
+ // 7983: GetIdx() nicht nStart
+ if( !pFrm->IsInFtn() || pFrm->GetPrev() ||
+ rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
+ pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
+ return 0;
+
+ // Aha, wir sind also im Fussnotenbereich
+ const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
+ SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
+ if( !pQuoFrm )
+ return 0;
+ const SwPageFrm* pPage = pFrm->FindPageFrm();
+ const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
+ if( pPage == pQuoFrm->FindPageFrm() )
+ return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht
+ const XubString aPage = lcl_GetPageNumber( pPage );
+ SwParaPortion *pPara = pQuoFrm->GetPara();
+ if( pPara )
+ pPara->SetErgoSumNum( aPage );
+ if( !rFtnInfo.aErgoSum.Len() )
+ return 0;
+ SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum,
+ lcl_GetPageNumber( pQuoPage ) );
+ return pErgo;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::FormatQuoVadis()
+ *************************************************************************/
+
+xub_StrLen SwTxtFormatter::FormatQuoVadis( const xub_StrLen nOffset )
+{
+ ASSERT( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
+ "SwTxtFormatter::FormatQuoVadis with swapped frame" );
+
+ if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
+ return nOffset;
+
+ const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow();
+ if( !pErgoFrm && pFrm->HasFollow() )
+ pErgoFrm = pFrm->GetFollow();
+ if( !pErgoFrm )
+ return nOffset;
+
+ if( pErgoFrm == pFrm->GetNext() )
+ {
+ SwFrm *pCol = pFrm->FindColFrm();
+ while( pCol && !pCol->GetNext() )
+ pCol = pCol->GetUpper()->FindColFrm();
+ if( pCol )
+ return nOffset;
+ }
+ else
+ {
+ const SwPageFrm* pPage = pFrm->FindPageFrm();
+ const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm();
+ if( pPage == pErgoPage )
+ return nOffset; // Wenn der ErgoSum auf der selben Seite steht
+ }
+
+ SwTxtFormatInfo &rInf = GetInfo();
+ const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
+ if( !rFtnInfo.aQuoVadis.Len() )
+ return nOffset;
+
+ // Ein Wort zu QuoVadis/ErgoSum:
+ // Fuer diese Texte wird der am Absatz eingestellte Font verwendet.
+ // Wir initialisieren uns also:
+// ResetFont();
+ FeedInf( rInf );
+ SeekStartAndChg( rInf, sal_True );
+ if( GetRedln() && pCurr->HasRedline() )
+ GetRedln()->Seek( *pFnt, nOffset, 0 );
+
+ // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen
+ // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen.
+ // Erst mal sehen, ob es so schlimm ist:
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+ KSHORT nLastLeft = 0;
+ while( pPor )
+ {
+ if ( pPor->IsFlyPortion() )
+ nLastLeft = ( (SwFlyPortion*) pPor)->Fix() +
+ ( (SwFlyPortion*) pPor)->Width();
+ pPor = pPor->GetPortion();
+ }
+ // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten
+ // Stelle umbricht, also beeinflussen wir die Width.
+ // nLastLeft ist jetzt quasi der rechte Rand.
+ const KSHORT nOldRealWidth = rInf.RealWidth();
+ rInf.RealWidth( nOldRealWidth - nLastLeft );
+
+ XubString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
+ SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo );
+ pQuo->SetAscent( rInf.GetAscent() );
+ pQuo->Height( rInf.GetTxtHeight() );
+ pQuo->Format( rInf );
+ USHORT nQuoWidth = pQuo->Width();
+ SwLinePortion* pCurrPor = pQuo;
+
+ while ( rInf.GetRest() )
+ {
+ SwLinePortion* pFollow = rInf.GetRest();
+ rInf.SetRest( 0 );
+ pCurrPor->Move( rInf );
+
+ ASSERT( pFollow->IsQuoVadisPortion(),
+ "Quo Vadis, rest of QuoVadisPortion" )
+
+ // format the rest and append it to the other QuoVadis parts
+ pFollow->Format( rInf );
+ nQuoWidth = nQuoWidth + pFollow->Width();
+
+ pCurrPor->Append( pFollow );
+ pCurrPor = pFollow;
+ }
+
+ nLastLeft = nOldRealWidth - nQuoWidth;
+ Right( Right() - nQuoWidth );
+
+ SWAP_IF_NOT_SWAPPED( pFrm )
+
+ const xub_StrLen nRet = FormatLine( nStart );
+
+ UNDO_SWAP( pFrm )
+
+ Right( rInf.Left() + nOldRealWidth - 1 );
+
+ nLastLeft = nOldRealWidth - pCurr->Width();
+ FeedInf( rInf );
+
+ // Es kann durchaus sein, dass am Ende eine Marginportion steht,
+ // die beim erneuten Aufspannen nur Aerger bereiten wuerde.
+ pPor = pCurr->FindLastPortion();
+ SwGluePortion *pGlue = pPor->IsMarginPortion() ?
+ (SwMarginPortion*) pPor : 0;
+ if( pGlue )
+ {
+ pGlue->Height( 0 );
+ pGlue->Width( 0 );
+ pGlue->SetLen( 0 );
+ pGlue->SetAscent( 0 );
+ pGlue->SetPortion( NULL );
+ pGlue->SetFixWidth(0);
+ }
+
+ // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer,
+ // dass der QuoVadis-Text rechts erscheint:
+ nLastLeft = nLastLeft - nQuoWidth;
+ if( nLastLeft )
+ {
+ if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand
+ {
+ switch( GetAdjust() )
+ {
+ case SVX_ADJUST_BLOCK:
+ {
+ if( !pCurr->GetLen() ||
+ CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1))
+ nLastLeft = pQuo->GetAscent();
+ nQuoWidth = nQuoWidth + nLastLeft;
+ break;
+ }
+ case SVX_ADJUST_RIGHT:
+ {
+ nLastLeft = pQuo->GetAscent();
+ nQuoWidth = nQuoWidth + nLastLeft;
+ break;
+ }
+ case SVX_ADJUST_CENTER:
+ {
+ nQuoWidth = nQuoWidth + pQuo->GetAscent();
+ long nDiff = nLastLeft - nQuoWidth;
+ if( nDiff < 0 )
+ {
+ nLastLeft = pQuo->GetAscent();
+ nQuoWidth = (USHORT)(-nDiff + nLastLeft);
+ }
+ else
+ {
+ nQuoWidth = 0;
+ nLastLeft = USHORT(( pQuo->GetAscent() + nDiff ) / 2);
+ }
+ break;
+ }
+ default:
+ nQuoWidth = nQuoWidth + nLastLeft;
+ }
+ }
+ else
+ nQuoWidth = nQuoWidth + nLastLeft;
+ if( nLastLeft )
+ {
+ pGlue = new SwGluePortion(0);
+ pGlue->Width( nLastLeft );
+ pPor->Append( pGlue );
+ pPor = pPor->GetPortion();
+ }
+ }
+
+ // Jetzt aber: die QuoVadis-Portion wird angedockt:
+ pCurrPor = pQuo;
+ while ( pCurrPor )
+ {
+ // pPor->Append deletes the pPortoin pointer of pPor. Therefore
+ // we have to keep a pointer to the next portion
+ pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion();
+ pPor->Append( pCurrPor );
+ pPor = pPor->GetPortion();
+ pCurrPor = pQuo;
+ }
+
+ pCurr->Width( pCurr->Width() + KSHORT( nQuoWidth ) );
+
+ // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt
+ // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig
+ // einen kleineren Font eingestellt als der vom QuoVadis-Text ...
+ CalcAdjustLine( pCurr );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( OPTDBG( rInf ) )
+ {
+// aDbstream << "FormatQuoVadis:" << endl;
+// pCurr->DebugPortions( aDbstream, rInf.GetTxt(), nStart );
+ }
+#endif
+
+ // Uff...
+ return nRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFormatter::MakeDummyLine()
+ *************************************************************************/
+
+// MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand
+// reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen
+// zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden.
+// Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn-
+// Oszillationen verwendet.
+
+void SwTxtFormatter::MakeDummyLine()
+{
+ KSHORT nRstHeight = GetFrmRstHeight();
+ if( pCurr && nRstHeight > pCurr->Height() )
+ {
+ SwLineLayout *pLay = new SwLineLayout;
+ nRstHeight = nRstHeight - pCurr->Height();
+ pLay->Height( nRstHeight );
+ pLay->SetAscent( nRstHeight );
+ Insert( pLay );
+ Next();
+ }
+}
+
+/*************************************************************************
+ * class SwFtnSave
+ *************************************************************************/
+class SwFtnSave
+{
+ SwTxtSizeInfo *pInf;
+ SwFont *pFnt;
+ SwFont *pOld;
+public:
+ SwFtnSave( const SwTxtSizeInfo &rInf,
+ const SwTxtFtn *pTxtFtn,
+ const bool bApplyGivenScriptType,
+ const BYTE nGivenScriptType );
+ ~SwFtnSave();
+};
+
+/*************************************************************************
+ * SwFtnSave::SwFtnSave()
+ *************************************************************************/
+
+SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf,
+ const SwTxtFtn* pTxtFtn,
+ const bool bApplyGivenScriptType,
+ const BYTE nGivenScriptType )
+ : pInf( &((SwTxtSizeInfo&)rInf) )
+ , pFnt( 0 )
+ , pOld( 0 )
+{
+ if( pTxtFtn && rInf.GetTxtFrm() )
+ {
+ pFnt = ((SwTxtSizeInfo&)rInf).GetFont();
+ pOld = new SwFont( *pFnt );
+ pOld->GetTox() = pFnt->GetTox();
+ pFnt->GetTox() = 0;
+ SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
+ const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
+
+ // --> OD 2009-01-29 #i98418#
+ if ( bApplyGivenScriptType )
+ {
+ pFnt->SetActual( nGivenScriptType );
+ }
+ else
+ {
+ // examine text and set script
+ String aTmpStr( rFtn.GetViewNumStr( *pDoc ) );
+ pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
+ }
+ // <--
+
+ const SwEndNoteInfo* pInfo;
+ if( rFtn.IsEndNote() )
+ pInfo = &pDoc->GetEndNoteInfo();
+ else
+ pInfo = &pDoc->GetFtnInfo();
+ const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
+ pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() );
+
+ // we reduce footnote size, if we are inside a double line portion
+ if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() )
+ {
+ Size aSize = pFnt->GetSize( pFnt->GetActual() );
+ pFnt->SetSize( Size( (long)aSize.Width() / 2,
+ (long)aSize.Height() / 2 ),
+ pFnt->GetActual() );
+ }
+
+ // set the correct rotation at the footnote font
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
+ sal_True, &pItem ))
+ pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(),
+ rInf.GetTxtFrm()->IsVertical() );
+
+ pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
+
+ if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
+ sal_True, &pItem ))
+ pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) );
+ }
+ else
+ pFnt = NULL;
+}
+
+/*************************************************************************
+ * SwFtnSave::~SwFtnSave()
+ *************************************************************************/
+
+SwFtnSave::~SwFtnSave()
+{
+ if( pFnt )
+ {
+ // SwFont zurueckstellen
+ *pFnt = *pOld;
+ pFnt->GetTox() = pOld->GetTox();
+ pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
+ delete pOld;
+ }
+}
+
+/*************************************************************************
+ * SwFtnPortion::SwFtnPortion()
+ *************************************************************************/
+
+SwFtnPortion::SwFtnPortion( const XubString &rExpand, SwTxtFrm *pFrame,
+ SwTxtFtn *pFootn, KSHORT nReal )
+ : SwFldPortion( rExpand, 0 )
+ , pFrm(pFrame)
+ , pFtn(pFootn)
+ , nOrigHeight( nReal )
+ // --> OD 2009-01-29 #i98418#
+ , mbPreferredScriptTypeSet( false )
+ , mnPreferredScriptType( SW_LATIN )
+ // <--
+{
+ SetLen(1);
+ SetWhichPor( POR_FTN );
+}
+
+/*************************************************************************
+ * SwFtnPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwFtnPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwFtnPortion::Format( SwTxtFormatInfo &rInf )
+{
+ // --> OD 2009-01-29 #i98418#
+// SwFtnSave aFtnSave( rInf, pFtn );
+ SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
+ // <--
+ // the idx is manipulated in SwExpandPortion::Format
+ // this flag indicates, that a footnote is allowed to trigger
+ // an underflow during SwTxtGuess::Guess
+ rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
+ sal_Bool bFull = SwFldPortion::Format( rInf );
+ rInf.SetFakeLineStart( sal_False );
+ SetAscent( rInf.GetAscent() );
+ Height( rInf.GetTxtHeight() );
+ rInf.SetFtnDone( !bFull );
+ if( !bFull )
+ rInf.SetParaFtn();
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwFtnPortion::Paint()
+ *************************************************************************/
+
+void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // --> OD 2009-01-29 #i98418#
+// SwFtnSave aFtnSave( rInf, pFtn );
+ SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
+ // <--
+ rInf.DrawViewOpt( *this, POR_FTN );
+ SwExpandPortion::Paint( rInf );
+}
+
+/*************************************************************************
+ * virtual SwFtnPortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const
+{
+ // --> OD 2009-01-29 #i98418#
+// SwFtnSave aFtnSave( rInfo, pFtn );
+ SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
+ // <--
+ return SwExpandPortion::GetTxtSize( rInfo );
+}
+
+// --> OD 2009-01-29 #i98418#
+void SwFtnPortion::SetPreferredScriptType( BYTE nPreferredScriptType )
+{
+ mbPreferredScriptTypeSet = true;
+ mnPreferredScriptType = nPreferredScriptType;
+}
+// <--
+
+/*************************************************************************
+ * class SwQuoVadisPortion
+ *************************************************************************/
+
+SwFldPortion *SwQuoVadisPortion::Clone( const XubString &rExpand ) const
+{ return new SwQuoVadisPortion( rExpand, aErgo ); }
+
+SwQuoVadisPortion::SwQuoVadisPortion( const XubString &rExp, const XubString& rStr )
+ : SwFldPortion( rExp ), aErgo(rStr)
+{
+ SetLen(0);
+ SetWhichPor( POR_QUOVADIS );
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf )
+{
+ // erster Versuch, vielleicht passt der Text
+ CheckScript( rInf );
+ sal_Bool bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+
+ if( bFull )
+ {
+ // zweiter Versuch, wir kuerzen den String:
+ aExpand = XubString( "...", RTL_TEXTENCODING_MS_1252 );
+ bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+ if( bFull )
+ // dritter Versuch, es langt: jetzt wird gestaucht:
+ Width( USHORT(rInf.Width() - rInf.X()) );
+
+ // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
+ if( rInf.GetRest() )
+ {
+ delete rInf.GetRest();
+ rInf.SetRest( 0 );
+ }
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ // if this QuoVadisPortion has a follow, the follow is responsible for
+ // the ergo text.
+ if ( ! HasFollow() )
+ rTxt += aErgo;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::HandlePortion()
+ *************************************************************************/
+
+void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString( aExpand );
+ aString += aErgo;
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::Paint()
+ *************************************************************************/
+
+void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // Wir wollen _immer_ per DrawStretchText ausgeben,
+ // weil nErgo schnell mal wechseln kann.
+ if( PrtWidth() )
+ {
+ rInf.DrawViewOpt( *this, POR_QUOVADIS );
+ SwTxtSlot aDiffTxt( &rInf, this, true, false );
+ SwFontSave aSave( rInf, pFnt );
+ rInf.DrawText( *this, rInf.GetLen(), sal_True );
+ }
+}
+
+/*************************************************************************
+ * class SwErgoSumPortion
+ *************************************************************************/
+
+SwFldPortion *SwErgoSumPortion::Clone( const XubString &rExpand ) const
+{
+ UniString aTmp; // = UniString::CreateFromInt32( 0 );
+ return new SwErgoSumPortion( rExpand, aTmp );
+}
+
+SwErgoSumPortion::SwErgoSumPortion( const XubString &rExp, const XubString& rStr )
+ : SwFldPortion( rExp )
+{
+ SetLen(0);
+ aExpand += rStr;
+
+ // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text
+ aExpand += ' ';
+ SetWhichPor( POR_ERGOSUM );
+}
+
+xub_StrLen SwErgoSumPortion::GetCrsrOfst( const KSHORT ) const
+{
+ return 0;
+}
+
+/*************************************************************************
+ * virtual SwErgoSumPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_Bool bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+ rInf.SetErgoDone( sal_True );
+
+ // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
+ if( bFull && rInf.GetRest() )
+ {
+ delete rInf.GetRest();
+ rInf.SetRest( 0 );
+ }
+
+ // We return false in order to get some text into the current line,
+ // even if it's full (better than looping)
+ return sal_False;
+}
+
+
+/*************************************************************************
+ * SwParaPortion::SetErgoSumNum()
+ *************************************************************************/
+
+void SwParaPortion::SetErgoSumNum( const XubString& rErgo )
+{
+ SwLineLayout *pLay = this;
+ while( pLay->GetNext() )
+ {
+ DBG_LOOP;
+ pLay = pLay->GetNext();
+ }
+ SwLinePortion *pPor = pLay;
+ SwQuoVadisPortion *pQuo = 0;
+ while( pPor && !pQuo )
+ {
+ if ( pPor->IsQuoVadisPortion() )
+ pQuo = (SwQuoVadisPortion*)pPor;
+ pPor = pPor->GetPortion();
+ }
+ if( pQuo )
+ pQuo->SetNumber( rErgo );
+}
+
+/*************************************************************************
+ * SwParaPortion::UpdateQuoVadis()
+ *
+ * Wird im SwTxtFrm::Prepare() gerufen
+ *************************************************************************/
+
+sal_Bool SwParaPortion::UpdateQuoVadis( const XubString &rQuo )
+{
+ SwLineLayout *pLay = this;
+ while( pLay->GetNext() )
+ {
+ DBG_LOOP;
+ pLay = pLay->GetNext();
+ }
+ SwLinePortion *pPor = pLay;
+ SwQuoVadisPortion *pQuo = 0;
+ while( pPor && !pQuo )
+ {
+ if ( pPor->IsQuoVadisPortion() )
+ pQuo = (SwQuoVadisPortion*)pPor;
+ pPor = pPor->GetPortion();
+ }
+
+ if( !pQuo )
+ return sal_False;
+
+ return pQuo->GetQuoTxt() == rQuo;
+}
+
+
+
diff --git a/sw/source/core/text/txthyph.cxx b/sw/source/core/text/txthyph.cxx
new file mode 100644
index 000000000000..69b4bef4135a
--- /dev/null
+++ b/sw/source/core/text/txthyph.cxx
@@ -0,0 +1,695 @@
+/*************************************************************************
+ *
+ * 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 <hintids.hxx>
+#include <editeng/unolingu.hxx>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <EnhancedPDFExportHelper.hxx>
+#include <viewopt.hxx> // SwViewOptions
+#include <viewsh.hxx>
+#include <errhdl.hxx>
+#include <txtcfg.hxx>
+#include <SwPortionHandler.hxx>
+#include <porhyph.hxx> //
+#include <inftxt.hxx>
+#include <itrform2.hxx> //
+#include <guess.hxx> //
+#include <splargs.hxx> // SwInterHyphInfo
+
+#ifdef DBG_UTIL
+extern const sal_Char *GetLangName( const MSHORT nLang );
+#endif
+
+using ::rtl::OUString;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::linguistic2;
+using namespace ::com::sun::star::i18n;
+
+/*************************************************************************
+ * SwTxtFormatInfo::HyphWord()
+ *************************************************************************/
+
+Reference< XHyphenatedWord > SwTxtFormatInfo::HyphWord(
+ const XubString &rTxt, const MSHORT nMinTrail )
+{
+ if( rTxt.Len() < 4 || pFnt->IsSymbol(pVsh) )
+ return 0;
+// ASSERT( IsHyphenate(), "SwTxtFormatter::HyphWord: why?" );
+ Reference< XHyphenator > xHyph = ::GetHyphenator();
+ Reference< XHyphenatedWord > xHyphWord;
+
+ if( xHyph.is() )
+ xHyphWord = xHyph->hyphenate( OUString(rTxt),
+ pBreakIt->GetLocale( pFnt->GetLanguage() ),
+ rTxt.Len() - nMinTrail, GetHyphValues() );
+ return xHyphWord;
+
+}
+
+/*************************************************************************
+ * SwTxtFrm::Hyphenate
+ *
+ * Wir formatieren eine Zeile fuer die interaktive Trennung
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::Hyphenate( SwInterHyphInfo &rHyphInf )
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),"swapped frame at SwTxtFrm::Hyphenate" );
+
+ if( !pBreakIt->GetBreakIter().is() )
+ return sal_False;;
+ // Wir machen den Laden erstmal dicht:
+ ASSERT( !IsLocked(), "SwTxtFrm::Hyphenate: this is locked" );
+ // 4935: Der frame::Frame muss eine gueltige SSize haben!
+ Calc();
+ GetFormatted();
+
+ sal_Bool bRet = sal_False;
+ if( !IsEmpty() )
+ {
+ // Wir muessen die Trennung immer einschalten.
+ // Keine Angst, der SwTxtIter sichert im Hyphenate die alte Zeile.
+ SwTxtFrmLocker aLock( this );
+
+ if ( IsVertical() )
+ SwapWidthAndHeight();
+
+ SwTxtFormatInfo aInf( this, sal_True ); // sal_True fuer interactive hyph!
+ SwTxtFormatter aLine( this, &aInf );
+ aLine.CharToLine( rHyphInf.nStart );
+ // Wenn wir innerhalb des ersten Wortes einer Zeile stehen, so koennte
+ // dieses in der vorherigen getrennt werden, deshalb gehen wir ein Zeile
+ // zurueck.
+ if( aLine.Prev() )
+ {
+ SwLinePortion *pPor = aLine.GetCurr()->GetFirstPortion();
+ while( pPor->GetPortion() )
+ pPor = pPor->GetPortion();
+ if( pPor->GetWhichPor() == POR_SOFTHYPH ||
+ pPor->GetWhichPor() == POR_SOFTHYPHSTR )
+ aLine.Next();
+ }
+
+ const xub_StrLen nEnd = rHyphInf.GetEnd();
+ while( !bRet && aLine.GetStart() < nEnd )
+ {
+ DBG_LOOP;
+ bRet = aLine.Hyphenate( rHyphInf );
+ if( !aLine.Next() )
+ break;
+ }
+
+ if ( IsVertical() )
+ SwapWidthAndHeight();
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::Hyphenate
+ *
+ * Wir formatieren eine Zeile fuer die interaktive Trennung
+ *************************************************************************/
+// Wir koennen davon ausgehen, dass bereits formatiert wurde.
+// Fuer die CeBIT'93 gehen wir den einfachen, sicheren Weg:
+// Die Zeile wird einfach neu formatiert, der Hyphenator wird dann
+// so vorbereitet, wie ihn die UI erwartet.
+// Hier stehen natuerlich enorme Optimierungsmoeglichkeiten offen.
+
+void SetParaPortion( SwTxtInfo *pInf, SwParaPortion *pRoot )
+{
+ ASSERT( pRoot, "SetParaPortion: no root anymore" );
+ pInf->pPara = pRoot;
+}
+
+sal_Bool SwTxtFormatter::Hyphenate( SwInterHyphInfo &rHyphInf )
+{
+ SwTxtFormatInfo &rInf = GetInfo();
+ sal_Bool bRet = sal_False;
+
+ // In der letzten Zeile gibt es nie etwas zu trennen.
+ // Es sei denn, es befindet sich eine FlyPortion darin,
+ // oder es ist die letzte Zeile des Masters
+ if( !GetNext() && !rInf.GetTxtFly()->IsOn() && !pFrm->GetFollow() )
+ return bRet;
+
+ xub_StrLen nWrdStart = nStart;
+
+ // Wir muessen die alte Zeile erhalten. Ein Beispiel:
+ // Das Attribut fuer Trennung wurde nicht gesetzt,
+ // in SwTxtFrm::Hyphenate wird es jedoch immer gesetzt,
+ // weil wir Trennpositionen im Hyphenator einstellen wollen.
+ SwLineLayout *pOldCurr = pCurr;
+
+ InitCntHyph();
+
+ // 5298: IsParaLine() (ex.IsFirstLine) fragt auf GetParaPortion() ab.
+ // wir muessen gleiche Bedingungen schaffen: in der ersten
+ // Zeile formatieren wir SwParaPortions...
+ if( pOldCurr->IsParaPortion() )
+ {
+ SwParaPortion *pPara = new SwParaPortion();
+ SetParaPortion( &rInf, pPara );
+ pCurr = pPara;
+ ASSERT( IsParaLine(), "SwTxtFormatter::Hyphenate: not the first" );
+ }
+ else
+ pCurr = new SwLineLayout();
+
+ nWrdStart = FormatLine( nWrdStart );
+
+ // Man muss immer im Hinterkopf behalten, dass es z.B.
+ // Felder gibt, die aufgetrennt werden koennen ...
+ if( pCurr->PrtWidth() && pCurr->GetLen() )
+ {
+ // Wir muessen uns darauf einstellen, dass in der Zeile
+ // FlyFrms haengen, an denen auch umgebrochen werden darf.
+ // Wir suchen also die erste HyphPortion in dem angegebenen
+ // Bereich.
+
+ SwLinePortion *pPos = pCurr->GetPortion();
+ const xub_StrLen nPamStart = rHyphInf.nStart;
+ nWrdStart = nStart;
+ const xub_StrLen nEnd = rHyphInf.GetEnd();
+ while( pPos )
+ {
+ // Entweder wir liegen drueber oder wir laufen gerade auf eine
+ // Hyphportion die am Ende der Zeile oder vor einem Flys steht.
+ if( nWrdStart >= nEnd )
+ {
+ nWrdStart = 0;
+ break;
+ }
+
+ if( nWrdStart >= nPamStart && pPos->InHyphGrp()
+ && ( !pPos->IsSoftHyphPortion()
+ || ((SwSoftHyphPortion*)pPos)->IsExpand() ) )
+ {
+ nWrdStart = nWrdStart + pPos->GetLen();
+ break;
+ }
+
+ nWrdStart = nWrdStart + pPos->GetLen();
+ pPos = pPos->GetPortion();
+ }
+ // Wenn pPos 0 ist, wurde keine Trennstelle ermittelt.
+ if( !pPos )
+ nWrdStart = 0;
+ }
+
+ // Das alte LineLayout wird wieder eingestellt ...
+ delete pCurr;
+ pCurr = pOldCurr;
+
+ if( pOldCurr->IsParaPortion() )
+ {
+ SetParaPortion( &rInf, (SwParaPortion*)pOldCurr );
+ ASSERT( IsParaLine(), "SwTxtFormatter::Hyphenate: even not the first" );
+ }
+
+ if( nWrdStart )
+ {
+ // nWrdStart bezeichnet nun die Position im String, der
+ // fuer eine Trennung zur Debatte steht.
+ // Start() hangelt sich zum End()
+ rHyphInf.nWordStart = nWrdStart;
+
+ xub_StrLen nLen = 0;
+ const xub_StrLen nEnd = nWrdStart;
+
+ // Wir suchen vorwaerts
+ Reference< XHyphenatedWord > xHyphWord;
+
+ Boundary aBound =
+ pBreakIt->GetBreakIter()->getWordBoundary( rInf.GetTxt(), nWrdStart,
+ pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ), WordType::DICTIONARY_WORD, sal_True );
+ nWrdStart = static_cast<xub_StrLen>(aBound.startPos);
+ nLen = static_cast<xub_StrLen>(aBound.endPos - nWrdStart);
+ bRet = 0 != nLen;
+ if( bRet )
+ {
+ XubString aSelTxt( rInf.GetTxt().Copy(nWrdStart, nLen) );
+ xub_StrLen nCnt = 0;
+
+// these things should be handled by the dialog
+// for( xub_StrLen i = 0; i < nLen; ++i )
+// {
+// sal_Unicode cCh = aSelTxt.GetChar(i);
+// if( (CH_TXTATR_BREAKWORD == cCh || CH_TXTATR_INWORD == cCh )
+// && rInf.HasHint( nWrdStart + i ) )
+// {
+// aSelTxt.Erase( i , 1 );
+// nCnt++;
+// --nLen;
+// if( i )
+// --i;
+// }
+// }
+
+ {
+ MSHORT nMinTrail = 0;
+ if( nWrdStart + nLen > nEnd )
+ nMinTrail = nWrdStart + nLen - nEnd - 1;
+
+ //!! rHyphInf.SetHyphWord( ... ) mu??? hier geschehen
+ xHyphWord = rInf.HyphWord( aSelTxt, nMinTrail );
+ bRet = xHyphWord.is();
+ if ( !rHyphInf.IsCheck() && sal_False == bRet )
+ rHyphInf.SetNoLang( sal_True );
+ }
+
+ if( bRet )
+ {
+ rHyphInf.SetHyphWord( xHyphWord );
+ rHyphInf.nWordStart = nWrdStart;
+ rHyphInf.nWordLen = nLen+nCnt;
+ rHyphInf.SetNoLang( sal_False );
+ rHyphInf.SetCheck( sal_True );
+ }
+#ifdef DEBUGGY
+ if( OPTDBG( rInf ) )
+ {
+ ASSERT( aSelTxt == aHyphWord,
+ "!SwTxtFormatter::Hyphenate: different words, different planets" );
+ aDbstream << "Diff: \"" << aSelTxt.GetStr() << "\" != \""
+ << aHyphWord.GetStr() << "\"" << endl;
+ ASSERT( bRet, "!SwTxtFormatter::Hyphenate: three of a perfect pair" );
+ aDbstream << "Hyphenate: ";
+ }
+#endif
+ }
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtPortion::CreateHyphen()
+ *************************************************************************/
+
+sal_Bool SwTxtPortion::CreateHyphen( SwTxtFormatInfo &rInf, SwTxtGuess &rGuess )
+{
+ Reference< XHyphenatedWord > xHyphWord = rGuess.HyphWord();
+
+ ASSERT( !pPortion, "SwTxtPortion::CreateHyphen(): another portion, another planet..." )
+ ASSERT( xHyphWord.is(), "SwTxtPortion::CreateHyphen(): You are lucky! The code is robust here." )
+
+ if( rInf.IsHyphForbud() ||
+ pPortion || // robust
+ !xHyphWord.is() || // more robust
+ // Mehrzeilige Felder duerfen nicht interaktiv getrennt werden.
+ ( rInf.IsInterHyph() && InFldGrp() ) )
+ return sal_False;
+
+ SwHyphPortion *pHyphPor;
+ xub_StrLen nPorEnd;
+ SwTxtSizeInfo aInf( rInf );
+
+ // first case: hyphenated word has alternative spelling
+ if ( xHyphWord->isAlternativeSpelling() )
+ {
+ SvxAlternativeSpelling aAltSpell;
+ aAltSpell = SvxGetAltSpelling( xHyphWord );
+ ASSERT( aAltSpell.bIsAltSpelling, "no alternatve spelling" );
+
+ XubString aAltTxt = aAltSpell.aReplacement;
+ nPorEnd = aAltSpell.nChangedPos + rGuess.BreakStart() - rGuess.FieldDiff();
+ xub_StrLen nTmpLen = 0;
+
+ // soft hyphen at alternative spelling position?
+ if( rInf.GetTxt().GetChar( rInf.GetSoftHyphPos() ) == CHAR_SOFTHYPHEN )
+ {
+ pHyphPor = new SwSoftHyphStrPortion( aAltTxt );
+ nTmpLen = 1;
+ }
+ else {
+ pHyphPor = new SwHyphStrPortion( aAltTxt );
+ }
+
+ // length of pHyphPor is adjusted
+ pHyphPor->SetLen( aAltTxt.Len() + 1 );
+ (SwPosSize&)(*pHyphPor) = pHyphPor->GetTxtSize( rInf );
+ pHyphPor->SetLen( aAltSpell.nChangedLength + nTmpLen );
+ }
+ else
+ {
+ // second case: no alternative spelling
+ SwHyphPortion aHyphPor;
+ aHyphPor.SetLen( 1 );
+
+ static const void* pLastMagicNo = 0;
+ static KSHORT aMiniCacheH = 0, aMiniCacheW = 0;
+ const void* pTmpMagic;
+ MSHORT nFntIdx;
+ rInf.GetFont()->GetMagic( pTmpMagic, nFntIdx, rInf.GetFont()->GetActual() );
+ if( !pLastMagicNo || pLastMagicNo != pTmpMagic ) {
+ pLastMagicNo = pTmpMagic;
+ (SwPosSize&)aHyphPor = aHyphPor.GetTxtSize( rInf );
+ aMiniCacheH = aHyphPor.Height(), aMiniCacheW = aHyphPor.Width();
+ } else {
+ aHyphPor.Height( aMiniCacheH ), aHyphPor.Width( aMiniCacheW );
+ }
+ aHyphPor.SetLen( 0 );
+ pHyphPor = new SwHyphPortion( aHyphPor );
+
+ pHyphPor->SetWhichPor( POR_HYPH );
+
+ // values required for this
+ nPorEnd = xHyphWord->getHyphenPos() + 1 + rGuess.BreakStart()
+ - rGuess.FieldDiff();
+ }
+
+ // portion end must be in front of us
+ // we do not put hyphens at start of line
+ if ( nPorEnd > rInf.GetIdx() ||
+ ( nPorEnd == rInf.GetIdx() && rInf.GetLineStart() != rInf.GetIdx() ) )
+ {
+ aInf.SetLen( nPorEnd - rInf.GetIdx() );
+ pHyphPor->SetAscent( GetAscent() );
+ SetLen( aInf.GetLen() );
+ CalcTxtSize( aInf );
+
+ Insert( pHyphPor );
+
+ short nKern = rInf.GetFont()->CheckKerning();
+ if( nKern )
+ new SwKernPortion( *this, nKern );
+
+ return sal_True;
+ }
+
+ // last exit for the lost
+ delete pHyphPor;
+ BreakCut( rInf, rGuess );
+ return sal_False;
+}
+
+
+/*************************************************************************
+ * virtual SwHyphPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwHyphPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ // --> FME 2004-06-24 #i16816# tagged pdf support
+ const sal_Unicode cChar = rInf.GetVsh() &&
+ rInf.GetVsh()->GetViewOptions()->IsPDFExport() &&
+ SwTaggedPDFHelper::IsExportTaggedPDF( *rInf.GetOut() ) ?
+ 0xad :
+ '-';
+ // <--
+
+ rTxt = cChar;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwHyphPortion::HandlePortion()
+ *************************************************************************/
+
+void SwHyphPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString( '-' );
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
+/*************************************************************************
+ * virtual SwHyphPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwHyphPortion::Format( SwTxtFormatInfo &rInf )
+{
+ const SwLinePortion *pLast = rInf.GetLast();
+ Height( pLast->Height() );
+ SetAscent( pLast->GetAscent() );
+ XubString aTxt;
+
+ if( !GetExpTxt( rInf, aTxt ) )
+ return sal_False;
+
+ PrtWidth( rInf.GetTxtSize( aTxt ).Width() );
+ const sal_Bool bFull = rInf.Width() <= rInf.X() + PrtWidth();
+ if( bFull && !rInf.IsUnderFlow() ) {
+ Truncate();
+ rInf.SetUnderFlow( this );
+ }
+
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwHyphStrPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwHyphStrPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwHyphStrPortion::HandlePortion()
+ *************************************************************************/
+
+void SwHyphStrPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Special( GetLen(), aExpand, GetWhichPor() );
+}
+
+/*************************************************************************
+ * class SwSoftHyphPortion
+ *************************************************************************/
+
+SwLinePortion *SwSoftHyphPortion::Compress() { return this; }
+
+SwSoftHyphPortion::SwSoftHyphPortion() :
+ bExpand(sal_False), nViewWidth(0), nHyphWidth(0)
+{
+ SetLen(1);
+ SetWhichPor( POR_SOFTHYPH );
+}
+
+KSHORT SwSoftHyphPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
+ // Moment errechnet werden:
+ if( !Width() && rInf.OnWin() && rInf.GetOpt().IsSoftHyph() && !IsExpand() )
+ {
+ if( !nViewWidth )
+ ((SwSoftHyphPortion*)this)->nViewWidth
+ = rInf.GetTxtSize( '-' ).Width();
+ }
+ else
+ ((SwSoftHyphPortion*)this)->nViewWidth = 0;
+ return nViewWidth;
+}
+
+/* Faelle:
+ * 1) SoftHyph steht in der Zeile, ViewOpt aus.
+ * -> unsichtbar, Nachbarn unveraendert
+ * 2) SoftHyph steht in der Zeile, ViewOpt an.
+ * -> sichtbar, Nachbarn veraendert
+ * 3) SoftHyph steht am Zeilenende, ViewOpt aus/an.
+ * -> immer sichtbar, Nachbarn unveraendert
+ */
+
+void SwSoftHyphPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ {
+ rInf.DrawViewOpt( *this, POR_SOFTHYPH );
+ SwExpandPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * virtual SwSoftHyphPortion::Format()
+ *************************************************************************/
+
+/* Die endgueltige Breite erhalten wir im FormatEOL().
+ * In der Underflow-Phase stellen wir fest, ob ueberhaupt ein
+ * alternatives Spelling vorliegt. Wenn ja ...
+ *
+ * Fall 1: "Au-to"
+ * 1) {Au}{-}{to}, {to} passt nicht mehr => Underflow
+ * 2) {-} ruft Hyphenate => keine Alternative
+ * 3) FormatEOL() und bFull = sal_True
+ *
+ * Fall 2: "Zuc-ker"
+ * 1) {Zuc}{-}{ker}, {ker} passt nicht mehr => Underflow
+ * 2) {-} ruft Hyphenate => Alternative!
+ * 3) Underflow() und bFull = sal_True
+ * 4) {Zuc} ruft Hyphenate => {Zuk}{-}{ker}
+ */
+
+sal_Bool SwSoftHyphPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_Bool bFull = sal_True;
+
+ // special case for old german spelling
+ if( rInf.IsUnderFlow() )
+ {
+ if( rInf.GetSoftHyphPos() )
+ return sal_True;
+
+ const sal_Bool bHyph = rInf.ChgHyph( sal_True );
+ if( rInf.IsHyphenate() )
+ {
+ rInf.SetSoftHyphPos( rInf.GetIdx() );
+ Width(0);
+ // if the soft hyphend word has an alternative spelling
+ // when hyphenated (old german spelling), the soft hyphen
+ // portion has to trigger an underflow
+ SwTxtGuess aGuess;
+ bFull = rInf.IsInterHyph() ||
+ !aGuess.AlternativeSpelling( rInf, rInf.GetIdx() - 1 );
+ }
+ rInf.ChgHyph( bHyph );
+
+ if( bFull && !rInf.IsHyphForbud() )
+ {
+ rInf.SetSoftHyphPos(0);
+ FormatEOL( rInf );
+ if ( rInf.GetFly() )
+ rInf.GetRoot()->SetMidHyph( sal_True );
+ else
+ rInf.GetRoot()->SetEndHyph( sal_True );
+ }
+ else
+ {
+ rInf.SetSoftHyphPos( rInf.GetIdx() );
+ Truncate();
+ rInf.SetUnderFlow( this );
+ }
+ return sal_True;
+ }
+
+ rInf.SetSoftHyphPos(0);
+ SetExpand( sal_True );
+ bFull = SwHyphPortion::Format( rInf );
+ SetExpand( sal_False );
+ if( !bFull )
+ {
+ // default-maessig besitzen wir keine Breite, aber eine Hoehe
+ nHyphWidth = Width();
+ Width(0);
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwSoftHyphPortion::FormatEOL()
+ *************************************************************************/
+// Format end of Line
+
+void SwSoftHyphPortion::FormatEOL( SwTxtFormatInfo &rInf )
+{
+ if( !IsExpand() )
+ {
+ SetExpand( sal_True );
+ if( rInf.GetLast() == this )
+ rInf.SetLast( FindPrevPortion( rInf.GetRoot() ) );
+
+ // 5964: alte Werte muessen wieder zurueckgesetzt werden.
+ const SwTwips nOldX = rInf.X();
+ const xub_StrLen nOldIdx = rInf.GetIdx();
+ rInf.X( rInf.X() - PrtWidth() );
+ rInf.SetIdx( rInf.GetIdx() - GetLen() );
+ const sal_Bool bFull = SwHyphPortion::Format( rInf );
+ nHyphWidth = Width();
+
+ // 6976: Eine truebe Sache: Wir werden erlaubterweise breiter,
+ // aber gleich wird noch ein Fly verarbeitet, der eine korrekte
+ // X-Position braucht.
+ if( bFull || !rInf.GetFly() )
+ rInf.X( nOldX );
+ else
+ rInf.X( nOldX + Width() );
+ rInf.SetIdx( nOldIdx );
+ }
+}
+
+/*************************************************************************
+ * virtual SwSoftHyphPortion::GetExpTxt()
+ *
+ * Wir expandieren:
+ * - wenn die Sonderzeichen sichtbar sein sollen
+ * - wenn wir am Ende der Zeile stehen.
+ * - wenn wir vor einem (echten/emuliertem) Zeilenumbruch stehen
+ *************************************************************************/
+
+sal_Bool SwSoftHyphPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ if( IsExpand() || ( rInf.OnWin() && rInf.GetOpt().IsSoftHyph() ) ||
+ ( GetPortion() && ( GetPortion()->InFixGrp() ||
+ GetPortion()->IsDropPortion() || GetPortion()->IsLayPortion() ||
+ GetPortion()->IsParaPortion() || GetPortion()->IsBreakPortion() ) ) )
+ {
+ return SwHyphPortion::GetExpTxt( rInf, rTxt );
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * virtual SwSoftHyphPortion::HandlePortion()
+ *************************************************************************/
+
+void SwSoftHyphPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ const String aString( '-' );
+ const USHORT nWhich = ! Width() ?
+ POR_SOFTHYPH_COMP :
+ GetWhichPor();
+ rPH.Special( GetLen(), aString, nWhich );
+}
+
+/*************************************************************************
+ * SwSoftHyphStrPortion::Paint
+ *************************************************************************/
+
+void SwSoftHyphStrPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // Bug oder feature?:
+ // {Zu}{k-}{ker}, {k-} wird grau statt {-}
+ rInf.DrawViewOpt( *this, POR_SOFTHYPH );
+ SwHyphStrPortion::Paint( rInf );
+}
+
+SwSoftHyphStrPortion::SwSoftHyphStrPortion( const XubString &rStr )
+ : SwHyphStrPortion( rStr )
+{
+ SetLen( 1 );
+ SetWhichPor( POR_SOFTHYPHSTR );
+}
+
+
+
diff --git a/sw/source/core/text/txtinit.cxx b/sw/source/core/text/txtinit.cxx
new file mode 100644
index 000000000000..486eb1d3c242
--- /dev/null
+++ b/sw/source/core/text/txtinit.cxx
@@ -0,0 +1,101 @@
+/*************************************************************************
+ *
+ * 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 "errhdl.hxx"
+#include "txtcfg.hxx"
+#include "swcache.hxx"
+#include "fntcache.hxx" // pFntCache ( SwFont/ScrFont-PrtFont Cache )
+#include "swfntcch.hxx" // pSwFontCache ( SwAttrSet/SwFont Cache )
+#include "txtfrm.hxx"
+#include "txtcache.hxx"
+#include "porlay.hxx"
+#include "porglue.hxx"
+#include "porexp.hxx"
+#include "porrst.hxx"
+#include "portab.hxx"
+#include "porfly.hxx"
+#include "portox.hxx"
+#include "porref.hxx"
+#include "porftn.hxx"
+#include "porhyph.hxx"
+#include "pordrop.hxx"
+#include "blink.hxx" // Blink-Manager
+#include "init.hxx" // Deklarationen fuer _TextInit() und _TextFinit()
+#include "txtfly.hxx" // SwContourCache
+#include "dbg_lay.hxx" // Layout Debug Fileausgabe
+
+SwCache *SwTxtFrm::pTxtCache = 0;
+long SwTxtFrm::nMinPrtLine = 0;
+SwContourCache *pContourCache = 0;
+SwDropCapCache *pDropCapCache = 0;
+
+IMPL_FIXEDMEMPOOL_NEWDEL( SwTxtLine, 50, 50 )
+IMPL_FIXEDMEMPOOL_NEWDEL( SwParaPortion, 50, 50 ) //Absaetze
+IMPL_FIXEDMEMPOOL_NEWDEL( SwLineLayout, 150, 150 ) //Zeilen
+IMPL_FIXEDMEMPOOL_NEWDEL( SwHolePortion, 150, 150 ) //z.B. Blanks am Zeilenende
+IMPL_FIXEDMEMPOOL_NEWDEL( SwTxtPortion, 200, 100 ) //Attributwechsel
+
+/*************************************************************************
+ * _TextInit(), _TextFinit()
+ *************************************************************************/
+
+// Werden _nur_ in init.cxx verwendet, dort stehen extern void _TextFinit()
+// und extern void _TextInit(...)
+
+void _TextInit()
+{
+ pFntCache = new SwFntCache; // Cache for SwSubFont -> SwFntObj = { Font aFont, Font* pScrFont, Font* pPrtFont, OutputDevice* pPrinter, ... }
+ pSwFontCache = new SwFontCache; // Cache for SwTxtFmtColl -> SwFontObj = { SwFont aSwFont, SfxPoolItem* pDefaultArray }
+ SwCache *pTxtCache = new SwCache( 250, 100 // Cache for SwTxtFrm -> SwTxtLine = { SwParaPortion* pLine }
+#ifdef DBG_UTIL
+ , "static SwTxtFrm::pTxtCache"
+#endif
+ );
+ SwTxtFrm::SetTxtCache( pTxtCache );
+ pWaveCol = new Color( COL_GRAY );
+ PROTOCOL_INIT
+}
+
+void _TextFinit()
+{
+ PROTOCOL_STOP
+ delete SwTxtFrm::GetTxtCache();
+ delete pSwFontCache;
+ delete pFntCache;
+ delete pBlink;
+ delete pWaveCol;
+ delete pContourCache;
+ SwDropPortion::DeleteDropCapCache();
+}
+
+
+
diff --git a/sw/source/core/text/txtio.cxx b/sw/source/core/text/txtio.cxx
new file mode 100644
index 000000000000..b1996905935f
--- /dev/null
+++ b/sw/source/core/text/txtio.cxx
@@ -0,0 +1,949 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+#ifndef DBG_UTIL
+#error Wer fummelt denn an den makefiles?
+#endif
+
+#include "viewsh.hxx" // IsDbg()
+#include "viewopt.hxx" // IsDbg()
+#include "txtatr.hxx"
+#include "errhdl.hxx"
+#include "txtcfg.hxx"
+#include "txtfrm.hxx" // IsDbg()
+#include "flyfrms.hxx"
+#include "inftxt.hxx"
+#include "porexp.hxx"
+#include "porfld.hxx"
+#include "porfly.hxx"
+#include "porftn.hxx"
+#include "porglue.hxx"
+#include "porhyph.hxx"
+#include "porlay.hxx"
+#include "porlin.hxx"
+#include "porref.hxx"
+#include "porrst.hxx"
+#include "portab.hxx"
+#include "portox.hxx"
+#include "portxt.hxx"
+#include "pordrop.hxx"
+#include "pormulti.hxx"
+#include "ndhints.hxx"
+
+// So kann man die Layoutstruktur ausgeben lassen
+// #define AMA_LAYOUT
+#ifdef AMA_LAYOUT
+#include <stdio.h>
+#include <stdlib.h> // getenv()
+#include <flowfrm.hxx>
+#include <pagefrm.hxx>
+#include <svx/svdobj.hxx>
+#include <dflyobj.hxx>
+
+
+void lcl_OutFollow( XubString &rTmp, const SwFrm* pFrm )
+{
+ if( pFrm->IsFlowFrm() )
+ {
+ const SwFlowFrm *pFlow = SwFlowFrm::CastFlowFrm( pFrm );
+ if( pFlow->IsFollow() || pFlow->GetFollow() )
+ {
+ rTmp += "(";
+ if( pFlow->IsFollow() )
+ rTmp += ".";
+ if( pFlow->GetFollow() )
+ {
+ MSHORT nFrmId = pFlow->GetFollow()->GetFrm()->GetFrmId();
+ rTmp += nFrmId;
+ }
+ rTmp += ")";
+ }
+ }
+}
+
+void lcl_OutFrame( SvFileStream& rStr, const SwFrm* pFrm, ByteString& rSp, sal_Bool bNxt )
+{
+ if( !pFrm )
+ return;
+ KSHORT nSpc = 0;
+ MSHORT nFrmId = pFrm->GetFrmId();
+ ByteString aTmp;
+ if( pFrm->IsLayoutFrm() )
+ {
+ if( pFrm->IsRootFrm() )
+ aTmp = "R";
+ else if( pFrm->IsPageFrm() )
+ aTmp = "P";
+ else if( pFrm->IsBodyFrm() )
+ aTmp = "B";
+ else if( pFrm->IsColumnFrm() )
+ aTmp = "C";
+ else if( pFrm->IsTabFrm() )
+ aTmp = "Tb";
+ else if( pFrm->IsRowFrm() )
+ aTmp = "Rw";
+ else if( pFrm->IsCellFrm() )
+ aTmp = "Ce";
+ else if( pFrm->IsSctFrm() )
+ aTmp = "S";
+ else if( pFrm->IsFlyFrm() )
+ {
+ aTmp = "F";
+ const SwFlyFrm *pFly = (SwFlyFrm*)pFrm;
+ if( pFly->IsFlyInCntFrm() )
+ aTmp += "in";
+ else if( pFly->IsFlyAtCntFrm() )
+ {
+ aTmp += "a";
+ if( pFly->IsAutoPos() )
+ aTmp += "u";
+ else
+ aTmp += "t";
+ }
+ else
+ aTmp += "l";
+ }
+ else if( pFrm->IsHeaderFrm() )
+ aTmp = "H";
+ else if( pFrm->IsFooterFrm() )
+ aTmp = "Fz";
+ else if( pFrm->IsFtnContFrm() )
+ aTmp = "Fc";
+ else if( pFrm->IsFtnFrm() )
+ aTmp = "Fn";
+ else
+ aTmp = "?L?";
+ aTmp += nFrmId;
+ lcl_OutFollow( aTmp, pFrm );
+ aTmp += " ";
+ rStr << aTmp;
+ nSpc = aTmp.Len();
+ rSp.Expand( nSpc + rSp.Len() );
+ lcl_OutFrame( rStr, ((SwLayoutFrm*)pFrm)->Lower(), rSp, sal_True );
+ }
+ else
+ {
+ if( pFrm->IsTxtFrm() )
+ aTmp = "T";
+ else if( pFrm->IsNoTxtFrm() )
+ aTmp = "N";
+ else
+ aTmp = "?C?";
+ aTmp += nFrmId;
+ lcl_OutFollow( aTmp, pFrm );
+ aTmp += " ";
+ rStr << aTmp;
+ nSpc = aTmp.Len();
+ rSp.Expand( nSpc + rSp.Len() );
+ }
+ if( pFrm->IsPageFrm() )
+ {
+ const SwPageFrm* pPg = (SwPageFrm*)pFrm;
+ const SwSortedObjs *pSorted = pPg->GetSortedObjs();
+ const MSHORT nCnt = pSorted ? pSorted->Count() : 0;
+ if( nCnt )
+ {
+ for( MSHORT i=0; i < nCnt; ++i )
+ {
+ // --> OD 2004-07-07 #i28701# - consider changed type of
+ // <SwSortedObjs> entries
+ SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
+ if( pAnchoredObj->ISA(SwFlyFrm) )
+ {
+ SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
+ lcl_OutFrame( rStr, pFly, rSp, sal_False );
+ }
+ else
+ {
+ aTmp = pAnchoredObj->GetDrawObj()->IsUnoObj() ? "UNO" : "Drw";
+ rStr << aTmp;
+ }
+ // <--
+ if( i < nCnt - 1 )
+ rStr << endl << rSp;
+ }
+ }
+ }
+ else if( pFrm->GetDrawObjs() )
+ {
+ MSHORT nCnt = pFrm->GetDrawObjs()->Count();
+ if( nCnt )
+ {
+ for( MSHORT i=0; i < nCnt; ++i )
+ {
+ // --> OD 2004-07-07 #i28701# - consider changed type of
+ // <SwSortedObjs> entries
+ SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[ i ];
+ if( pAnchoredObj->ISA(SwFlyFrm) )
+ {
+ SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
+ lcl_OutFrame( rStr, pFly, rSp, sal_False );
+ }
+ else
+ {
+ aTmp = pAnchoredObj->GetDrawObj()->IsUnoObj() ? "UNO" : "Drw";
+ rStr << aTmp;
+ }
+ if( i < nCnt - 1 )
+ rStr << endl << rSp;
+ }
+ }
+ }
+ if( nSpc )
+ rSp.Erase( rSp.Len() - nSpc );
+ if( bNxt && pFrm->GetNext() )
+ {
+ do
+ {
+ pFrm = pFrm->GetNext();
+ rStr << endl << rSp;
+ lcl_OutFrame( rStr, pFrm, rSp, sal_False );
+ } while ( pFrm->GetNext() );
+ }
+}
+
+void LayOutPut( const SwFrm* pFrm )
+{
+ static char* pOutName = 0;
+ const sal_Bool bFirstOpen = pOutName ? sal_False : sal_True;
+ if( bFirstOpen )
+ {
+ char *pPath = getenv( "TEMP" );
+ char *pName = "layout.txt";
+ if( !pPath )
+ pOutName = pName;
+ else
+ {
+ const int nLen = strlen(pPath);
+ // fuer dieses new wird es kein delete geben.
+ pOutName = new char[nLen + strlen(pName) + 3];
+ if(nLen && (pPath[nLen-1] == '\\') || (pPath[nLen-1] == '/'))
+ snprintf( pOutName, sizeof(pOutName), "%s%s", pPath, pName );
+ else
+ snprintf( pOutName, sizeof(pOutName), "%s/%s", pPath, pName );
+ }
+ }
+ SvFileStream aStream( pOutName, (bFirstOpen
+ ? STREAM_WRITE | STREAM_TRUNC
+ : STREAM_WRITE ));
+
+ if( !aStream.GetError() )
+ {
+ if ( bFirstOpen )
+ aStream << "Layout-Struktur";
+ else
+ aStream.Seek( STREAM_SEEK_TO_END );
+ aStream << endl;
+ aStream << "---------------------------------------------" << endl;
+ XubString aSpace;
+ lcl_OutFrame( aStream, pFrm, aSpace, sal_False );
+ }
+}
+
+#endif
+
+SvStream &operator<<( SvStream &rOs, const SwpHints & ) //$ ostream
+{
+ rOs << " {HINTS:";
+
+// REMOVED
+
+ rOs << '}';
+ return rOs;
+}
+
+/*************************************************************************
+ * IsDbg()
+ *************************************************************************/
+
+sal_Bool IsDbg( const SwTxtFrm *pFrm )
+{
+ if( pFrm && pFrm->GetShell() )
+ return pFrm->GetShell()->GetViewOptions()->IsTest4();
+ else
+ return sal_False;
+}
+
+#if OSL_DEBUG_LEVEL < 2
+
+static void Error()
+{
+ // wegen PM und BCC
+ sal_Bool bFalse = sal_False;
+ ASSERT( bFalse, "txtio: No debug version" );
+}
+
+#define IMPL_OUTOP(class) \
+ SvStream &class::operator<<( SvStream &rOs ) const /*$ostream*/\
+ { \
+ Error(); \
+ return rOs; \
+ }
+
+IMPL_OUTOP( SwTxtPortion )
+IMPL_OUTOP( SwLinePortion )
+IMPL_OUTOP( SwBreakPortion )
+IMPL_OUTOP( SwGluePortion )
+IMPL_OUTOP( SwFldPortion )
+IMPL_OUTOP( SwHiddenPortion )
+IMPL_OUTOP( SwHyphPortion )
+IMPL_OUTOP( SwFixPortion )
+IMPL_OUTOP( SwFlyPortion )
+IMPL_OUTOP( SwFlyCntPortion )
+IMPL_OUTOP( SwMarginPortion )
+IMPL_OUTOP( SwNumberPortion )
+IMPL_OUTOP( SwBulletPortion )
+IMPL_OUTOP( SwGrfNumPortion )
+IMPL_OUTOP( SwLineLayout )
+IMPL_OUTOP( SwParaPortion )
+IMPL_OUTOP( SwFtnPortion )
+IMPL_OUTOP( SwFtnNumPortion )
+IMPL_OUTOP( SwTmpEndPortion )
+IMPL_OUTOP( SwHyphStrPortion )
+IMPL_OUTOP( SwExpandPortion )
+IMPL_OUTOP( SwBlankPortion )
+IMPL_OUTOP( SwToxPortion )
+IMPL_OUTOP( SwRefPortion )
+IMPL_OUTOP( SwIsoToxPortion )
+IMPL_OUTOP( SwIsoRefPortion )
+IMPL_OUTOP( SwSoftHyphPortion )
+IMPL_OUTOP( SwSoftHyphStrPortion )
+IMPL_OUTOP( SwTabPortion )
+IMPL_OUTOP( SwTabLeftPortion )
+IMPL_OUTOP( SwTabRightPortion )
+IMPL_OUTOP( SwTabCenterPortion )
+IMPL_OUTOP( SwTabDecimalPortion )
+IMPL_OUTOP( SwPostItsPortion )
+IMPL_OUTOP( SwQuoVadisPortion )
+IMPL_OUTOP( SwErgoSumPortion )
+IMPL_OUTOP( SwHolePortion )
+IMPL_OUTOP( SwDropPortion )
+IMPL_OUTOP( SwKernPortion )
+IMPL_OUTOP( SwArrowPortion )
+IMPL_OUTOP( SwMultiPortion )
+IMPL_OUTOP( SwCombinedPortion )
+
+const char *GetPortionName( const MSHORT )
+{
+ return 0;
+}
+
+const char *GetPrepName( const PrepareHint )
+{
+ return 0;
+}
+
+void SwLineLayout::DebugPortions( SvStream &, const XubString &, //$ ostream
+ const xub_StrLen )
+{
+}
+
+const char *GetLangName( const MSHORT )
+{
+ return 0;
+}
+
+#else
+# include <limits.h>
+# include <stdlib.h>
+# include "swtypes.hxx" // ZTCCONST
+# include "swfont.hxx" // SwDropPortion
+
+CONSTCHAR( pClose, "} " );
+
+/*************************************************************************
+ * GetPortionName()
+ *************************************************************************/
+
+CONSTCHAR( pPOR_LIN, "LIN" );
+CONSTCHAR( pPOR_TXT, "TXT" );
+CONSTCHAR( pPOR_SHADOW, "SHADOW" );
+CONSTCHAR( pPOR_TAB, "TAB" );
+CONSTCHAR( pPOR_TABLEFT, "TABLEFT" );
+CONSTCHAR( pPOR_TABRIGHT, "TABRIGHT" );
+CONSTCHAR( pPOR_TABCENTER, "TABCENTER" );
+CONSTCHAR( pPOR_TABDECIMAL, "TABDECIMAL" );
+CONSTCHAR( pPOR_EXP, "EXP" );
+CONSTCHAR( pPOR_HYPH, "HYPH" );
+CONSTCHAR( pPOR_HYPHSTR, "HYPHSTR" );
+CONSTCHAR( pPOR_FLD, "FLD" );
+CONSTCHAR( pPOR_FIX, "FIX" );
+CONSTCHAR( pPOR_FLY, "FLY" );
+CONSTCHAR( pPOR_FLYCNT, "FLYCNT" );
+CONSTCHAR( pPOR_MARGIN, "MARGIN" );
+CONSTCHAR( pPOR_GLUE, "GLUE" );
+CONSTCHAR( pPOR_HOLE, "HOLE" );
+CONSTCHAR( pPOR_END, "END" );
+CONSTCHAR( pPOR_BRK, "BRK" );
+CONSTCHAR( pPOR_LAY, "LAY" );
+CONSTCHAR( pPOR_BLANK, "BLANK" );
+CONSTCHAR( pPOR_FTN, "FTN" );
+CONSTCHAR( pPOR_FTNNUM, "FTNNUM" );
+CONSTCHAR( pPOR_POSTITS, "POSTITS" );
+CONSTCHAR( pPOR_SOFTHYPH, "SOFTHYPH" );
+CONSTCHAR( pPOR_SOFTHYPHSTR, "SOFTHYPHSTR" );
+CONSTCHAR( pPOR_TOX, "TOX" );
+CONSTCHAR( pPOR_REF, "REF" );
+
+CONSTCHAR( pPOR_ISOTOX, "ISOTOX" );
+CONSTCHAR( pPOR_ISOREF, "ISOREF" );
+CONSTCHAR( pPOR_HIDDEN, "Hidden" );
+CONSTCHAR( pPOR_QUOVADIS, "QuoVadis" );
+CONSTCHAR( pPOR_ERGOSUM, "ErgoSum" );
+CONSTCHAR( pPOR_NUMBER, "NUMBER" );
+CONSTCHAR( pPOR_BULLET, "BULLET" );
+CONSTCHAR( pPOR_UNKW, "UNKW" );
+CONSTCHAR( pPOR_PAR, "PAR" );
+
+const char *GetPortionName( const MSHORT /*nType*/ )
+{
+ return 0;
+}
+
+CONSTCHAR( pPREP_CLEAR, "CLEAR" );
+CONSTCHAR( pPREP_WIDOWS_ORPHANS, "WIDOWS_ORPHANS" );
+CONSTCHAR( pPREP_FIXSIZE_CHG, "FIXSIZE_CHG" );
+CONSTCHAR( pPREP_FOLLOW_FOLLOWS, "FOLLOW_FOLLOWS" );
+CONSTCHAR( pPREP_ADJUST_FRM, "ADJUST_FRM" );
+CONSTCHAR( pPREP_FREE_SPACE, "FREE_SPACE" );
+CONSTCHAR( pPREP_FLY_CHGD, "FLY_CHGD" );
+CONSTCHAR( pPREP_FLY_ATTR_CHG, "FLY_ATTR_CHG" );
+CONSTCHAR( pPREP_FLY_ARRIVE, "FLY_ARRIVE" );
+CONSTCHAR( pPREP_FLY_LEAVE, "FLY_LEAVE" );
+CONSTCHAR( pPREP_VIEWOPT, "VIEWOPT" );
+CONSTCHAR( pPREP_FTN, "FTN" );
+CONSTCHAR( pPREP_POS_CHGD, "POS" );
+CONSTCHAR( pPREP_UL_SPACE, "UL_SPACE" );
+CONSTCHAR( pPREP_MUST_FIT, "MUST_FIT" );
+CONSTCHAR( pPREP_WIDOWS, "ORPHANS" );
+CONSTCHAR( pPREP_QUOVADIS, "QUOVADIS" );
+CONSTCHAR( pPREP_PAGE, "PAGE" );
+
+const char *GetPrepName( const PrepareHint ePrep )
+{
+ // Kurz und schmerzlos:
+ const char *ppNameArr[PREP_END] =
+ {
+ pPREP_CLEAR, pPREP_WIDOWS_ORPHANS, pPREP_FIXSIZE_CHG,
+ pPREP_FOLLOW_FOLLOWS, pPREP_ADJUST_FRM, pPREP_FREE_SPACE,
+ pPREP_FLY_CHGD, pPREP_FLY_ATTR_CHG, pPREP_FLY_ARRIVE,
+ pPREP_FLY_LEAVE, pPREP_VIEWOPT, pPREP_FTN, pPREP_POS_CHGD,
+ pPREP_UL_SPACE, pPREP_MUST_FIT, pPREP_WIDOWS, pPREP_QUOVADIS,
+ pPREP_PAGE
+ };
+ ASSERT( ePrep < PREP_END, "GetPrepName: unknown PrepareHint" );
+ return( ppNameArr[ePrep] );
+}
+
+/*************************************************************************
+ * SwLineLayout::DebugPortions()
+ *
+ * DebugPortion() iteriert ueber alle Portions einer Zeile und deckt die
+ * internen Strukturen auf.
+ * Im Gegensatz zum Ausgabe-Operator werden auch die Textteile ausgegeben.
+ *************************************************************************/
+
+void SwLineLayout::DebugPortions( SvStream &rOs, const XubString &/*rTxt*/, //$ ostream
+ const xub_StrLen /*nStart*/ )
+{
+ SwLinePortion *pPortion2 = GetPortion();
+
+ xub_StrLen nPos = 0;
+ MSHORT nNr = 0;
+ KSHORT nPrtWidth, nLastPrt;
+ nPrtWidth = nLastPrt = 0;
+
+ SwLinePortion::operator<<( rOs );
+ rOs << '\"' << endl;
+
+ while( pPortion2 )
+ {
+ DBG_LOOP;
+ SwTxtPortion *pTxtPor = pPortion2->InTxtGrp() ?
+ (SwTxtPortion *)pPortion2 : NULL ;
+ (void)pTxtPor;
+ ++nNr;
+ nLastPrt = nPrtWidth;
+ nPrtWidth = nPrtWidth + pPortion2->PrtWidth();
+ rOs << "\tNr:" << nNr
+ << " Pos:" << nPos
+ << " Org:" << nLastPrt
+ << endl;
+
+ rOs << "\t";
+ pPortion2->operator<<( rOs );
+ rOs << endl;
+ nPos = nPos + pPortion2->GetLen();
+ pPortion2 = pPortion2->GetPortion();
+ }
+}
+
+const char *GetLangName( const MSHORT /*nLang*/ )
+{
+ return "???";
+}
+
+SvStream &SwLinePortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ rOs << " {";
+ rOs << "L:" << nLineLength;
+ rOs << " H:" << Height();
+ rOs << " W:" << PrtWidth();
+ rOs << " A:" << nAscent;
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTxtPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TXT:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTmpEndPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {END:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ if( PrtWidth() )
+ rOs << "(view)";
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwBreakPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {BREAK:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwKernPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {KERN:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwArrowPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {ARROW:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwMultiPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {MULTI:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwCombinedPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {COMBINED:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwLineLayout::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {LINE:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ SwLinePortion *pPos = GetPortion();
+ while( pPos )
+ {
+ DBG_LOOP;
+ rOs << "\t";
+ pPos->operator<<( rOs );
+ pPos = pPos->GetPortion();
+ }
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwGluePortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {GLUE:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << " F:" << GetFixWidth();
+ rOs << " G:" << GetPrtGlue();
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwFixPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {FIX:" );
+ rOs << pTxt;
+ SwGluePortion::operator<<( rOs );
+ rOs << " Fix:" << nFix;
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwFlyPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {FLY:" );
+ rOs << pTxt;
+ SwFixPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwMarginPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {MAR:" );
+ rOs << pTxt;
+ SwGluePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwFlyCntPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {FLYCNT:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ if( bDraw )
+ {
+ CONSTCHAR( pTxt2, " {DRAWINCNT" );
+ rOs << pTxt2;
+ rOs << pClose;
+ }
+ else
+ {
+ CONSTCHAR( pTxt2, " {FRM:" );
+ rOs << pTxt2;
+ rOs << " {FRM:" << GetFlyFrm()->Frm() << pClose;
+ rOs << " {PRT:" << GetFlyFrm()->Prt() << pClose;
+ rOs << pClose;
+ }
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwExpandPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {EXP:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwFtnPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {FTN:" );
+ rOs << pTxt;
+ SwExpandPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwFtnNumPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {FTNNUM:" );
+ rOs << pTxt;
+ SwNumberPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwNumberPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {NUMBER:" );
+ rOs << pTxt;
+ SwExpandPortion::operator<<( rOs );
+ rOs << " Exp:\"" << '\"';
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwBulletPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {BULLET:" );
+ rOs << pTxt;
+ SwNumberPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwGrfNumPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {GRFNUM:" );
+ rOs << pTxt;
+ SwNumberPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwHiddenPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {Hidden:" );
+ rOs << pTxt;
+ SwFldPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwToxPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TOX:" );
+ rOs << pTxt;
+ SwTxtPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwRefPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {Ref:" );
+ rOs << pTxt;
+ SwTxtPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwIsoToxPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {ISOTOX:" );
+ rOs << pTxt;
+ SwToxPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwIsoRefPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {ISOREF:" );
+ rOs << pTxt;
+ SwRefPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwHyphPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {HYPH:" );
+ rOs << pTxt;
+ SwExpandPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwHyphStrPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {HYPHSTR:" );
+ rOs << pTxt;
+ SwExpandPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwSoftHyphPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {SOFTHYPH:" );
+ rOs << pTxt;
+ SwHyphPortion::operator<<( rOs );
+ rOs << (IsExpand() ? " on" : " off");
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwSoftHyphStrPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {SOFTHYPHSTR:" );
+ rOs << pTxt;
+ SwHyphStrPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwBlankPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {BLANK:" );
+ rOs << pTxt;
+ SwExpandPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwFldPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {FLD:" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ if( IsFollow() )
+ rOs << " F!";
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwPostItsPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {POSTITS" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTabPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TAB" );
+ rOs << pTxt;
+ SwFixPortion::operator<<( rOs );
+ rOs << " T:" << nTabPos;
+ if( IsFilled() )
+ rOs << " \"" << cFill << '\"';
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTabLeftPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TABLEFT" );
+ rOs << pTxt;
+ SwTabPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTabRightPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TABRIGHT" );
+ rOs << pTxt;
+ SwTabPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTabCenterPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TABCENTER" );
+ rOs << pTxt;
+ SwTabPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwTabDecimalPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {TABDECIMAL" );
+ rOs << pTxt;
+ SwTabPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwParaPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {PAR" );
+ rOs << pTxt;
+ SwLineLayout::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwHolePortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {HOLE" );
+ rOs << pTxt;
+ SwLinePortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwQuoVadisPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {QUOVADIS" );
+ rOs << pTxt;
+ SwFldPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwErgoSumPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {ERGOSUM" );
+ rOs << pTxt;
+ SwFldPortion::operator<<( rOs );
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &operator<<( SvStream &rOs, const SwTxtSizeInfo &rInf ) //$ ostream
+{
+ CONSTCHAR( pTxt, " {SIZEINFO:" );
+ rOs << pTxt;
+ rOs << ' ' << (rInf.OnWin() ? "WIN:" : "PRT:" );
+ rOs << " Idx:" << rInf.GetIdx();
+ rOs << " Len:" << rInf.GetLen();
+ rOs << pClose;
+ return rOs;
+}
+
+SvStream &SwDropPortion::operator<<( SvStream &rOs ) const //$ ostream
+{
+ CONSTCHAR( pTxt, " {DROP:" );
+ rOs << pTxt;
+ SwTxtPortion::operator<<( rOs );
+ if( pPart && nDropHeight )
+ {
+ rOs << " H:" << nDropHeight;
+ rOs << " L:" << nLines;
+ rOs <<" Fnt:" << pPart->GetFont().GetHeight();
+ if( nX || nY )
+ rOs << " [" << nX << '/' << nY << ']';
+ }
+ rOs << pClose;
+ return rOs;
+}
+
+#endif /* OSL_DEBUG_LEVEL */
+
+
diff --git a/sw/source/core/text/txtpaint.cxx b/sw/source/core/text/txtpaint.cxx
new file mode 100644
index 000000000000..efb05c0b836b
--- /dev/null
+++ b/sw/source/core/text/txtpaint.cxx
@@ -0,0 +1,137 @@
+/*************************************************************************
+ *
+ * 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 "txtpaint.hxx"
+#include "swrect.hxx"
+#include "rootfrm.hxx"
+
+/*************************************************************************
+ * SwSaveClip::Reset()
+ *************************************************************************/
+
+void SwSaveClip::Reset()
+{
+ // Der alte Zustand wird wieder hergestellt.
+ if( pOut && bChg )
+ {
+ if ( pOut->GetConnectMetaFile() )
+ pOut->Pop();
+ else
+ {
+ if( bOn )
+ pOut->SetClipRegion( aClip );
+ else
+ pOut->SetClipRegion();
+ }
+ bChg = sal_False;
+ }
+}
+
+/*************************************************************************
+ * SwSaveClip::_ChgClip()
+ *************************************************************************/
+
+void SwSaveClip::_ChgClip( const SwRect &rRect, const SwTxtFrm* pFrm,
+ sal_Bool bEnlargeRect )
+{
+ SwRect aOldRect( rRect );
+ const sal_Bool bVertical = pFrm && pFrm->IsVertical();
+
+ if ( pFrm && pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( (SwRect&)rRect );
+
+ if ( bVertical )
+ pFrm->SwitchHorizontalToVertical( (SwRect&)rRect );
+
+ if ( !pOut || (!rRect.HasArea() && !pOut->IsClipRegion()) )
+ {
+ (SwRect&)rRect = aOldRect;
+ return;
+ }
+
+ if ( !bChg )
+ {
+ if ( pOut->GetConnectMetaFile() )
+ pOut->Push();
+ else if ( bOn )
+ aClip = pOut->GetClipRegion();
+ }
+
+ if ( !rRect.HasArea() )
+ pOut->SetClipRegion();
+ else
+ {
+ Rectangle aRect( rRect.SVRect() );
+
+ // Having underscores in our line, we enlarged the repaint area
+ // (see frmform.cxx) because for some fonts it could be too small.
+ // Consequently, we have to enlarge the clipping rectangle as well.
+ if ( bEnlargeRect && ! bVertical )
+ aRect.Bottom() += 40;
+
+ // Wenn das ClipRect identisch ist, passiert nix.
+ if( pOut->IsClipRegion() ) // kein && wg Mac
+ {
+ if ( aRect == pOut->GetClipRegion().GetBoundRect() )
+ {
+ (SwRect&)rRect = aOldRect;
+ return;
+ }
+ }
+
+ if( SwRootFrm::HasSameRect( rRect ) )
+ pOut->SetClipRegion();
+ else
+ {
+ const Region aClipRegion( aRect );
+ pOut->SetClipRegion( aClipRegion );
+#if OSL_DEBUG_LEVEL > 1
+ Rectangle aDbgRect = pOut->GetClipRegion().GetBoundRect();
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+#ifdef DBG_UTIL
+ static sal_Bool bDbg = sal_False;
+ if( bDbg )
+ {
+ DbgBackColor aDbg( pOut, bDbg, COL_RED );
+ pOut->DrawRect( aRect );
+ }
+#endif
+#endif
+ }
+ bChg = sal_True;
+
+ (SwRect&)rRect = aOldRect;
+}
+
+
diff --git a/sw/source/core/text/txtpaint.hxx b/sw/source/core/text/txtpaint.hxx
new file mode 100644
index 000000000000..37fbd6a9ac39
--- /dev/null
+++ b/sw/source/core/text/txtpaint.hxx
@@ -0,0 +1,191 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _TXTPAINT_HXX
+#define _TXTPAINT_HXX
+#include <vcl/outdev.hxx>
+
+class SwRect; // SwSaveClip
+#include <txtfrm.hxx>
+
+/*************************************************************************
+ * class SwSaveClip
+ *************************************************************************/
+
+class SwSaveClip
+{
+ Region aClip;
+ const sal_Bool bOn;
+ sal_Bool bChg;
+protected:
+ OutputDevice* pOut;
+ void _ChgClip( const SwRect &rRect, const SwTxtFrm* pFrm,
+ sal_Bool bEnlargeRect );
+public:
+ inline SwSaveClip( OutputDevice* pOut );
+ inline ~SwSaveClip();
+ inline void ChgClip( const SwRect &rRect, const SwTxtFrm* pFrm = 0,
+ sal_Bool bEnlargeRect = sal_False)
+ { if( pOut ) _ChgClip( rRect, pFrm, bEnlargeRect ); }
+ void Reset();
+ inline sal_Bool IsOn() const { return bOn; }
+ inline sal_Bool IsChg() const { return bChg; }
+ inline sal_Bool IsOut() const { return 0 != pOut; }
+ inline OutputDevice *GetOut() { return pOut; }
+};
+
+inline SwSaveClip::SwSaveClip( OutputDevice* pOutDev ) :
+ bOn( pOutDev && pOutDev->IsClipRegion() ),
+ bChg( sal_False ),
+ pOut(pOutDev)
+{}
+
+inline SwSaveClip::~SwSaveClip()
+{
+ Reset();
+}
+
+#ifdef DBG_UTIL
+
+/*************************************************************************
+ * class SwDbgOut
+ *************************************************************************/
+
+class SwDbgOut
+{
+protected:
+ OutputDevice* pOut;
+public:
+ inline SwDbgOut( OutputDevice* pOutDev, const sal_Bool bOn = sal_True );
+};
+
+/*************************************************************************
+ * class DbgColor
+ *************************************************************************/
+
+class DbgColor
+{
+ Font *pFnt;
+ Color aColor;
+public:
+ inline DbgColor( Font *pFont, const sal_Bool bOn = sal_True,
+ const ColorData eColor = COL_BLUE );
+ inline ~DbgColor();
+};
+
+/*************************************************************************
+ * class DbgBrush
+ *************************************************************************/
+
+class DbgBackColor : public SwDbgOut
+{
+ Color aOldFillColor;
+public:
+ DbgBackColor( OutputDevice* pOut, const sal_Bool bOn = sal_True,
+ ColorData nColor = COL_YELLOW );
+ ~DbgBackColor();
+};
+
+/*************************************************************************
+ * class DbgRect
+ *************************************************************************/
+
+class DbgRect : public SwDbgOut
+{
+public:
+ DbgRect( OutputDevice* pOut, const Rectangle &rRect,
+ const sal_Bool bOn = sal_True,
+ ColorData eColor = COL_LIGHTBLUE );
+};
+
+/*************************************************************************
+ * Inline-Implementierung
+ *************************************************************************/
+
+inline SwDbgOut::SwDbgOut( OutputDevice* pOutDev, const sal_Bool bOn )
+ :pOut( bOn ? pOutDev : 0 )
+{ }
+
+
+inline DbgColor::DbgColor( Font *pFont, const sal_Bool bOn,
+ const ColorData eColor )
+ :pFnt( bOn ? pFont : 0 )
+{
+ if( pFnt )
+ {
+ aColor = pFnt->GetColor();
+ pFnt->SetColor( Color( eColor ) );
+ }
+}
+
+inline DbgColor::~DbgColor()
+{
+ if( pFnt )
+ pFnt->SetColor( aColor );
+}
+
+inline DbgBackColor::DbgBackColor( OutputDevice* pOutDev, const sal_Bool bOn,
+ ColorData eColor )
+ :SwDbgOut( pOutDev, bOn )
+{
+ if( pOut )
+ {
+ aOldFillColor = pOut->GetFillColor();
+ pOut->SetFillColor( Color(eColor) );
+ }
+}
+
+inline DbgBackColor::~DbgBackColor()
+{
+ if( pOut )
+ {
+ pOut->SetFillColor( aOldFillColor );
+ }
+}
+
+inline DbgRect::DbgRect( OutputDevice* pOutDev, const Rectangle &rRect,
+ const sal_Bool bOn,
+ ColorData eColor )
+ : SwDbgOut( pOutDev, bOn )
+{
+ if( pOut )
+ {
+ const Color aColor( eColor );
+ Color aLineColor = pOut->GetLineColor();
+ pOut->SetLineColor( aColor );
+ Color aFillColor = pOut->GetFillColor();
+ pOut->SetFillColor( Color(COL_TRANSPARENT) );
+ pOut->DrawRect( rRect );
+ pOut->SetLineColor( aLineColor );
+ pOut->SetFillColor( aFillColor );
+ }
+}
+
+#endif
+
+
+
+#endif
diff --git a/sw/source/core/text/txttab.cxx b/sw/source/core/text/txttab.cxx
new file mode 100644
index 000000000000..5c1598c4db0b
--- /dev/null
+++ b/sw/source/core/text/txttab.cxx
@@ -0,0 +1,663 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+#include <editeng/lrspitem.hxx>
+#ifndef _SVX_TSTPITEM_HXX //autogen
+#include <editeng/tstpitem.hxx>
+#endif
+#include <IDocumentSettingAccess.hxx>
+#include <frmatr.hxx>
+#include <SwPortionHandler.hxx>
+
+#include "viewopt.hxx" // SwViewOptions
+#include "txtcfg.hxx"
+#include "portab.hxx"
+#include "inftxt.hxx"
+#include "itrform2.hxx"
+#include "txtfrm.hxx"
+#include <numrule.hxx>
+// --> OD 2008-06-05 #i89179#
+#include <porfld.hxx>
+// <--
+
+
+/*************************************************************************
+ * SwLineInfo::GetTabStop()
+ *************************************************************************/
+
+//#i24363# tab stops relative to indent
+/* Return the first tab stop that is > nSearchPos.
+ * If the tab stop is outside the print area, we
+ * return 0 if it is not the first tab stop.*/
+const SvxTabStop *SwLineInfo::GetTabStop( const SwTwips nSearchPos,
+ const SwTwips nRight ) const
+{
+ for( MSHORT i = 0; i < pRuler->Count(); ++i )
+ {
+ const SvxTabStop &rTabStop = pRuler->operator[](i);
+ if( rTabStop.GetTabPos() > SwTwips(nRight) )
+ return i ? 0 : &rTabStop;
+
+ if( rTabStop.GetTabPos() > nSearchPos )
+ return &rTabStop;
+ }
+ return 0;
+}
+
+/*************************************************************************
+ * SwLineInfo::NumberOfTabStops()
+ *************************************************************************/
+
+USHORT SwLineInfo::NumberOfTabStops() const
+{
+ return pRuler->Count();
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewTabPortion()
+ *************************************************************************/
+
+SwTabPortion *SwTxtFormatter::NewTabPortion( SwTxtFormatInfo &rInf, bool bAuto ) const
+{
+ SwTabPortion *pTabPor = 0;
+ SwTabPortion *pLastTab = rInf.GetLastTab();
+ if( pLastTab && ( pLastTab->IsTabCntPortion() || pLastTab->IsTabDecimalPortion() ) )
+ if( pLastTab->PostFormat( rInf ) )
+ return 0;
+
+ xub_Unicode cFill = 0;
+ xub_Unicode cDec = 0;
+ SvxTabAdjust eAdj;
+
+ KSHORT nNewTabPos;
+ {
+ const bool bRTL = pFrm->IsRightToLeft();
+ // #i24363# tab stops relative to indent
+ // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
+ //
+ // --> OD 2008-07-01 #i91133#
+ const bool bTabsRelativeToIndent =
+ pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT);
+ const SwTwips nTabLeft = bRTL
+ ? pFrm->Frm().Right() -
+ ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
+ : pFrm->Frm().Left() +
+ ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
+ // <--
+
+ //
+ // nLinePos: The absolute position, where we started the line formatting.
+ //
+ SwTwips nLinePos = GetLeftMargin();
+ if ( bRTL )
+ {
+ Point aPoint( nLinePos, 0 );
+ pFrm->SwitchLTRtoRTL( aPoint );
+ nLinePos = aPoint.X();
+ }
+
+ //
+ // nTabPos: The current position, relative to the line start.
+ //
+ SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
+ if( nTabPos < rInf.X() )
+ {
+ nTabPos = rInf.X();
+ }
+
+ //
+ // nCurrentAbsPos: The current position in absolute coordinates.
+ //
+ const SwTwips nCurrentAbsPos = bRTL ?
+ nLinePos - nTabPos :
+ nLinePos + nTabPos;
+
+ SwTwips nMyRight = Right();
+
+ if ( pFrm->IsVertical() )
+ {
+ Point aRightTop( nMyRight, pFrm->Frm().Top() );
+ pFrm->SwitchHorizontalToVertical( aRightTop );
+ nMyRight = aRightTop.Y();
+ }
+
+ SwTwips nNextPos;
+
+ // #i24363# tab stops relative to indent
+ // nSearchPos: The current position relative to the tabs origin.
+ //
+ const SwTwips nSearchPos = bRTL ?
+ nTabLeft - nCurrentAbsPos :
+ nCurrentAbsPos - nTabLeft;
+
+ //
+ // First, we examine the tab stops set at the paragraph style or
+ // any hard set tab stops:
+ // Note: If there are no user defined tab stops, there is always a
+ // default tab stop.
+ //
+ const SvxTabStop* pTabStop =
+ aLineInf.GetTabStop( nSearchPos, nMyRight );
+ if( pTabStop )
+ {
+ cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
+ cDec = pTabStop->GetDecimal();
+ eAdj = pTabStop->GetAdjustment();
+ nNextPos = pTabStop->GetTabPos();
+ }
+ else
+ {
+ KSHORT nDefTabDist = aLineInf.GetDefTabStop();
+ if( KSHRT_MAX == nDefTabDist )
+ {
+ const SvxTabStopItem& rTab =
+ (const SvxTabStopItem &)pFrm->GetAttrSet()->
+ GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
+ if( rTab.Count() )
+ nDefTabDist = (KSHORT)rTab.GetStart()->GetTabPos();
+ else
+ nDefTabDist = SVX_TAB_DEFDIST;
+ aLineInf.SetDefTabStop( nDefTabDist );
+ }
+ SwTwips nCount = nSearchPos;
+
+ // Bei negativen Werten rundet "/" auf, "%" liefert negative Reste,
+ // bei positiven Werten rundet "/" ab, "%" liefert positvie Reste!
+ if ( nCount < 0 )
+ nCount = 0;
+
+ nCount /= nDefTabDist;
+ nNextPos = ( nCount + 1 ) * nDefTabDist ;
+ // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
+ const SwTwips nMinimumTabWidth = pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) ? 0 : 50;
+ // <--
+ if( ( bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
+ ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth ) )
+ {
+ nNextPos += nDefTabDist;
+ }
+ cFill = 0;
+ eAdj = SVX_TAB_ADJUST_LEFT;
+ }
+ // --> OD 2008-02-07 #newlistlevelattrs#
+ long nForced = 0;
+ if ( !bTabsRelativeToIndent )
+ {
+ if ( bRTL )
+ {
+ Point aPoint( Left(), 0 );
+ pFrm->SwitchLTRtoRTL( aPoint );
+ nForced = pFrm->Frm().Right() - aPoint.X();
+ }
+ else
+ {
+ nForced = Left() - pFrm->Frm().Left();
+ }
+ }
+ if( pCurr->HasForcedLeftMargin() )
+ {
+ SwLinePortion* pPor = pCurr->GetPortion();
+ while( pPor && !pPor->IsFlyPortion() )
+ pPor = pPor->GetPortion();
+ if( pPor )
+ nForced += pPor->Width();
+ }
+
+ // <--
+ // --> OD 2009-04-03 #i100732#
+ // correction of condition, when a tab stop at the left margin can
+ // be applied:
+ // If the paragraph is not inside a list having a list tab stop following
+ // the list label or no further tab stop found in such a paragraph or
+ // the next tab stop position does not equal the list tab stop,
+ // a tab stop at the left margin can be applied. If this condition is
+ // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
+ const bool bTabAtLeftMargin =
+ ( !aLineInf.IsListTabStopIncluded() ||
+ !pTabStop ||
+ nNextPos != aLineInf.GetListTabStopPosition() ) ||
+ // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
+ pFrm->GetTxtNode()->getIDocumentSettingAccess()->
+ get(IDocumentSettingAccess::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST);
+ if ( bTabAtLeftMargin &&
+ // <--
+ ( ( bRTL && nCurrentAbsPos > nTabLeft - nForced ) ||
+ ( !bRTL && nCurrentAbsPos < nTabLeft + nForced ) ) &&
+ // --> OD 2009-07-21 #i103685#
+ // adjust condition:
+ // - back to pre OOo 3.0 condition, if tab stops are relative to indent
+ // - further checks needed, if tab stops are not relative to indent
+ ( nNextPos > 0 &&
+ ( bTabsRelativeToIndent ||
+ ( !pTabStop || nNextPos > nForced ) ) ) )
+ // <--
+ {
+ eAdj = SVX_TAB_ADJUST_DEFAULT;
+ cFill = 0;
+ nNextPos = nForced;
+ }
+ nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
+ ASSERT( nNextPos >= 0, "GetTabStop: Don't go back!" );
+ nNewTabPos = KSHORT(nNextPos);
+ }
+
+ if ( bAuto )
+ {
+ if ( SVX_TAB_ADJUST_DECIMAL == eAdj &&
+ // --> FME 2005-12-19 #127428#
+ 1 == aLineInf.NumberOfTabStops() )
+ // <--
+ pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
+ }
+ else
+ {
+ switch( eAdj )
+ {
+ case SVX_TAB_ADJUST_RIGHT :
+ {
+ pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
+ break;
+ }
+ case SVX_TAB_ADJUST_CENTER :
+ {
+ pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
+ break;
+ }
+ case SVX_TAB_ADJUST_DECIMAL :
+ {
+ pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
+ break;
+ }
+ default:
+ {
+ ASSERT( SVX_TAB_ADJUST_LEFT == eAdj || SVX_TAB_ADJUST_DEFAULT == eAdj,
+ "+SwTxtFormatter::NewTabPortion: unknown adjustment" );
+ pTabPor = new SwTabLeftPortion( nNewTabPos, cFill );
+ break;
+ }
+ }
+ }
+
+ // Vorhandensein von Tabulatoren anzeigen ... ist nicht mehr noetig
+ // pCurr->SetTabulation();
+ // Aus Sicherheitsgruenden lassen wir uns die Daten errechnen
+ // pTabPor->Height( pLast->Height() );
+ // pTabPor->SetAscent( pLast->GetAscent() );
+ return pTabPor;
+}
+
+/*************************************************************************
+ * SwTabPortion::SwTabPortion()
+ *************************************************************************/
+
+// Die Basisklasse wird erstmal ohne alles initialisiert.
+
+
+SwTabPortion::SwTabPortion( const KSHORT nTabPosition, const xub_Unicode cFillChar )
+ : SwFixPortion( 0, 0 ), nTabPos(nTabPosition), cFill(cFillChar)
+{
+ nLineLength = 1;
+#ifdef DBG_UTIL
+ if( IsFilled() )
+ {
+ ASSERT( ' ' != cFill, "SwTabPortion::CTOR: blanks ?!" );
+ }
+#endif
+ SetWhichPor( POR_TAB );
+}
+
+/*************************************************************************
+ * virtual SwTabPortion::Format()
+ *************************************************************************/
+
+
+
+sal_Bool SwTabPortion::Format( SwTxtFormatInfo &rInf )
+{
+ SwTabPortion *pLastTab = rInf.GetLastTab();
+ if( pLastTab == this )
+ return PostFormat( rInf );
+ if( pLastTab )
+ pLastTab->PostFormat( rInf );
+ return PreFormat( rInf );
+}
+
+/*************************************************************************
+ * virtual SwTabPortion::FormatEOL()
+ *************************************************************************/
+
+
+
+void SwTabPortion::FormatEOL( SwTxtFormatInfo &rInf )
+{
+ if( rInf.GetLastTab() == this && !IsTabLeftPortion() )
+ PostFormat( rInf );
+}
+
+/*************************************************************************
+ * SwTabPortion::PreFormat()
+ *************************************************************************/
+
+
+
+sal_Bool SwTabPortion::PreFormat( SwTxtFormatInfo &rInf )
+{
+ ASSERT( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
+
+ // Hier lassen wir uns nieder...
+ Fix( static_cast<USHORT>(rInf.X()) );
+
+ const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
+
+ // Die Mindestbreite eines Tabs ist immer mindestens ein Blank
+ // --> FME 2004-11-25 #i37686# In compatibility mode, the minimum width
+ // should be 1, even for non-left tab stops.
+ USHORT nMinimumTabWidth = 1;
+ // <--
+ if ( !bTabCompat )
+ {
+ // --> OD 2008-06-05 #i89179#
+ // tab portion representing the list tab of a list label gets the
+ // same font as the corresponding number portion
+ std::auto_ptr< SwFontSave > pSave( 0 );
+ if ( GetLen() == 0 &&
+ rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
+ static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
+ {
+ const SwFont* pNumberPortionFont =
+ static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
+ pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
+ }
+ // <--
+ XubString aTmp( ' ' );
+ SwTxtSizeInfo aInf( rInf, aTmp );
+ nMinimumTabWidth = aInf.GetTxtSize().Width();
+ }
+ PrtWidth( nMinimumTabWidth );
+
+ // Break tab stop to next line if:
+ // 1. Minmal width does not fit to line anymore.
+ // 2. An underflow event was called for the tab portion.
+ sal_Bool bFull = ( bTabCompat && rInf.IsUnderFlow() ) ||
+ rInf.Width() <= rInf.X() + PrtWidth();
+
+ // #95477# Rotated tab stops get the width of one blank
+ const USHORT nDir = rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
+
+ if( ! bFull && 0 == nDir )
+ {
+ const MSHORT nWhich = GetWhichPor();
+ switch( nWhich )
+ {
+ case POR_TABRIGHT:
+ case POR_TABDECIMAL:
+ case POR_TABCENTER:
+ {
+ if( POR_TABDECIMAL == nWhich )
+ rInf.SetTabDecimal(
+ ((SwTabDecimalPortion*)this)->GetTabDecimal());
+ rInf.SetLastTab( this );
+ break;
+ }
+ case POR_TABLEFT:
+ {
+ PrtWidth( static_cast<USHORT>(GetTabPos() - rInf.X()) );
+ bFull = rInf.Width() <= rInf.X() + PrtWidth();
+
+ // In tabulator compatibility mode, we reset the bFull flag
+ // if the tabulator is at the end of the paragraph and the
+ // tab stop position is outside the frame:
+ if ( bFull && bTabCompat &&
+ rInf.GetIdx() + GetLen() == rInf.GetTxt().Len() &&
+ GetTabPos() >= rInf.GetTxtFrm()->Frm().Width() )
+ bFull = sal_False;
+
+ break;
+ }
+ default: ASSERT( !this, "SwTabPortion::PreFormat: unknown adjustment" );
+ }
+ }
+
+ if( bFull )
+ {
+ // Wir muessen aufpassen, dass wir nicht endlos schleifen,
+ // wenn die Breite kleiner ist, als ein Blank ...
+ if( rInf.GetIdx() == rInf.GetLineStart() &&
+ // --> FME 2005-01-19 #119175# TabStop should be forced to current
+ // line if there is a fly reducing the line width:
+ !rInf.GetFly() )
+ // <--
+ {
+ PrtWidth( static_cast<USHORT>(rInf.Width() - rInf.X()) );
+ SetFixWidth( PrtWidth() );
+ }
+ else
+ {
+ Height( 0 );
+ Width( 0 );
+ SetLen( 0 );
+ SetAscent( 0 );
+ SetPortion( NULL ); //?????
+ }
+ return sal_True;
+ }
+ else
+ {
+ // Ein Kunstgriff mit Effekt: Die neuen Tabportions verhalten sich nun
+ // so, wie FlyFrms, die in der Zeile stehen - inklusive Adjustment !
+ SetFixWidth( PrtWidth() );
+ return sal_False;
+ }
+}
+
+/*************************************************************************
+ * SwTabPortion::PostFormat()
+ *************************************************************************/
+
+
+
+sal_Bool SwTabPortion::PostFormat( SwTxtFormatInfo &rInf )
+{
+ const KSHORT nRight = Min( GetTabPos(), rInf.Width() );
+ const SwLinePortion *pPor = GetPortion();
+
+ KSHORT nPorWidth = 0;
+ while( pPor )
+ {
+ DBG_LOOP;
+ nPorWidth = nPorWidth + pPor->Width();
+ pPor = pPor->GetPortion();
+ }
+
+ const MSHORT nWhich = GetWhichPor();
+ ASSERT( POR_TABLEFT != nWhich, "SwTabPortion::PostFormat: already formatted" );
+ const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
+
+ // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full:
+ if ( bTabCompat && POR_TABDECIMAL == nWhich )
+ {
+ KSHORT nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
+
+ // no value was set => no decimal character was found
+ if ( USHRT_MAX != nPrePorWidth )
+ {
+ if ( nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
+ {
+ nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
+ }
+
+ nPorWidth = nPrePorWidth - 1;
+ }
+ }
+ // <--
+
+ if( POR_TABCENTER == nWhich )
+ {
+ // zentrierte Tabs bereiten Probleme:
+ // Wir muessen den Anteil herausfinden, der noch auf die Zeile passt.
+ KSHORT nNewWidth = nPorWidth /2;
+ if( nNewWidth > rInf.Width() - nRight )
+ nNewWidth = nPorWidth - (rInf.Width() - nRight);
+ nPorWidth = nNewWidth;
+ }
+
+ const KSHORT nDiffWidth = nRight - Fix();
+
+ if( nDiffWidth > nPorWidth )
+ {
+ const KSHORT nOldWidth = GetFixWidth();
+ const KSHORT nAdjDiff = nDiffWidth - nPorWidth;
+ if( nAdjDiff > GetFixWidth() )
+ PrtWidth( nAdjDiff );
+ // Nicht erschrecken: wir muessen rInf weiterschieben.
+ // Immerhin waren wir als Rechtstab bislang nur ein Blank breit.
+ // Da wir uns jetzt aufgespannt haben, muss der Differenzbetrag
+ // auf rInf.X() addiert werden !
+ rInf.X( rInf.X() + PrtWidth() - nOldWidth );
+ }
+ SetFixWidth( PrtWidth() );
+ // letzte Werte zuruecksetzen
+ rInf.SetLastTab(0);
+ if( POR_TABDECIMAL == nWhich )
+ rInf.SetTabDecimal(0);
+
+ return rInf.Width() <= rInf.X();
+}
+
+/*************************************************************************
+ * virtual SwTabPortion::Paint()
+ *
+ * Ex: LineIter::DrawTab()
+ *************************************************************************/
+
+void SwTabPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+#ifdef DBG_UTIL
+ // Wir wollen uns die Fixbreite anzeigen
+ if( rInf.OnWin() && OPTDBG( rInf ) &&
+ !rInf.GetOpt().IsPagePreview() && \
+ !rInf.GetOpt().IsReadonly() && \
+ SwViewOption::IsFieldShadings() )
+ {
+ const KSHORT nTmpWidth = PrtWidth();
+ ((SwTabPortion*)this)->PrtWidth( GetFixWidth() );
+ rInf.DrawViewOpt( *this, POR_TAB );
+ ((SwTabPortion*)this)->PrtWidth( nTmpWidth );
+ }
+#endif
+
+ // --> OD 2008-06-05 #i89179#
+ // tab portion representing the list tab of a list label gets the
+ // same font as the corresponding number portion
+ std::auto_ptr< SwFontSave > pSave( 0 );
+ if ( GetLen() == 0 )
+ {
+ const SwLinePortion* pPrevPortion =
+ const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
+ if ( pPrevPortion &&
+ pPrevPortion->InNumberGrp() &&
+ static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
+ {
+ const SwFont* pNumberPortionFont =
+ static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
+ pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
+ }
+ }
+ // <--
+ rInf.DrawBackBrush( *this );
+
+ // do we have to repaint a post it portion?
+ if( rInf.OnWin() && pPortion && !pPortion->Width() )
+ pPortion->PrePaint( rInf, this );
+
+ // Darstellung von Sonderzeichen
+ if( rInf.OnWin() && rInf.GetOpt().IsTab() )
+ {
+ // gefuellte Tabs werden grau hinterlegt.
+ if( IsFilled() )
+ rInf.DrawViewOpt( *this, POR_TAB );
+ else
+ rInf.DrawTab( *this );
+ }
+
+ // 6842: Tabs sollen auf einmal wieder unterstrichen werden.
+ if( rInf.GetFont()->IsPaintBlank() )
+ {
+ // Tabs mit Fuellung
+ XubString aTxt( ' ' );
+ const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
+ // robust:
+ if( nCharWidth )
+ {
+ // 6864: immer mit Kerning, auch auf dem Drucker!
+ KSHORT nChar = Width() / nCharWidth;
+ rInf.DrawText( aTxt.Fill( nChar, ' ' ), *this, 0, nChar, sal_True );
+ }
+ }
+
+ // Ausgabe von Fuellzeichen
+ if( IsFilled() )
+ {
+ // Tabs mit Fuellung
+ XubString aTxt( cFill );
+ const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
+#if OSL_DEBUG_LEVEL > 1
+ ASSERT( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
+#endif
+ // robust:
+ if( nCharWidth )
+ {
+ // 6864: immer mit Kerning, auch auf dem Drucker!
+ KSHORT nChar = Width() / nCharWidth;
+ if ( cFill == '_' )
+ ++nChar; // damit keine Luecken entstehen (Bug 13430)
+ rInf.DrawText( aTxt.Fill( nChar, cFill ), *this, 0, nChar, sal_True );
+ }
+ }
+}
+
+/*************************************************************************
+ * virtual SwAutoTabDecimalPortion::Paint()
+ *************************************************************************/
+
+void SwAutoTabDecimalPortion::Paint( const SwTxtPaintInfo & ) const
+{
+}
+
+/*************************************************************************
+ * virtual SwTabPortion::HandlePortion()
+ *************************************************************************/
+
+void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Text( GetLen(), GetWhichPor() );
+}
+
diff --git a/sw/source/core/text/widorp.cxx b/sw/source/core/text/widorp.cxx
new file mode 100644
index 000000000000..be69b19263e3
--- /dev/null
+++ b/sw/source/core/text/widorp.cxx
@@ -0,0 +1,566 @@
+/*************************************************************************
+ *
+ * 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 "hintids.hxx"
+
+#include "layfrm.hxx"
+#include "ftnboss.hxx"
+#include "ndtxt.hxx"
+#include "paratr.hxx"
+#include <editeng/orphitem.hxx>
+#include <editeng/widwitem.hxx>
+#include <editeng/keepitem.hxx>
+#include <editeng/spltitem.hxx>
+#include <frmatr.hxx>
+#include <txtftn.hxx>
+#include <fmtftn.hxx>
+#include <rowfrm.hxx>
+
+#include "txtcfg.hxx"
+#include "widorp.hxx"
+#include "txtfrm.hxx"
+#include "itrtxt.hxx"
+#include "sectfrm.hxx" //SwSectionFrm
+#include "ftnfrm.hxx"
+
+#undef WIDOWTWIPS
+
+
+/*************************************************************************
+ * inline IsNastyFollow()
+ *************************************************************************/
+// Ein Follow, der auf der selben Seite steht, wie sein Master ist nasty.
+inline sal_Bool IsNastyFollow( const SwTxtFrm *pFrm )
+{
+ ASSERT( !pFrm->IsFollow() || !pFrm->GetPrev() ||
+ ((const SwTxtFrm*)pFrm->GetPrev())->GetFollow() == pFrm,
+ "IsNastyFollow: Was ist denn hier los?" );
+ return pFrm->IsFollow() && pFrm->GetPrev();
+}
+
+/*************************************************************************
+ * SwTxtFrmBreak::SwTxtFrmBreak()
+ *************************************************************************/
+
+SwTxtFrmBreak::SwTxtFrmBreak( SwTxtFrm *pNewFrm, const SwTwips nRst )
+ : nRstHeight(nRst), pFrm(pNewFrm)
+{
+ SWAP_IF_SWAPPED( pFrm )
+ SWRECTFN( pFrm )
+ nOrigin = (pFrm->*fnRect->fnGetPrtTop)();
+ SwSectionFrm* pSct;
+ bKeep = !pFrm->IsMoveable() || IsNastyFollow( pFrm ) ||
+ ( pFrm->IsInSct() && (pSct=pFrm->FindSctFrm())->Lower()->IsColumnFrm()
+ && !pSct->MoveAllowed( pFrm ) ) ||
+ !pFrm->GetTxtNode()->GetSwAttrSet().GetSplit().GetValue() ||
+ pFrm->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue();
+ bBreak = sal_False;
+
+ if( !nRstHeight && !pFrm->IsFollow() && pFrm->IsInFtn() && pFrm->HasPara() )
+ {
+ nRstHeight = pFrm->GetFtnFrmHeight();
+ nRstHeight += (pFrm->Prt().*fnRect->fnGetHeight)() -
+ (pFrm->Frm().*fnRect->fnGetHeight)();
+ if( nRstHeight < 0 )
+ nRstHeight = 0;
+ }
+
+ UNDO_SWAP( pFrm )
+}
+
+/* BP 18.6.93: Widows.
+ * Im Gegensatz zur ersten Implementierung werden die Widows nicht
+ * mehr vorausschauend berechnet, sondern erst beim Formatieren des
+ * gesplitteten Follows festgestellt. Im Master faellt die Widows-
+ * Berechnung also generell weg (nWidows wird manipuliert).
+ * Wenn der Follow feststellt, dass die Widowsregel zutrifft,
+ * verschickt er an seinen Vorgaenger ein Prepare.
+ * Ein besonderes Problem ergibt sich, wenn die Widows zuschlagen,
+ * aber im Master noch ein paar Zeilen zur Verfuegung stehen.
+ *
+ */
+
+/*************************************************************************
+ * SwTxtFrmBreak::IsInside()
+ *************************************************************************/
+
+/* BP(22.07.92): Berechnung von Witwen und Waisen.
+ * Die Methode liefert sal_True zurueck, wenn eine dieser Regelung zutrifft.
+ *
+ * Eine Schwierigkeit gibt es im Zusammenhang mit Widows und
+ * unterschiedlichen Formaten zwischen Master- und Folgeframes:
+ * Beispiel: Wenn die erste Spalte 3cm und die zweite 4cm breit ist
+ * und Widows auf sagen wir 3 gesetzt ist, so ist erst bei der Formatierung
+ * des Follows entscheidbar, ob die Widowsbedingung einhaltbar ist oder
+ * nicht. Leider ist davon abhaengig, ob der Absatz als Ganzes auf die
+ * naechste Seite rutscht.
+ */
+
+sal_Bool SwTxtFrmBreak::IsInside( SwTxtMargin &rLine ) const
+{
+ sal_Bool bFit = sal_False;
+
+ SWAP_IF_SWAPPED( pFrm )
+ SWRECTFN( pFrm )
+ // nOrigin is an absolut value, rLine referes to the swapped situation.
+
+ SwTwips nTmpY;
+ if ( pFrm->IsVertical() )
+ nTmpY = pFrm->SwitchHorizontalToVertical( rLine.Y() + rLine.GetLineHeight() );
+ else
+ nTmpY = rLine.Y() + rLine.GetLineHeight();
+
+ SwTwips nLineHeight = (*fnRect->fnYDiff)( nTmpY , nOrigin );
+
+ // 7455 und 6114: Raum fuer die Umrandung unten einkalkulieren.
+ nLineHeight += (pFrm->*fnRect->fnGetBottomMargin)();
+
+ if( nRstHeight )
+ bFit = nRstHeight >= nLineHeight;
+ else
+ {
+ // Der Frm besitzt eine Hoehe, mit der er auf die Seite passt.
+ SwTwips nHeight =
+ (*fnRect->fnYDiff)( (pFrm->GetUpper()->*fnRect->fnGetPrtBottom)(), nOrigin );
+
+ // Wenn sich alles innerhalb des bestehenden Frames abspielt,
+ // ist das Ergebnis sal_True;
+ bFit = nHeight >= nLineHeight;
+ if( !bFit )
+ {
+ // Die LineHeight sprengt die aktuelle Frm-Hoehe.
+ // Nun rufen wir ein Probe-Grow, um zu ermitteln, ob der
+ // Frame um den gewuenschten Bereich wachsen wuerde.
+ nHeight += pFrm->GrowTst( LONG_MAX );
+
+ // Das Grow() returnt die Hoehe, um die der Upper des TxtFrm
+ // den TxtFrm wachsen lassen wuerde.
+ // Der TxtFrm selbst darf wachsen wie er will.
+ bFit = nHeight >= nLineHeight;
+ }
+ }
+
+ UNDO_SWAP( pFrm );
+
+ return bFit;
+}
+
+/*************************************************************************
+ * SwTxtFrmBreak::IsBreakNow()
+ *************************************************************************/
+
+sal_Bool SwTxtFrmBreak::IsBreakNow( SwTxtMargin &rLine )
+{
+ SWAP_IF_SWAPPED( pFrm )
+
+ // bKeep ist staerker als IsBreakNow()
+ // Ist noch genug Platz ?
+ if( bKeep || IsInside( rLine ) )
+ bBreak = sal_False;
+ else
+ {
+ /* Diese Klasse geht davon aus, dass der SwTxtMargin von Top nach Bottom
+ * durchgearbeitet wird. Aus Performancegruenden wird in folgenden
+ * Faellen der Laden fuer das weitere Aufspalten dicht gemacht:
+ * Wenn eine einzige Zeile nicht mehr passt.
+ * Sonderfall: bei DummyPortions ist LineNr == 1, obwohl wir splitten
+ * wollen.
+ */
+ // 6010: DropLines mit einbeziehen
+
+ sal_Bool bFirstLine = 1 == rLine.GetLineNr() && !rLine.GetPrev();
+ bBreak = sal_True;
+ if( ( bFirstLine && pFrm->GetIndPrev() )
+ || ( rLine.GetLineNr() <= rLine.GetDropLines() ) )
+ {
+ bKeep = sal_True;
+ bBreak = sal_False;
+ }
+ else if(bFirstLine && pFrm->IsInFtn() && !pFrm->FindFtnFrm()->GetPrev())
+ {
+ SwLayoutFrm* pTmp = pFrm->FindFtnBossFrm()->FindBodyCont();
+ if( !pTmp || !pTmp->Lower() )
+ bBreak = sal_False;
+ }
+ }
+
+ UNDO_SWAP( pFrm )
+
+ return bBreak;
+}
+
+// OD 2004-02-27 #106629# - no longer inline
+void SwTxtFrmBreak::SetRstHeight( const SwTxtMargin &rLine )
+{
+ // OD, FME 2004-02-27 #106629# - consider bottom margin
+ SWRECTFN( pFrm )
+ nRstHeight = (pFrm->*fnRect->fnGetBottomMargin)();
+ if ( bVert )
+ nRstHeight += nOrigin - pFrm->SwitchHorizontalToVertical( rLine.Y() );
+ else
+ nRstHeight += rLine.Y() - nOrigin;
+}
+
+/*************************************************************************
+ * WidowsAndOrphans::WidowsAndOrphans()
+ *************************************************************************/
+
+WidowsAndOrphans::WidowsAndOrphans( SwTxtFrm *pNewFrm, const SwTwips nRst,
+ sal_Bool bChkKeep )
+ : SwTxtFrmBreak( pNewFrm, nRst ), nWidLines( 0 ), nOrphLines( 0 )
+{
+ SWAP_IF_SWAPPED( pFrm )
+
+ if( bKeep )
+ {
+ // 5652: bei Absaetzen, die zusammengehalten werden sollen und
+ // groesser sind als die Seite wird bKeep aufgehoben.
+ if( bChkKeep && !pFrm->GetPrev() && !pFrm->IsInFtn() &&
+ pFrm->IsMoveable() &&
+ ( !pFrm->IsInSct() || pFrm->FindSctFrm()->MoveAllowed(pFrm) ) )
+ bKeep = sal_False;
+ //Auch bei gesetztem Keep muessen Orphans beachtet werden,
+ //z.B. bei verketteten Rahmen erhaelt ein Follow im letzten Rahmen ein Keep,
+ //da er nicht (vorwaerts) Moveable ist,
+ //er darf aber trotzdem vom Master Zeilen anfordern wg. der Orphanregel.
+ if( pFrm->IsFollow() )
+ nWidLines = pFrm->GetTxtNode()->GetSwAttrSet().GetWidows().GetValue();
+ }
+ else
+ {
+ const SwAttrSet& rSet = pFrm->GetTxtNode()->GetSwAttrSet();
+ const SvxOrphansItem &rOrph = rSet.GetOrphans();
+ if ( rOrph.GetValue() > 1 )
+ nOrphLines = rOrph.GetValue();
+ if ( pFrm->IsFollow() )
+ nWidLines = rSet.GetWidows().GetValue();
+
+ }
+
+ if ( bKeep || nWidLines || nOrphLines )
+ {
+ bool bResetFlags = false;
+
+ if ( pFrm->IsInTab() )
+ {
+ // For compatibility reasons, we disable Keep/Widows/Orphans
+ // inside splittable row frames:
+ if ( pFrm->GetNextCellLeaf( MAKEPAGE_NONE ) || pFrm->IsInFollowFlowRow() )
+ {
+ const SwFrm* pTmpFrm = pFrm->GetUpper();
+ while ( !pTmpFrm->IsRowFrm() )
+ pTmpFrm = pTmpFrm->GetUpper();
+ if ( static_cast<const SwRowFrm*>(pTmpFrm)->IsRowSplitAllowed() )
+ bResetFlags = true;
+ }
+ }
+
+ if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
+ {
+ // Innerhalb von Fussnoten gibt es gute Gruende, das Keep-Attribut und
+ // die Widows/Orphans abzuschalten.
+ SwFtnFrm *pFtn = pFrm->FindFtnFrm();
+ sal_Bool bFt = !pFtn->GetAttr()->GetFtn().IsEndNote();
+ if( !pFtn->GetPrev() &&
+ pFtn->FindFtnBossFrm( bFt ) != pFtn->GetRef()->FindFtnBossFrm( bFt )
+ && ( !pFrm->IsInSct() || pFrm->FindSctFrm()->MoveAllowed(pFrm) ) )
+ {
+ bResetFlags = true;
+ }
+ }
+
+ if ( bResetFlags )
+ {
+ bKeep = sal_False;
+ nOrphLines = 0;
+ nWidLines = 0;
+ }
+ }
+
+ UNDO_SWAP( pFrm )
+}
+
+/*************************************************************************
+ * WidowsAndOrphans::FindBreak()
+ *************************************************************************/
+
+/* Die Find*-Methoden suchen nicht nur, sondern stellen den SwTxtMargin auf
+ * die Zeile ein, wo der Absatz gebrochen werden soll und kuerzen ihn dort.
+ * FindBreak()
+ */
+
+sal_Bool WidowsAndOrphans::FindBreak( SwTxtFrm *pFrame, SwTxtMargin &rLine,
+ sal_Bool bHasToFit )
+{
+ // OD 2004-02-25 #i16128# - Why member <pFrm> _*and*_ parameter <pFrame>??
+ // Thus, assertion on situation, that these are different to figure out why.
+ ASSERT( pFrm == pFrame, "<WidowsAndOrphans::FindBreak> - pFrm != pFrame" );
+
+ SWAP_IF_SWAPPED( pFrm )
+
+ sal_Bool bRet = sal_True;
+ MSHORT nOldOrphans = nOrphLines;
+ if( bHasToFit )
+ nOrphLines = 0;
+ rLine.Bottom();
+ // OD 2004-02-25 #i16128# - method renamed
+ if( !IsBreakNowWidAndOrp( rLine ) )
+ bRet = sal_False;
+ if( !FindWidows( pFrame, rLine ) )
+ {
+ sal_Bool bBack = sal_False;
+ // OD 2004-02-25 #i16128# - method renamed
+ while( IsBreakNowWidAndOrp( rLine ) )
+ {
+ if( rLine.PrevLine() )
+ bBack = sal_True;
+ else
+ break;
+ }
+ // Eigentlich werden bei HasToFit Schusterjungen (Orphans) nicht
+ // beruecksichtigt, wenn allerdings Dummy-Lines im Spiel sind und
+ // die Orphansregel verletzt wird, machen wir mal eine Ausnahme:
+ // Wir lassen einfach eine Dummyline zurueck und wandern mit dem Text
+ // komplett auf die naechste Seite/Spalte.
+ if( rLine.GetLineNr() <= nOldOrphans &&
+ rLine.GetInfo().GetParaPortion()->IsDummy() &&
+ ( ( bHasToFit && bRet ) || IsBreakNow( rLine ) ) )
+ rLine.Top();
+
+ rLine.TruncLines( sal_True );
+ bRet = bBack;
+ }
+ nOrphLines = nOldOrphans;
+
+ UNDO_SWAP( pFrm )
+
+ return bRet;
+}
+
+/*************************************************************************
+ * WidowsAndOrphans::FindWidows()
+ *************************************************************************/
+
+/* FindWidows positioniert den SwTxtMargin des Masters auf die umzubrechende
+ * Zeile, indem der Follow formatiert und untersucht wird.
+ * Liefert sal_True zurueck, wenn die Widows-Regelung in Kraft tritt,
+ * d.h. der Absatz _zusammengehalten_ werden soll !
+ */
+
+sal_Bool WidowsAndOrphans::FindWidows( SwTxtFrm *pFrame, SwTxtMargin &rLine )
+{
+ ASSERT( ! pFrame->IsVertical() || ! pFrame->IsSwapped(),
+ "WidowsAndOrphans::FindWidows with swapped frame" )
+
+ if( !nWidLines || !pFrame->IsFollow() )
+ return sal_False;
+
+ rLine.Bottom();
+
+ // Wir koennen noch was abzwacken
+ SwTxtFrm *pMaster = pFrame->FindMaster();
+ ASSERT(pMaster, "+WidowsAndOrphans::FindWidows: Widows in a master?");
+ if( !pMaster )
+ return sal_False;
+
+ // 5156: Wenn die erste Zeile des Follows nicht passt, wird der Master
+ // wohl voll mit Dummies sein. In diesem Fall waere ein PREP_WIDOWS fatal.
+ if( pMaster->GetOfst() == pFrame->GetOfst() )
+ return sal_False;
+
+ // Resthoehe des Masters
+ SWRECTFN( pFrame )
+
+ const SwTwips nDocPrtTop = (pFrame->*fnRect->fnGetPrtTop)();
+ SwTwips nOldHeight;
+ SwTwips nTmpY = rLine.Y() + rLine.GetLineHeight();
+
+ if ( bVert )
+ {
+ nTmpY = pFrame->SwitchHorizontalToVertical( nTmpY );
+ nOldHeight = -(pFrame->Prt().*fnRect->fnGetHeight)();
+ }
+ else
+ nOldHeight = (pFrame->Prt().*fnRect->fnGetHeight)();
+
+ const SwTwips nChg = (*fnRect->fnYDiff)( nTmpY, nDocPrtTop + nOldHeight );
+
+ // Unterhalb der Widows-Schwelle...
+ if( rLine.GetLineNr() >= nWidLines )
+ {
+ // 8575: Follow to Master I
+ // Wenn der Follow *waechst*, so besteht fuer den Master die Chance,
+ // Zeilen entgegenzunehmen, die er vor Kurzem gezwungen war an den
+ // Follow abzugeben: Prepare(Need); diese Abfrage unterhalb von nChg!
+ // (0W, 2O, 2M, 2F) + 1F = 3M, 2F
+ if( rLine.GetLineNr() > nWidLines && pFrame->IsJustWidow() )
+ {
+ // Wenn der Master gelockt ist, so hat er vermutlich gerade erst
+ // eine Zeile an uns abgegeben, diese geben nicht zurueck, nur
+ // weil bei uns daraus mehrere geworden sind (z.B. durch Rahmen).
+ if( !pMaster->IsLocked() && pMaster->GetUpper() )
+ {
+ const SwTwips nTmpRstHeight = (pMaster->Frm().*fnRect->fnBottomDist)
+ ( (pMaster->GetUpper()->*fnRect->fnGetPrtBottom)() );
+ if ( nTmpRstHeight >=
+ SwTwips(rLine.GetInfo().GetParaPortion()->Height() ) )
+ {
+ pMaster->Prepare( PREP_ADJUST_FRM );
+ pMaster->_InvalidateSize();
+ pMaster->InvalidatePage();
+ }
+ }
+
+ pFrame->SetJustWidow( sal_False );
+ }
+ return sal_False;
+ }
+
+ // 8575: Follow to Master II
+ // Wenn der Follow *schrumpft*, so besteht fuer den Master die Chance,
+ // den kompletten Orphan zu inhalieren.
+ // (0W, 2O, 2M, 1F) - 1F = 3M, 0F -> PREP_ADJUST_FRM
+ // (0W, 2O, 3M, 2F) - 1F = 2M, 2F -> PREP_WIDOWS
+
+ if( 0 > nChg && !pMaster->IsLocked() && pMaster->GetUpper() )
+ {
+ SwTwips nTmpRstHeight = (pMaster->Frm().*fnRect->fnBottomDist)
+ ( (pMaster->GetUpper()->*fnRect->fnGetPrtBottom)() );
+ if( nTmpRstHeight >= SwTwips(rLine.GetInfo().GetParaPortion()->Height() ) )
+ {
+ pMaster->Prepare( PREP_ADJUST_FRM );
+ pMaster->_InvalidateSize();
+ pMaster->InvalidatePage();
+ pFrame->SetJustWidow( sal_False );
+ return sal_False;
+ }
+ }
+
+ // Master to Follow
+ // Wenn der Follow nach seiner Formatierung weniger Zeilen enthaelt
+ // als Widows, so besteht noch die Chance, einige Zeilen des Masters
+ // abzuzwacken. Wenn dadurch die Orphans-Regel des Masters in Kraft
+ // tritt muss im CalcPrep() des Master-Frame der Frame so vergroessert
+ // werden, dass er nicht mehr auf seine urspruengliche Seite passt.
+ // Wenn er noch ein paar Zeilen entbehren kann, dann muss im CalcPrep()
+ // ein Shrink() erfolgen, der Follow mit dem Widows rutscht dann auf
+ // die Seite des Masters, haelt sich aber zusammen, so dass er (endlich)
+ // auf die naechste Seite rutscht. - So die Theorie!
+
+
+ // Wir fordern nur noch ein Zeile zur Zeit an, weil eine Zeile des Masters
+ // bei uns durchaus mehrere Zeilen ergeben koennten.
+ // Dafuer behaelt CalcFollow solange die Kontrolle, bis der Follow alle
+ // notwendigen Zeilen bekommen hat.
+ MSHORT nNeed = 1; // frueher: nWidLines - rLine.GetLineNr();
+
+ // Special case: Master cannot give lines to follow
+ // --> FME 2008-09-16 #i91421#
+ if ( !pMaster->GetIndPrev() )
+ {
+ ULONG nLines = pMaster->GetThisLines();
+ if(nLines == 0 && pMaster->HasPara())
+ {
+ const SwParaPortion *pMasterPara = pMaster->GetPara();
+ if(pMasterPara && pMasterPara->GetNext())
+ nLines = 2;
+ }
+ if( nLines <= nNeed )
+ return sal_False;
+ }
+
+ pMaster->Prepare( PREP_WIDOWS, (void*)&nNeed );
+ return sal_True;
+}
+
+/*************************************************************************
+ * WidowsAndOrphans::WouldFit()
+ *************************************************************************/
+
+sal_Bool WidowsAndOrphans::WouldFit( SwTxtMargin &rLine, SwTwips &rMaxHeight, sal_Bool bTst )
+{
+ // Here it does not matter, if pFrm is swapped or not.
+ // IsInside() takes care for itself
+
+ // Wir erwarten, dass rLine auf der letzten Zeile steht!!
+ ASSERT( !rLine.GetNext(), "WouldFit: aLine::Bottom missed!" );
+ MSHORT nLineCnt = rLine.GetLineNr();
+
+ // Erstmal die Orphansregel und den Initialenwunsch erfuellen ...
+ const MSHORT nMinLines = Max( GetOrphansLines(), rLine.GetDropLines() );
+ if ( nLineCnt < nMinLines )
+ return sal_False;
+
+ rLine.Top();
+ SwTwips nLineSum = rLine.GetLineHeight();
+
+ while( nMinLines > rLine.GetLineNr() )
+ {
+ DBG_LOOP;
+ if( !rLine.NextLine() )
+ return sal_False;
+ nLineSum += rLine.GetLineHeight();
+ }
+
+ // Wenn wir jetzt schon nicht mehr passen ...
+ if( !IsInside( rLine ) )
+ return sal_False;
+
+ // Jetzt noch die Widows-Regel ueberpruefen
+ if( !nWidLines && !pFrm->IsFollow() )
+ {
+ // I.A. brauchen Widows nur ueberprueft werden, wenn wir ein Follow
+ // sind. Bei WouldFit muss aber auch fuer den Master die Regel ueber-
+ // prueft werden, weil wir ja gerade erst die Trennstelle ermitteln.
+ // Im Ctor von WidowsAndOrphans wurde nWidLines aber nur fuer Follows
+ // aus dem AttrSet ermittelt, deshalb holen wir es hier nach:
+ const SwAttrSet& rSet = pFrm->GetTxtNode()->GetSwAttrSet();
+ nWidLines = rSet.GetWidows().GetValue();
+ }
+
+ // Sind nach Orphans/Initialen noch genug Zeilen fuer die Widows uebrig?
+ // #111937#: If we are currently doing a test formatting, we may not
+ // consider the widows rule for two reasons:
+ // 1. The columns may have different widths.
+ // Widow lines would have wrong width.
+ // 2. Test formatting is only done up to the given space.
+ // we do not have any lines for widows at all.
+ if( bTst || nLineCnt - nMinLines >= GetWidowsLines() )
+ {
+ if( rMaxHeight >= nLineSum )
+ {
+ rMaxHeight -= nLineSum;
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
diff --git a/sw/source/core/text/widorp.hxx b/sw/source/core/text/widorp.hxx
new file mode 100644
index 000000000000..3ceef310b64e
--- /dev/null
+++ b/sw/source/core/text/widorp.hxx
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _WIDORP_HXX
+#define _WIDORP_HXX
+class SwTxtFrm;
+
+#include "swtypes.hxx"
+#include "itrtxt.hxx"
+
+class SwTxtFrmBreak
+{
+private:
+ SwTwips nRstHeight;
+ SwTwips nOrigin;
+protected:
+ SwTxtFrm *pFrm;
+ sal_Bool bBreak;
+ sal_Bool bKeep;
+public:
+ SwTxtFrmBreak( SwTxtFrm *pFrm, const SwTwips nRst = 0 );
+ sal_Bool IsBreakNow( SwTxtMargin &rLine );
+
+ sal_Bool IsBroken() const { return bBreak; }
+ sal_Bool IsKeepAlways() const { return bKeep; }
+ void Keep() { bKeep = sal_True; }
+ void Break() { bKeep = sal_False; bBreak = sal_True; }
+
+ inline sal_Bool GetKeep() const { return bKeep; }
+ inline void SetKeep( const sal_Bool bNew ) { bKeep = bNew; }
+
+ sal_Bool IsInside( SwTxtMargin &rLine ) const;
+
+ // Um Sonderfaelle mit Ftn behandeln zu koennen.
+ // Mit SetRstHeight wird dem SwTxtFrmBreak die Resthoehe eingestellt,
+ // Um TruncLines() rufen zu koennen, ohne dass IsBreakNow() einen
+ // anderen Wert zurueckliefert.
+ // Es wird dabei davon ausgegangen, dass rLine auf der letzten Zeile
+ // steht, die nicht mehr passt.
+
+ // OD 2004-02-27 #106629# - no longer inline
+ void SetRstHeight( const SwTxtMargin &rLine );
+ SwTwips GetRstHeight() const { return nRstHeight; }
+};
+
+class WidowsAndOrphans : public SwTxtFrmBreak
+{
+private:
+ MSHORT nWidLines, nOrphLines;
+
+public:
+ WidowsAndOrphans( SwTxtFrm *pFrm, const SwTwips nRst = 0,
+ sal_Bool bCheckKeep = sal_True );
+ sal_Bool FindWidows( SwTxtFrm *pFrm, SwTxtMargin &rLine );
+ MSHORT GetWidowsLines() const
+ { return nWidLines; }
+ MSHORT GetOrphansLines() const
+ { return nOrphLines; }
+ void ClrOrphLines(){ nOrphLines = 0; }
+
+ sal_Bool FindBreak( SwTxtFrm *pFrm, SwTxtMargin &rLine, sal_Bool bHasToFit );
+ sal_Bool WouldFit( SwTxtMargin &rLine, SwTwips &rMaxHeight, sal_Bool bTest );
+ // OD 2004-02-25 #i16128# - rename method to avoid confusion with base class
+ // method <SwTxtFrmBreak::IsBreakNow>, which isn't virtual.
+ sal_Bool IsBreakNowWidAndOrp( SwTxtMargin &rLine )
+ {
+ return ( rLine.GetLineNr() > nOrphLines ) && IsBreakNow( rLine );
+ }
+};
+
+
+#endif
diff --git a/sw/source/core/text/wrong.cxx b/sw/source/core/text/wrong.cxx
new file mode 100644
index 000000000000..6029b6c84aeb
--- /dev/null
+++ b/sw/source/core/text/wrong.cxx
@@ -0,0 +1,644 @@
+/*************************************************************************
+ *
+ * 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 <tools/string.hxx>
+#include <tools/debug.hxx>
+#include "errhdl.hxx"
+#include "swtypes.hxx"
+#include "txttypes.hxx"
+
+#include "SwGrammarMarkUp.hxx"
+
+
+/*************************************************************************
+ * SwWrongList::SwWrongList()
+ *************************************************************************/
+SwWrongList::SwWrongList( WrongListType eType ) :
+ meType (eType),
+ nBeginInvalid(STRING_LEN), // everything correct... (the invalid area starts beyond the string)
+ nEndInvalid (STRING_LEN)
+{
+ maList.reserve( 5 );
+}
+
+SwWrongList::~SwWrongList()
+{
+ ClearList();
+}
+
+/*************************************************************************
+ * SwWrongList* SwWrongList::Clone()
+ *************************************************************************/
+
+SwWrongList* SwWrongList::Clone()
+{
+ SwWrongList* pClone = new SwWrongList( meType );
+ pClone->CopyFrom( *this );
+ return pClone;
+}
+
+/*************************************************************************
+ * void SwWrongList::CopyFrom( const SwWrongList& rCopy )
+ *************************************************************************/
+
+void SwWrongList::CopyFrom( const SwWrongList& rCopy )
+{
+ maList = rCopy.maList;
+ meType = rCopy.meType;
+ nBeginInvalid = rCopy.nBeginInvalid;
+ nEndInvalid = rCopy.nEndInvalid;
+ for( size_t i = 0; i < maList.size(); ++i )
+ {
+ if( maList[i].mpSubList )
+ maList[i].mpSubList = maList[i].mpSubList->Clone();
+ }
+}
+
+/*************************************************************************
+ * SwWrongList::ClearList()
+ *************************************************************************/
+void SwWrongList::ClearList()
+{
+ for ( size_t i = 0; i < maList.size(); ++i)
+ {
+ if (maList[i].mpSubList)
+ delete maList[i].mpSubList;
+ maList[i].mpSubList = NULL;
+ }
+ maList.clear();
+}
+
+/*************************************************************************
+ * sal_Bool SwWrongList::InWrongWord() gibt den Anfang und die Laenge des
+ * Wortes zurueck, wenn es als falsch markiert ist.
+ *************************************************************************/
+sal_Bool SwWrongList::InWrongWord( xub_StrLen &rChk, xub_StrLen &rLn ) const
+{
+ MSHORT nPos = GetWrongPos( rChk );
+ xub_StrLen nWrPos;
+ if( nPos < Count() && ( nWrPos = Pos( nPos ) ) <= rChk )
+ {
+ rLn = Len( nPos );
+ if( nWrPos + rLn <= rChk )
+ return sal_False;
+ rChk = nWrPos;
+ return sal_True;
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * sal_Bool SwWrongList::Check() liefert den ersten falschen Bereich
+ *************************************************************************/
+sal_Bool SwWrongList::Check( xub_StrLen &rChk, xub_StrLen &rLn ) const
+{
+ MSHORT nPos = GetWrongPos( rChk );
+ rLn = rLn + rChk;
+ xub_StrLen nWrPos;
+
+ if( nPos == Count() )
+ return sal_False;
+
+ xub_StrLen nEnd = Len( nPos );
+ nEnd = nEnd + ( nWrPos = Pos( nPos ) );
+ if( nEnd == rChk )
+ {
+ ++nPos;
+ if( nPos == Count() )
+ return sal_False;
+ else
+ {
+ nEnd = Len( nPos );
+ nEnd = nEnd + ( nWrPos = Pos( nPos ) );
+ }
+ }
+ if( nEnd > rChk && nWrPos < rLn )
+ {
+ if( nWrPos > rChk )
+ rChk = nWrPos;
+ if( nEnd < rLn )
+ rLn = nEnd;
+ rLn = rLn - rChk;
+ return 0 != rLn;
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * xub_StrLen SwWrongList::NextWrong() liefert die naechste Fehlerposition
+ *************************************************************************/
+
+xub_StrLen SwWrongList::NextWrong( xub_StrLen nChk ) const
+{
+ xub_StrLen nRet;
+ xub_StrLen nPos = GetWrongPos( nChk );
+ if( nPos < Count() )
+ {
+ nRet = Pos( nPos );
+ if( nRet < nChk && nRet + Len( nPos ) <= nChk )
+ {
+ if( ++nPos < Count() )
+ nRet = Pos( nPos );
+ else
+ nRet = STRING_LEN;
+ }
+ }
+ else
+ nRet = STRING_LEN;
+ if( nRet > GetBeginInv() && nChk < GetEndInv() )
+ nRet = nChk > GetBeginInv() ? nChk : GetBeginInv();
+ return nRet;
+}
+
+/*************************************************************************
+ * MSHORT SwWrongList::GetWrongPos( xub_StrLen nValue )
+ * sucht die erste Position im Array, die groessergleich nValue ist,
+ * dies kann natuerlich auch hinter dem letzten Element sein!
+ *************************************************************************/
+
+MSHORT SwWrongList::GetWrongPos( xub_StrLen nValue ) const
+{
+ MSHORT nOben = Count(), nMitte = 0, nUnten = 0;
+
+ if( nOben > 0 )
+ {
+ // For smart tag lists, we may not use a binary search. We return the
+ // position of the first smart tag which coveres nValue
+ if ( 0 != maList[0].maType.getLength() || maList[0].mpSubList )
+ {
+ std::vector<SwWrongArea>::const_iterator aIter = maList.begin();
+ while ( aIter != maList.end() )
+ {
+ const xub_StrLen nSTPos = (*aIter).mnPos;
+ const xub_StrLen nSTLen = (*aIter).mnLen;
+ if ( nSTPos <= nValue && nValue < nSTPos + nSTLen )
+ break;
+ else if ( nSTPos > nValue )
+ break;
+
+ ++aIter;
+ ++nUnten;
+ }
+ return nUnten;
+ }
+
+ --nOben;
+ while( nUnten <= nOben )
+ {
+ nMitte = nUnten + ( nOben - nUnten ) / 2;
+ xub_StrLen nTmp = Pos( nMitte );
+ if( nTmp == nValue )
+ {
+ nUnten = nMitte;
+ break;
+ }
+ else if( nTmp < nValue )
+ {
+ if( nTmp + Len( nMitte ) >= nValue )
+ {
+ nUnten = nMitte;
+ break;
+ }
+ nUnten = nMitte + 1;
+ }
+ else if( nMitte == 0 )
+ {
+ break;
+ }
+ else
+ nOben = nMitte - 1;
+ }
+ }
+
+ // nUnten now points to an index i into the wrong list which
+ // 1. nValue is inside [ Area[i].pos, Area[i].pos + Area[i].len ] (inkl!!!)
+ // 2. nValue < Area[i].pos
+
+ return nUnten;
+}
+
+/*************************************************************************
+ * void SwWrongList::_Invalidate()
+ *************************************************************************/
+
+void SwWrongList::_Invalidate( xub_StrLen nBegin, xub_StrLen nEnd )
+{
+ if ( nBegin < GetBeginInv() )
+ nBeginInvalid = nBegin;
+ if ( nEnd > GetEndInv() )
+ nEndInvalid = nEnd;
+}
+
+void SwWrongList::SetInvalid( xub_StrLen nBegin, xub_StrLen nEnd )
+{
+ nBeginInvalid = nBegin;
+ nEndInvalid = nEnd;
+}
+
+
+/*************************************************************************
+ * SwWrongList::Move( xub_StrLen nPos, long nDiff )
+ * veraendert alle Positionen ab nPos um den angegebenen Wert,
+ * wird nach Einfuegen oder Loeschen von Buchstaben benoetigt.
+ *************************************************************************/
+
+void SwWrongList::Move( xub_StrLen nPos, long nDiff )
+{
+ MSHORT i = GetWrongPos( nPos );
+ if( nDiff < 0 )
+ {
+ xub_StrLen nEnd = nPos + xub_StrLen( -nDiff );
+ MSHORT nLst = i;
+ xub_StrLen nWrPos;
+ xub_StrLen nWrLen;
+ sal_Bool bJump = sal_False;
+ while( nLst < Count() && Pos( nLst ) < nEnd )
+ ++nLst;
+ if( nLst > i && ( nWrPos = Pos( nLst - 1 ) ) <= nPos )
+ {
+ nWrLen = Len( nLst - 1 );
+ // calculate new length of word
+ nWrLen = ( nEnd > nWrPos + nWrLen ) ?
+ nPos - nWrPos :
+ static_cast<xub_StrLen>(nWrLen + nDiff);
+ if( nWrLen )
+ {
+ maList[--nLst].mnLen = nWrLen;
+ bJump = sal_True;
+ }
+ }
+ Remove( i, nLst - i );
+
+ if ( bJump )
+ ++i;
+ if( STRING_LEN == GetBeginInv() )
+ SetInvalid( nPos ? nPos - 1 : nPos, nPos + 1 );
+ else
+ {
+ ShiftLeft( nBeginInvalid, nPos, nEnd );
+ ShiftLeft( nEndInvalid, nPos, nEnd );
+ _Invalidate( nPos ? nPos - 1 : nPos, nPos + 1 );
+ }
+ }
+ else
+ {
+ xub_StrLen nWrPos;
+ xub_StrLen nEnd = nPos + xub_StrLen( nDiff );
+ if( STRING_LEN != GetBeginInv() )
+ {
+ if( nBeginInvalid > nPos )
+ nBeginInvalid = nBeginInvalid + xub_StrLen( nDiff );
+ if( nEndInvalid >= nPos )
+ nEndInvalid = nEndInvalid + xub_StrLen( nDiff );
+ }
+ // Wenn wir mitten in einem falschen Wort stehen, muss vom Wortanfang
+ // invalidiert werden.
+ if( i < Count() && nPos >= ( nWrPos = Pos( i ) ) )
+ {
+ Invalidate( nWrPos, nEnd );
+ xub_StrLen nWrLen = Len( i ) + xub_StrLen( nDiff );
+ maList[i++].mnLen = nWrLen;
+ nWrLen = nWrLen + nWrPos;
+ Invalidate( nWrPos, nWrLen );
+ }
+ else
+ Invalidate( nPos, nEnd );
+ }
+ while( i < Count() )
+ {
+ const xub_StrLen nTmp = static_cast<xub_StrLen>(nDiff + maList[i].mnPos);
+ maList[i++].mnPos = nTmp;
+ }
+}
+
+/*************************************************************************
+ * SwWrongList::Fresh
+ *
+ * For a given range [nPos, nPos + nLen[ and an index nIndex, this function
+ * basically counts the number of SwWrongArea entries starting with nIndex
+ * up to nPos + nLen. All these entries are removed.
+ *************************************************************************/
+sal_Bool SwWrongList::Fresh( xub_StrLen &rStart, xub_StrLen &rEnd, xub_StrLen nPos,
+ xub_StrLen nLen, MSHORT nIndex, xub_StrLen nCursorPos )
+{
+ // length of word must be greater than 0 and cursor position must be outside the word
+ sal_Bool bRet = nLen && ( nCursorPos > nPos + nLen || nCursorPos < nPos );
+
+ xub_StrLen nWrPos = 0;
+ xub_StrLen nWrEnd = rEnd;
+ MSHORT nCnt = nIndex;
+ if( nCnt < Count() && ( nWrPos = Pos( nIndex ) ) < nPos )
+ {
+ if( rStart > nWrPos )
+ rStart = nWrPos;
+ }
+
+ while( nCnt < Count() && ( nWrPos = Pos( nCnt ) ) < nPos )
+ nWrEnd = nWrPos + Len( nCnt++ );
+
+ if( nCnt < Count() && nWrPos == nPos && Len( nCnt ) == nLen )
+ {
+ ++nCnt;
+ bRet = sal_True;
+ }
+ else
+ {
+ if( bRet )
+ {
+ if( rStart > nPos )
+ rStart = nPos;
+ nWrEnd = nPos + nLen;
+ }
+ }
+
+ nPos = nPos + nLen;
+
+ if( nCnt < Count() && ( nWrPos = Pos( nCnt ) ) < nPos )
+ {
+ if( rStart > nWrPos )
+ rStart = nWrPos;
+ }
+
+ while( nCnt < Count() && ( nWrPos = Pos( nCnt ) ) < nPos )
+ nWrEnd = nWrPos + Len( nCnt++ );
+
+ if( rEnd < nWrEnd )
+ rEnd = nWrEnd;
+
+ Remove( nIndex, nCnt - nIndex );
+
+ return bRet;
+}
+
+void SwWrongList::Invalidate( xub_StrLen nBegin, xub_StrLen nEnd )
+{
+ if (STRING_LEN == GetBeginInv())
+ SetInvalid( nBegin, nEnd );
+ else
+ _Invalidate( nBegin, nEnd );
+}
+
+sal_Bool SwWrongList::InvalidateWrong( )
+{
+ if( Count() )
+ {
+ xub_StrLen nFirst = Pos( 0 );
+ xub_StrLen nLast = Pos( Count() - 1 ) + Len( Count() - 1 );
+ Invalidate( nFirst, nLast );
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+SwWrongList* SwWrongList::SplitList( xub_StrLen nSplitPos )
+{
+ SwWrongList *pRet = NULL;
+ MSHORT nLst = 0;
+ xub_StrLen nWrPos;
+ xub_StrLen nWrLen;
+ while( nLst < Count() && Pos( nLst ) < nSplitPos )
+ ++nLst;
+ if( nLst && ( nWrPos = Pos( nLst - 1 ) )
+ + ( nWrLen = Len( nLst - 1 ) ) > nSplitPos )
+ {
+ nWrLen += nWrPos - nSplitPos;
+ maList[--nLst].mnPos = nSplitPos;
+ maList[nLst].mnLen = nWrLen;
+ }
+ if( nLst )
+ {
+ if( WRONGLIST_GRAMMAR == GetWrongListType() )
+ pRet = new SwGrammarMarkUp();
+ else
+ pRet = new SwWrongList( GetWrongListType() );
+ pRet->Insert(0, maList.begin(), ( nLst >= maList.size() ? maList.end() : maList.begin() + nLst ) );
+ pRet->SetInvalid( GetBeginInv(), GetEndInv() );
+ pRet->_Invalidate( nSplitPos ? nSplitPos - 1 : nSplitPos, nSplitPos );
+ Remove( 0, nLst );
+ }
+ if( STRING_LEN == GetBeginInv() )
+ SetInvalid( 0, 1 );
+ else
+ {
+ ShiftLeft( nBeginInvalid, 0, nSplitPos );
+ ShiftLeft( nEndInvalid, 0, nSplitPos );
+ _Invalidate( 0, 1 );
+ }
+ nLst = 0;
+ while( nLst < Count() )
+ {
+ nWrPos = maList[nLst].mnPos - nSplitPos;
+ maList[nLst++].mnPos = nWrPos;
+ }
+ return pRet;
+}
+
+void SwWrongList::JoinList( SwWrongList* pNext, xub_StrLen nInsertPos )
+{
+ if (pNext)
+ {
+ DBG_ASSERT( GetWrongListType() == pNext->GetWrongListType(), "type mismatch with next list" );
+ }
+ if( pNext )
+ {
+ USHORT nCnt = Count();
+ pNext->Move( 0, nInsertPos );
+ Insert(nCnt, pNext->maList.begin(), pNext->maList.end());
+
+ Invalidate( pNext->GetBeginInv(), pNext->GetEndInv() );
+ if( nCnt && Count() > nCnt )
+ {
+ xub_StrLen nWrPos = Pos( nCnt );
+ xub_StrLen nWrLen = Len( nCnt );
+ if( !nWrPos )
+ {
+ nWrPos = nWrPos + nInsertPos;
+ nWrLen = nWrLen - nInsertPos;
+ maList[nCnt].mnPos = nWrPos;
+ maList[nCnt].mnLen = nWrLen;
+ }
+ if( nWrPos == Pos( nCnt - 1 ) + Len( nCnt - 1 ) )
+ {
+ nWrLen = nWrLen + Len( nCnt - 1 );
+ maList[nCnt - 1].mnLen = nWrLen;
+ Remove( nCnt, 1 );
+ }
+ }
+ }
+ Invalidate( nInsertPos ? nInsertPos - 1 : nInsertPos, nInsertPos + 1 );
+}
+
+
+void SwWrongList::InsertSubList( xub_StrLen nNewPos, xub_StrLen nNewLen, USHORT nWhere, SwWrongList* pSubList )
+{
+ if (pSubList)
+ {
+ DBG_ASSERT( GetWrongListType() == pSubList->GetWrongListType(), "type mismatch with sub list" );
+ }
+ std::vector<SwWrongArea>::iterator i = maList.begin();
+ if ( nWhere >= maList.size() )
+ i = maList.end(); // robust
+ else
+ i += nWhere;
+ maList.insert(i, SwWrongArea( rtl::OUString(), 0, nNewPos, nNewLen, pSubList ) );
+}
+
+
+// New functions: Necessary because SwWrongList has been changed to use std::vector
+void SwWrongList::Insert(USHORT nWhere, std::vector<SwWrongArea>::iterator startPos, std::vector<SwWrongArea>::iterator endPos)
+{
+ std::vector<SwWrongArea>::iterator i = maList.begin();
+ if ( nWhere >= maList.size() )
+ i = maList.end(); // robust
+ else
+ i += nWhere;
+ maList.insert(i, startPos, endPos); // insert [startPos, endPos[ before i
+
+ // ownership of the sublist is passed to maList, therefore we have to set the
+ // pSubList-Pointers to 0
+ while ( startPos != endPos )
+ {
+ (*startPos).mpSubList = 0;
+ ++startPos;
+ }
+}
+
+void SwWrongList::Remove(USHORT nIdx, USHORT nLen )
+{
+ if ( nIdx >= maList.size() ) return;
+ std::vector<SwWrongArea>::iterator i1 = maList.begin();
+ i1 += nIdx;
+
+ std::vector<SwWrongArea>::iterator i2 = i1;
+ if ( nIdx + nLen >= static_cast<USHORT>(maList.size()) )
+ i2 = maList.end(); // robust
+ else
+ i2 += nLen;
+
+ std::vector<SwWrongArea>::iterator iLoop = i1;
+ while ( iLoop != i2 )
+ {
+ if ( (*iLoop).mpSubList )
+ delete (*iLoop).mpSubList;
+ ++iLoop;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ const int nOldSize = Count();
+ (void) nOldSize;
+#endif
+
+ maList.erase(i1, i2);
+
+#if OSL_DEBUG_LEVEL > 1
+ ASSERT( Count() + nLen == nOldSize, "SwWrongList::Remove() trouble" )
+#endif
+}
+
+void SwWrongList::RemoveEntry( xub_StrLen nBegin, xub_StrLen nEnd ) {
+ USHORT nDelPos = 0;
+ USHORT nDel = 0;
+ std::vector<SwWrongArea>::iterator aIter = maList.begin();
+ while( aIter != maList.end() && (*aIter).mnPos < nBegin )
+ {
+ ++aIter;
+ ++nDelPos;
+ }
+ if( WRONGLIST_GRAMMAR == GetWrongListType() )
+ {
+ while( aIter != maList.end() && nBegin < nEnd && nEnd > (*aIter).mnPos )
+ {
+ ++aIter;
+ ++nDel;
+ }
+ }
+ else
+ {
+ while( aIter != maList.end() && nBegin == (*aIter).mnPos && nEnd == (*aIter).mnPos +(*aIter).mnLen )
+ {
+ ++aIter;
+ ++nDel;
+ }
+ }
+ if( nDel )
+ Remove( nDelPos, nDel );
+}
+
+bool SwWrongList::LookForEntry( xub_StrLen nBegin, xub_StrLen nEnd ) {
+ std::vector<SwWrongArea>::iterator aIter = maList.begin();
+ while( aIter != maList.end() && (*aIter).mnPos < nBegin )
+ ++aIter;
+ if( aIter != maList.end() && nBegin == (*aIter).mnPos && nEnd == (*aIter).mnPos +(*aIter).mnLen )
+ return true;
+ return false;
+}
+
+void SwWrongList::Insert( const rtl::OUString& rType,
+ com::sun::star::uno::Reference< com::sun::star::container::XStringKeyMap > xPropertyBag,
+ xub_StrLen nNewPos, xub_StrLen nNewLen )
+{
+ std::vector<SwWrongArea>::iterator aIter = maList.begin();
+
+ while ( aIter != maList.end() )
+ {
+ const xub_StrLen nSTPos = (*aIter).mnPos;
+
+ if ( nNewPos < nSTPos )
+ {
+ // insert at current position
+ break;
+ }
+ else if ( nNewPos == nSTPos )
+ {
+ while ( aIter != maList.end() && (*aIter).mnPos == nSTPos )
+ {
+ const xub_StrLen nSTLen = (*aIter).mnLen;
+
+ if ( nNewLen < nSTLen )
+ {
+ // insert at current position
+ break;
+ }
+
+ ++aIter;
+ }
+
+ break;
+ }
+
+ ++aIter;
+ }
+
+ maList.insert(aIter, SwWrongArea( rType, xPropertyBag, nNewPos, nNewLen, 0 ) );
+}
+
+