xref: /aoo41x/main/sw/source/core/text/itratr.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 #include <editeng/charscaleitem.hxx>
34 #include <txtatr.hxx>
35 #include <sfx2/printer.hxx>
36 #include <svx/svdobj.hxx>
37 #include <vcl/window.hxx>
38 #include <vcl/svapp.hxx>
39 #include <fmtanchr.hxx>
40 #include <fmtfsize.hxx>
41 #include <fmtornt.hxx>
42 #include <fmtflcnt.hxx>
43 #include <fmtcntnt.hxx>
44 #include <fmtftn.hxx>
45 #include <frmatr.hxx>
46 #include <frmfmt.hxx>
47 #include <fmtfld.hxx>
48 #include <doc.hxx>
49 #include <viewsh.hxx>	// ViewShell
50 #include <rootfrm.hxx>
51 #include <docary.hxx>
52 #include <ndtxt.hxx>
53 #include <dcontact.hxx>
54 #include <fldbas.hxx>      // SwField
55 #include <pam.hxx>         // SwPosition		(lcl_MinMaxNode)
56 #include <itratr.hxx>
57 #include <htmltbl.hxx>
58 #include <swtable.hxx>
59 #include <redlnitr.hxx>
60 #include <fmtsrnd.hxx>
61 #include <itrtxt.hxx>
62 #include <breakit.hxx>
63 #include <com/sun/star/i18n/WordType.hpp>
64 #include <com/sun/star/i18n/ScriptType.hdl>
65 #include <editeng/lrspitem.hxx>
66 #include <switerator.hxx>
67 
68 using namespace ::com::sun::star::i18n;
69 using namespace ::com::sun::star;
70 
71 /*************************************************************************
72  *						SwAttrIter::Chg()
73  *************************************************************************/
74 
75 void SwAttrIter::Chg( SwTxtAttr *pHt )
76 {
77     ASSERT( pHt && pFnt, "No attribute of font available for change");
78     if( pRedln && pRedln->IsOn() )
79         pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True );
80 	else
81         aAttrHandler.PushAndChg( *pHt, *pFnt );
82 	nChgCnt++;
83 }
84 
85 /*************************************************************************
86  *						SwAttrIter::Rst()
87  *************************************************************************/
88 
89 void SwAttrIter::Rst( SwTxtAttr *pHt )
90 {
91     ASSERT( pHt && pFnt, "No attribute of font available for reset");
92     // get top from stack after removing pHt
93     if( pRedln && pRedln->IsOn() )
94         pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False );
95 	else
96         aAttrHandler.PopAndChg( *pHt, *pFnt );
97 	nChgCnt--;
98 }
99 
100 /*************************************************************************
101  *				virtual SwAttrIter::~SwAttrIter()
102  *************************************************************************/
103 
104 SwAttrIter::~SwAttrIter()
105 {
106 	delete pRedln;
107 	delete pFnt;
108 }
109 
110 /*************************************************************************
111  *						SwAttrIter::GetAttr()
112  *
113  * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf
114  * der Position nPos liegt und kein EndIndex besitzt.
115  * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen
116  * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten"
117  * Attribute sind z.B. Felder (die expandierten Text bereit halten) und
118  * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen
119  * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs
120  * an der Startposition ein Sonderzeichen in den String einfuegt.
121  * Der Formatierer stoesst auf das Sonderzeichen und holt sich per
122  * GetAttr() das entartete Attribut.
123  *************************************************************************/
124 
125 SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const
126 {
127     return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0;
128 }
129 
130 /*************************************************************************
131  *						  SwAttrIter::SeekAndChg()
132  *************************************************************************/
133 
134 sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut )
135 {
136 	sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos );
137 	if ( pLastOut != pOut )
138 	{
139 		pLastOut = pOut;
140 		pFnt->SetFntChg( sal_True );
141 		bChg = sal_True;
142 	}
143 	if( bChg )
144 	{
145 		// wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
146 		// des gewuenschten Fonts ...
147 		if ( !nChgCnt && !nPropFont )
148 			pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
149 				aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
150         pFnt->ChgPhysFnt( pShell, *pOut );
151 	}
152 	return bChg;
153 }
154 
155 sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos )
156 {
157 	Seek( nNewPos );
158 	if ( !nChgCnt && !nPropFont )
159 		pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
160 			aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
161 	return pFnt->IsSymbol( pShell );
162 }
163 
164 /*************************************************************************
165  *						  SwAttrIter::SeekStartAndChg()
166  *************************************************************************/
167 
168 sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont )
169 {
170     if ( pRedln && pRedln->ExtOn() )
171         pRedln->LeaveExtend( *pFnt, 0 );
172 
173     // reset font to its original state
174     aAttrHandler.Reset();
175     aAttrHandler.ResetFont( *pFnt );
176 
177     nStartIndex = nEndIndex = nPos = nChgCnt = 0;
178 	if( nPropFont )
179 		pFnt->SetProportion( nPropFont );
180     if( pRedln )
181 	{
182 		pRedln->Clear( pFnt );
183 		if( !bParaFont )
184 			nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN );
185 		else
186 			pRedln->Reset();
187 	}
188 
189 	if ( pHints && !bParaFont )
190 	{
191 		SwTxtAttr *pTxtAttr;
192 		// Solange wir noch nicht am Ende des StartArrays angekommen sind &&
193 		// das TextAttribut an Position 0 beginnt ...
194 		while ( ( nStartIndex < pHints->GetStartCount() ) &&
195 				!(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) )
196 		{
197 			// oeffne die TextAttribute
198 			Chg( pTxtAttr );
199 			nStartIndex++;
200 		}
201 	}
202 
203 	sal_Bool bChg = pFnt->IsFntChg();
204 	if ( pLastOut != pOut )
205 	{
206 		pLastOut = pOut;
207 		pFnt->SetFntChg( sal_True );
208 		bChg = sal_True;
209 	}
210 	if( bChg )
211 	{
212 		// wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
213 		// des gewuenschten Fonts ...
214 		if ( !nChgCnt && !nPropFont )
215 			pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
216 				aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
217         pFnt->ChgPhysFnt( pShell, *pOut );
218 	}
219 	return bChg;
220 }
221 
222 /*************************************************************************
223  *						 SwAttrIter::SeekFwd()
224  *************************************************************************/
225 
226 // AMA: Neuer AttrIter Nov 94
227 
228 void SwAttrIter::SeekFwd( const xub_StrLen nNewPos )
229 {
230 	SwTxtAttr *pTxtAttr;
231 
232 	if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden...
233 	{
234 		// Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden.
235 
236 		// Solange wir noch nicht am Ende des EndArrays angekommen sind &&
237 		// das TextAttribut vor oder an der neuen Position endet ...
238 		while ( ( nEndIndex < pHints->GetEndCount() ) &&
239 				(*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
240 		{
241 			// schliesse die TextAttribute, deren StartPos vor
242 			// oder an der alten nPos lag, die z.Z. geoeffnet sind.
243 			if (*pTxtAttr->GetStart() <= nPos)	Rst( pTxtAttr );
244 			nEndIndex++;
245 		}
246 	}
247 	else // ueberlies die nicht geoeffneten Enden
248 	{
249 		while ( ( nEndIndex < pHints->GetEndCount() ) &&
250 				(*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
251 		{
252 			nEndIndex++;
253 		}
254 	}
255 	// Solange wir noch nicht am Ende des StartArrays angekommen sind &&
256 	// das TextAttribut vor oder an der neuen Position beginnt ...
257 	while ( ( nStartIndex < pHints->GetStartCount() ) &&
258 		   (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos))
259 	{
260 		// oeffne die TextAttribute, deren Ende hinter der neuen Position liegt
261 		if ( *pTxtAttr->GetAnyEnd() > nNewPos )  Chg( pTxtAttr );
262 		nStartIndex++;
263 	}
264 
265 }
266 
267 /*************************************************************************
268  *						 SwAttrIter::Seek()
269  *************************************************************************/
270 
271 sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos )
272 {
273     if ( pRedln && pRedln->ExtOn() )
274         pRedln->LeaveExtend( *pFnt, nNewPos );
275 
276 	if( pHints )
277 	{
278 		if( !nNewPos || nNewPos < nPos )
279 		{
280             if( pRedln )
281 				pRedln->Clear( NULL );
282 
283             // reset font to its original state
284             aAttrHandler.Reset();
285             aAttrHandler.ResetFont( *pFnt );
286 
287             if( nPropFont )
288 				pFnt->SetProportion( nPropFont );
289 			nStartIndex = nEndIndex = nPos = 0;
290 			nChgCnt = 0;
291 
292             // Achtung!
293             // resetting the font here makes it necessary to apply any
294             // changes for extended input directly to the font
295             if ( pRedln && pRedln->ExtOn() )
296             {
297                 pRedln->UpdateExtFont( *pFnt );
298                 ++nChgCnt;
299             }
300 		}
301 		SeekFwd( nNewPos );
302 	}
303 
304     pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) );
305 
306     if( pRedln )
307 		nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos );
308 	nPos = nNewPos;
309 
310 	if( nPropFont )
311 		pFnt->SetProportion( nPropFont );
312 
313 	return pFnt->IsFntChg();
314 }
315 
316 /*************************************************************************
317  *						SwAttrIter::GetNextAttr()
318  *************************************************************************/
319 
320 xub_StrLen SwAttrIter::GetNextAttr( ) const
321 {
322 	xub_StrLen nNext = STRING_LEN;
323 	if( pHints )
324 	{
325 		if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts?
326 		   nNext = (*pHints->GetStart(nStartIndex)->GetStart());
327 		if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden?
328 		{
329 			xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd());
330 			if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher?
331 		}
332 	}
333 	if (m_pTxtNode!=NULL) {
334 	    //TODO maybe use hints like FieldHints for this instead of looking at the text...
335 	    int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len());
336 	    sal_uInt16 p=nPos;
337 	    const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer();
338 	    while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++;
339 	    if ((p<l && p>nPos) || nNext<=p)
340 		nNext=p;
341 	    else
342 		nNext=p+1;
343 	}
344     if( pRedln )
345 		return pRedln->GetNextRedln( nNext );
346 	return nNext;
347 }
348 
349 #if OSL_DEBUG_LEVEL > 1
350 /*************************************************************************
351  *						SwAttrIter::Dump()
352  *************************************************************************/
353 
354 void SwAttrIter::Dump( SvStream &/*rOS*/ ) const
355 {
356 // Noch nicht an den neuen Attributiterator angepasst ...
357 }
358 
359 #endif
360 
361 class SwMinMaxArgs
362 {
363 public:
364     OutputDevice* pOut;
365     ViewShell* pSh;
366 	sal_uLong &rMin;
367 	sal_uLong &rMax;
368 	sal_uLong &rAbsMin;
369 	long nRowWidth;
370 	long nWordWidth;
371 	long nWordAdd;
372     xub_StrLen nNoLineBreak;
373     SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, sal_uLong& rMinI, sal_uLong &rMaxI, sal_uLong &rAbsI )
374 		: pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI )
375         { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; }
376 	void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; }
377 	void NewWord() { nWordAdd = nWordWidth = 0; }
378 };
379 
380 sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt,
381 	xub_StrLen nIdx, xub_StrLen nEnd )
382 {
383 	sal_Bool bRet = sal_False;
384 	while( nIdx < nEnd )
385 	{
386 		xub_StrLen nStop = nIdx;
387         sal_Bool bClear;
388         LanguageType eLang = pFnt->GetLanguage();
389         if( pBreakIt->GetBreakIter().is() )
390         {
391             bClear = CH_BLANK == rTxt.GetChar( nStop );
392             Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx,
393                              pBreakIt->GetLocale( eLang ),
394                              WordType::DICTIONARY_WORD, sal_True ) );
395             nStop = (xub_StrLen)aBndry.endPos;
396             if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
397                 rArg.NewWord();
398             if( nStop == nIdx )
399                 ++nStop;
400             if( nStop > nEnd )
401                 nStop = nEnd;
402         }
403         else
404         {
405             while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) )
406                 ++nStop;
407             bClear = nStop == nIdx;
408             if ( bClear )
409             {
410                 rArg.NewWord();
411                 while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) )
412                     ++nStop;
413             }
414         }
415 
416         SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx );
417         long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width();
418 		rArg.nRowWidth += nAktWidth;
419 		if( bClear )
420 			rArg.NewWord();
421 		else
422 		{
423 			rArg.nWordWidth += nAktWidth;
424 			if( (long)rArg.rAbsMin < rArg.nWordWidth )
425 				rArg.rAbsMin = rArg.nWordWidth;
426 			rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
427 			bRet = sal_True;
428 		}
429 		nIdx = nStop;
430     }
431 	return bRet;
432 }
433 
434 sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const//swmodtest 080307
435 {
436 	SwScriptInfo aScriptInfo;
437     SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
438     aIter.Seek( nBegin );
439     return aIter.GetFnt()->IsSymbol(
440 		const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()) );//swmod 080311
441 }
442 
443 class SwMinMaxNodeArgs
444 {
445 public:
446 	sal_uLong nMaxWidth;    // Summe aller Rahmenbreite
447 	long nMinWidth;		// Breitester Rahmen
448 	long nLeftRest;     // noch nicht von Rahmen ueberdeckter Platz im l. Rand
449 	long nRightRest;    // noch nicht von Rahmen ueberdeckter Platz im r. Rand
450 	long nLeftDiff;		// Min/Max-Differenz des Rahmens im linken Rand
451 	long nRightDiff;    // Min/Max-Differenz des Rahmens im rechten Rand
452 	sal_uLong nIndx;		// Indexnummer des Nodes
453 	void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
454 };
455 
456 sal_Bool lcl_MinMaxNode( const SwFrmFmtPtr& rpNd, void* pArgs )
457 {
458 	const SwFmtAnchor& rFmtA = ((SwFrmFmt*)rpNd)->GetAnchor();
459 
460 	bool bCalculate = false;
461     if ((FLY_AT_PARA == rFmtA.GetAnchorId()) ||
462         (FLY_AT_CHAR == rFmtA.GetAnchorId()))
463 	{
464 		bCalculate = true;
465 	}
466 
467 	if (bCalculate)
468 	{
469 		const SwMinMaxNodeArgs *pIn = (const SwMinMaxNodeArgs*)pArgs;
470 		const SwPosition *pPos = rFmtA.GetCntntAnchor();
471 		ASSERT(pPos && pIn, "Unexpected NULL arguments");
472 		if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
473 			bCalculate = false;
474 	}
475 
476 	if (bCalculate)
477 	{
478 		long nMin, nMax;
479 		SwHTMLTableLayout *pLayout = 0;
480 		MSHORT nWhich = ((SwFrmFmt*)rpNd)->Which();
481 		if( RES_DRAWFRMFMT != nWhich )
482 		{
483 			// Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle?
484             const SwNodes& rNodes = static_cast<SwFrmFmt*>(rpNd)->GetDoc()->GetNodes();
485             const SwFmtCntnt& rFlyCntnt = ((SwFrmFmt*)rpNd)->GetCntnt();
486 			sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex();
487             SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode();
488 			if( !pTblNd )
489 			{
490                 SwNode *pNd = rNodes[nStt];
491                 pNd = rNodes[pNd->EndOfSectionIndex()-1];
492 				if( pNd->IsEndNode() )
493 					pTblNd = pNd->StartOfSectionNode()->GetTableNode();
494 			}
495 
496 			if( pTblNd )
497 				pLayout = pTblNd->GetTable().GetHTMLTableLayout();
498 		}
499 
500 		const SwFmtHoriOrient& rOrient = ((SwFrmFmt*)rpNd)->GetHoriOrient();
501         sal_Int16 eHoriOri = rOrient.GetHoriOrient();
502 
503 		long nDiff;
504 		if( pLayout )
505 		{
506 			nMin = pLayout->GetMin();
507 			nMax = pLayout->GetMax();
508 			nDiff = nMax - nMin;
509 		}
510 		else
511 		{
512 			if( RES_DRAWFRMFMT == nWhich )
513 			{
514 				const SdrObject* pSObj = rpNd->FindSdrObject();
515 				if( pSObj )
516 					nMin = pSObj->GetCurrentBoundRect().GetWidth();
517 				else
518 				nMin = 0;
519 
520 			}
521 			else
522 			{
523 				const SwFmtFrmSize &rSz = ( (SwFrmFmt*)rpNd )->GetFrmSize();
524 				nMin = rSz.GetWidth();
525 			}
526 			nMax = nMin;
527 			nDiff = 0;
528 		}
529 
530 		const SvxLRSpaceItem &rLR = ( (SwFrmFmt*)rpNd )->GetLRSpace();
531 		nMin += rLR.GetLeft();
532 		nMin += rLR.GetRight();
533 		nMax += rLR.GetLeft();
534 		nMax += rLR.GetRight();
535 
536 		if( SURROUND_THROUGHT == ((SwFrmFmt*)rpNd)->GetSurround().GetSurround() )
537 		{
538 			( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
539 			return sal_True;
540 		}
541 
542 		// Rahmen, die recht bzw. links ausgerichtet sind, gehen nur
543 		// teilweise in die Max-Berechnung ein, da der Rand schon berueck-
544 		// sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen,
545 		// wird dieser Teil hinzuaddiert.
546 		switch( eHoriOri )
547 		{
548             case text::HoriOrientation::RIGHT:
549 			{
550 				if( nDiff )
551 				{
552 					((SwMinMaxNodeArgs*)pArgs)->nRightRest -=
553 						((SwMinMaxNodeArgs*)pArgs)->nRightDiff;
554 					((SwMinMaxNodeArgs*)pArgs)->nRightDiff = nDiff;
555 				}
556                 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
557 				{
558 					if( ((SwMinMaxNodeArgs*)pArgs)->nRightRest > 0 )
559 						((SwMinMaxNodeArgs*)pArgs)->nRightRest = 0;
560 				}
561 				((SwMinMaxNodeArgs*)pArgs)->nRightRest -= nMin;
562 				break;
563 			}
564             case text::HoriOrientation::LEFT:
565 			{
566 				if( nDiff )
567 				{
568 					((SwMinMaxNodeArgs*)pArgs)->nLeftRest -=
569 						((SwMinMaxNodeArgs*)pArgs)->nLeftDiff;
570 					((SwMinMaxNodeArgs*)pArgs)->nLeftDiff = nDiff;
571 				}
572                 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
573 					((SwMinMaxNodeArgs*)pArgs)->nLeftRest < 0 )
574 					((SwMinMaxNodeArgs*)pArgs)->nLeftRest = 0;
575 				((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= nMin;
576 				break;
577 			}
578 			default:
579 			{
580 				( (SwMinMaxNodeArgs*)pArgs )->nMaxWidth += nMax;
581 				( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
582 			}
583 		}
584 	}
585 	return sal_True;
586 }
587 
588 #define FLYINCNT_MIN_WIDTH 284
589 
590 // changing this method very likely requires changing of
591 // "GetScalingOfSelectedText"
592 void SwTxtNode::GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax,
593 							   sal_uLong& rAbsMin, OutputDevice* pOut ) const
594 {
595     ViewShell* pSh = 0;
596 	GetDoc()->GetEditShell( &pSh );
597 	if( !pOut )
598 	{
599         if( pSh )
600 			pOut = pSh->GetWin();
601 		if( !pOut )
602 			pOut = GetpApp()->GetDefaultDevice();
603 	}
604 
605 	MapMode aOldMap( pOut->GetMapMode() );
606 	pOut->SetMapMode( MapMode( MAP_TWIP ) );
607 
608 	rMin = 0;
609 	rMax = 0;
610 	rAbsMin = 0;
611 
612 	const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
613 	long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True );
614 	short nFLOffs;
615 	// Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich
616 	// bereits gefuellt...
617 	if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
618 		nLROffset = nFLOffs;
619 
620 	SwMinMaxNodeArgs aNodeArgs;
621 	aNodeArgs.nMinWidth = 0;
622 	aNodeArgs.nMaxWidth = 0;
623 	aNodeArgs.nLeftRest = nLROffset;
624 	aNodeArgs.nRightRest = rSpace.GetRight();
625 	aNodeArgs.nLeftDiff = 0;
626 	aNodeArgs.nRightDiff = 0;
627 	if( nIndex )
628 	{
629 		SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts();
630 		if( pTmp )
631 		{
632 			aNodeArgs.nIndx = nIndex;
633 			pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs );
634 		}
635 	}
636 	if( aNodeArgs.nLeftRest < 0 )
637 		aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
638 	aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
639 	if( aNodeArgs.nLeftRest < 0 )
640 		aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
641 
642 	if( aNodeArgs.nRightRest < 0 )
643 		aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
644 	aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
645 	if( aNodeArgs.nRightRest < 0 )
646 		aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
647 
648 	SwScriptInfo aScriptInfo;
649     SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
650 	xub_StrLen nIdx = 0;
651 	aIter.SeekAndChgAttrIter( nIdx, pOut );
652     xub_StrLen nLen = m_Text.Len();
653 	long nAktWidth = 0;
654 	MSHORT nAdd = 0;
655     SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
656 	while( nIdx < nLen )
657 	{
658 		xub_StrLen nNextChg = aIter.GetNextAttr();
659 		xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
660 		if( nNextChg > nStop )
661 			nNextChg = nStop;
662 		SwTxtAttr *pHint = NULL;
663 		xub_Unicode cChar = CH_BLANK;
664 		nStop = nIdx;
665 		while( nStop < nLen && nStop < nNextChg &&
666                CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) &&
667                CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
668                CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
669                !pHint )
670 		{
671 			if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
672 				|| ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
673 				++nStop;
674 		}
675         if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
676         {
677 			nAdd = 20;
678         }
679 		nIdx = nStop;
680 		aIter.SeekAndChgAttrIter( nIdx, pOut );
681 		switch( cChar )
682 		{
683 			case CH_BREAK  :
684 			{
685 				if( (long)rMax < aArg.nRowWidth )
686 					rMax = aArg.nRowWidth;
687 				aArg.nRowWidth = 0;
688 				aArg.NewWord();
689 				aIter.SeekAndChgAttrIter( ++nIdx, pOut );
690 			}
691 			break;
692 			case CH_TAB    :
693 			{
694 				aArg.NewWord();
695 				aIter.SeekAndChgAttrIter( ++nIdx, pOut );
696 			}
697 			break;
698             case CHAR_SOFTHYPHEN:
699                 ++nIdx;
700             break;
701             case CHAR_HARDBLANK:
702             case CHAR_HARDHYPHEN:
703             {
704                 XubString sTmp( cChar );
705                 SwDrawTextInfo aDrawInf( const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()),
706 					*pOut, 0, sTmp, 0, 1, 0, sal_False );//swmod 080311
707                 nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
708                 aArg.nWordWidth += nAktWidth;
709                 aArg.nRowWidth += nAktWidth;
710                 if( (long)rAbsMin < aArg.nWordWidth )
711                     rAbsMin = aArg.nWordWidth;
712                 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
713                 aArg.nNoLineBreak = nIdx++;
714             }
715             break;
716 			case CH_TXTATR_BREAKWORD:
717 			case CH_TXTATR_INWORD:
718 			{
719 				if( !pHint )
720 					break;
721 				long nOldWidth = aArg.nWordWidth;
722 				long nOldAdd = aArg.nWordAdd;
723 				aArg.NewWord();
724 
725 				switch( pHint->Which() )
726 				{
727 					case RES_TXTATR_FLYCNT :
728 					{
729 						SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt();
730 						const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace();
731 						if( RES_DRAWFRMFMT == pFrmFmt->Which() )
732 						{
733 							const SdrObject* pSObj = pFrmFmt->FindSdrObject();
734 							if( pSObj )
735 								nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
736 							else
737 								nAktWidth = 0;
738 						}
739 						else
740 						{
741 							const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize();
742 							if( RES_FLYFRMFMT == pFrmFmt->Which()
743 								&& rTmpSize.GetWidthPercent() )
744 							{
745 /*-----------------24.01.97 14:09----------------------------------------------
746  * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich
747  * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale
748  * Breite 0,5 cm und als maximale KSHRT_MAX.
749  * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt
750  * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen.
751  * --------------------------------------------------------------------------*/
752 								nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm
753 								if( (long)rMax < KSHRT_MAX )
754 									rMax = KSHRT_MAX;
755 							}
756 							else
757 								nAktWidth = pFrmFmt->GetFrmSize().GetWidth();
758 						}
759 						nAktWidth += rLR.GetLeft();
760 						nAktWidth += rLR.GetRight();
761 						aArg.nWordAdd = nOldWidth + nOldAdd;
762 						aArg.nWordWidth = nAktWidth;
763 						aArg.nRowWidth += nAktWidth;
764 						if( (long)rAbsMin < aArg.nWordWidth )
765 							rAbsMin = aArg.nWordWidth;
766 						aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
767 						break;
768 					}
769 					case RES_TXTATR_FTN :
770 					{
771 						const XubString aTxt = pHint->GetFtn().GetNumStr();
772 						if( lcl_MinMaxString( aArg, aIter.GetFnt(),	aTxt, 0,
773 							aTxt.Len() ) )
774 							nAdd = 20;
775 						break;
776 					}
777 					case RES_TXTATR_FIELD :
778 					{
779 						SwField *pFld = (SwField*)pHint->GetFld().GetFld();
780                         const String aTxt = pFld->ExpandField(true);
781 						if( lcl_MinMaxString( aArg, aIter.GetFnt(),	aTxt, 0,
782 							aTxt.Len() ) )
783 							nAdd = 20;
784 						break;
785 					}
786 					default: aArg.nWordWidth = nOldWidth;
787 							 aArg.nWordAdd = nOldAdd;
788 
789 				}
790 				aIter.SeekAndChgAttrIter( ++nIdx, pOut );
791 			}
792 			break;
793 		}
794 	}
795 	if( (long)rMax < aArg.nRowWidth )
796 		rMax = aArg.nRowWidth;
797 
798 	nLROffset += rSpace.GetRight();
799 
800 	rAbsMin += nLROffset;
801 	rAbsMin += nAdd;
802 	rMin += nLROffset;
803 	rMin += nAdd;
804 	if( (long)rMin < aNodeArgs.nMinWidth )
805 		rMin = aNodeArgs.nMinWidth;
806 	if( (long)rAbsMin < aNodeArgs.nMinWidth )
807 		rAbsMin = aNodeArgs.nMinWidth;
808 	rMax += aNodeArgs.nMaxWidth;
809 	rMax += nLROffset;
810 	rMax += nAdd;
811 	if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
812 		rMax = rMin;  // in das Minimum ein
813 	pOut->SetMapMode( aOldMap );
814 }
815 
816 /*************************************************************************
817  *						SwTxtNode::GetScalingOfSelectedText()
818  *
819  * Calculates the width of the text part specified by nStt and nEnd,
820  * the height of the line containing nStt is devided by this width,
821  * indicating the scaling factor, if the text part is rotated.
822  * Having CH_BREAKs in the text part, this method returns the scaling
823  * factor for the longest of the text parts separated by the CH_BREAKs.
824  *
825  * changing this method very likely requires changing of "GetMinMaxSize"
826  *************************************************************************/
827 
828 sal_uInt16 SwTxtNode::GetScalingOfSelectedText(	xub_StrLen nStt, xub_StrLen nEnd )
829 	const
830 {
831     ViewShell* pSh = NULL;
832     OutputDevice* pOut = NULL;
833 	GetDoc()->GetEditShell( &pSh );
834 
835     if ( pSh )
836         pOut = &pSh->GetRefDev();
837     else
838     {
839         //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
840         if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) )
841             pOut = GetpApp()->GetDefaultDevice();
842         else
843             pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
844     }
845 
846     ASSERT( pOut, "GetScalingOfSelectedText without outdev" )
847 
848     MapMode aOldMap( pOut->GetMapMode() );
849 	pOut->SetMapMode( MapMode( MAP_TWIP ) );
850 
851     if ( nStt == nEnd )
852     {
853         if ( !pBreakIt->GetBreakIter().is() )
854             return 100;
855 
856         SwScriptInfo aScriptInfo;
857         SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
858         aIter.SeekAndChgAttrIter( nStt, pOut );
859 
860         Boundary aBound =
861             pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
862             pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
863             WordType::DICTIONARY_WORD, sal_True );
864 
865         if ( nStt == aBound.startPos )
866         {
867             // cursor is at left or right border of word
868             pOut->SetMapMode( aOldMap );
869             return 100;
870         }
871 
872         nStt = (xub_StrLen)aBound.startPos;
873         nEnd = (xub_StrLen)aBound.endPos;
874 
875         if ( nStt == nEnd )
876         {
877             pOut->SetMapMode( aOldMap );
878             return 100;
879         }
880     }
881 
882     SwScriptInfo aScriptInfo;
883 	SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
884 
885     // We do not want scaling attributes to be considered during this
886     // calculation. For this, we push a temporary scaling attribute with
887     // scaling value 100 and priority flag on top of the scaling stack
888     SwAttrHandler& rAH = aIter.GetAttrHandler();
889     SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
890     SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
891     aAttr.SetPriorityAttr( sal_True );
892     rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
893 
894     xub_StrLen nIdx = nStt;
895 
896 	sal_uLong nWidth = 0;
897 	sal_uLong nProWidth = 0;
898 
899 	while( nIdx < nEnd )
900 	{
901 		aIter.SeekAndChgAttrIter( nIdx, pOut );
902 
903 		// scan for end of portion
904 		xub_StrLen nNextChg = aIter.GetNextAttr();
905 		xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
906 		if( nNextChg > nStop )
907 			nNextChg = nStop;
908 
909 		nStop = nIdx;
910 		xub_Unicode cChar = CH_BLANK;
911         SwTxtAttr* pHint = NULL;
912 
913         // stop at special characters in [ nIdx, nNextChg ]
914         while( nStop < nEnd && nStop < nNextChg )
915         {
916             cChar = m_Text.GetChar( nStop );
917             if (
918                 CH_TAB == cChar ||
919                 CH_BREAK == cChar ||
920                 CHAR_HARDBLANK == cChar ||
921                 CHAR_HARDHYPHEN == cChar ||
922                 CHAR_SOFTHYPHEN == cChar ||
923                 (
924                   (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
925                   (0 == (pHint = aIter.GetAttr(nStop)))
926                 )
927                )
928             {
929                 break;
930             }
931             else
932                 ++nStop;
933         }
934 
935 		// calculate text widths up to cChar
936         if ( nStop > nIdx )
937         {
938             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
939             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
940         }
941 
942 		nIdx = nStop;
943 		aIter.SeekAndChgAttrIter( nIdx, pOut );
944 
945 		if ( cChar == CH_BREAK )
946 		{
947 			nWidth = Max( nWidth, nProWidth );
948 			nProWidth = 0;
949 			nIdx++;
950 		}
951 		else if ( cChar == CH_TAB )
952 		{
953 			// tab receives width of one space
954             XubString sTmp( CH_BLANK );
955             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
956             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
957 			nIdx++;
958 		}
959         else if ( cChar == CHAR_SOFTHYPHEN )
960             ++nIdx;
961         else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
962         {
963             XubString sTmp( cChar );
964             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
965             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
966 			nIdx++;
967         }
968 		else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
969 		{
970 			switch( pHint->Which() )
971 			{
972 				case RES_TXTATR_FTN :
973 				{
974 					const XubString aTxt = pHint->GetFtn().GetNumStr();
975                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
976 
977                     nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
978 					break;
979 				}
980 				case RES_TXTATR_FIELD :
981 				{
982 					SwField *pFld = (SwField*)pHint->GetFld().GetFld();
983                     String const aTxt = pFld->ExpandField(true);
984                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
985 
986                     nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
987 					break;
988 				}
989 				default:
990 				{
991 				// any suggestions for a default action?
992 				}
993 			} // end of switch
994 			nIdx++;
995 		} // end of while
996 	}
997 
998 	nWidth = Max( nWidth, nProWidth );
999 
1000 	// search for a text frame this node belongs to
1001 	SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this );
1002     SwTxtFrm* pFrm = 0;
1003     for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() )
1004 	{
1005 			if ( pTmpFrm->GetOfst() <= nStt &&
1006 				( !pTmpFrm->GetFollow() ||
1007 				   pTmpFrm->GetFollow()->GetOfst() > nStt )	)
1008 			{
1009 				pFrm = pTmpFrm;
1010 				break;
1011 			}
1012 		}
1013 
1014 	// search for the line containing nStt
1015     if ( pFrm && pFrm->HasPara() )
1016 	{
1017 		SwTxtInfo aInf( pFrm );
1018         SwTxtIter aLine( pFrm, &aInf );
1019 		aLine.CharToLine( nStt );
1020         pOut->SetMapMode( aOldMap );
1021         return (sal_uInt16)( nWidth ?
1022 			( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1023 	}
1024 	// no frame or no paragraph, we take the height of the character
1025 	// at nStt as line height
1026 
1027     aIter.SeekAndChgAttrIter( nStt, pOut );
1028     pOut->SetMapMode( aOldMap );
1029 
1030     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
1031     return (sal_uInt16)
1032            ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
1033 }
1034 
1035 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const
1036 {
1037     sal_uInt16 nRet = 0;
1038 
1039     xub_StrLen nIdx = 0;
1040     sal_Unicode cCh;
1041 
1042     while ( nIdx < GetTxt().Len() &&
1043              ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
1044                 ' ' == cCh ) )
1045         ++nIdx;
1046 
1047     if ( nIdx > 0 )
1048     {
1049         SwPosition aPos( *this );
1050         aPos.nContent += nIdx;
1051 
1052         // Find the non-follow text frame:
1053 	    SwIterator<SwTxtFrm,SwTxtNode> aIter( *this );
1054         for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1055         {
1056             // Only consider master frames:
1057             if ( !pFrm->IsFollow() )
1058             {
1059                 SWRECTFN( pFrm )
1060                 SwRect aRect;
1061                 pFrm->GetCharRect( aRect, aPos );
1062                 nRet = (sal_uInt16)
1063                        ( pFrm->IsRightToLeft() ?
1064                             (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1065                             (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
1066                 break;
1067             }
1068         }
1069     }
1070 
1071     return nRet;
1072 }
1073