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