xref: /trunk/main/sw/source/core/text/itratr.cxx (revision c0286415)
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 					case RES_TXTATR_FIELD :
774 					{
775 						SwField *pFld = (SwField*)pHint->GetFmtFld().GetField();
776                         const String aTxt = pFld->ExpandField(true);
777 						if( lcl_MinMaxString( aArg, aIter.GetFnt(),	aTxt, 0,
778 							aTxt.Len() ) )
779 							nAdd = 20;
780 						break;
781 					}
782 					default: aArg.nWordWidth = nOldWidth;
783 							 aArg.nWordAdd = nOldAdd;
784 
785 				}
786 				aIter.SeekAndChgAttrIter( ++nIdx, pOut );
787 			}
788 			break;
789 		}
790 	}
791 	if( (long)rMax < aArg.nRowWidth )
792 		rMax = aArg.nRowWidth;
793 
794 	nLROffset += rSpace.GetRight();
795 
796 	rAbsMin += nLROffset;
797 	rAbsMin += nAdd;
798 	rMin += nLROffset;
799 	rMin += nAdd;
800 	if( (long)rMin < aNodeArgs.nMinWidth )
801 		rMin = aNodeArgs.nMinWidth;
802 	if( (long)rAbsMin < aNodeArgs.nMinWidth )
803 		rAbsMin = aNodeArgs.nMinWidth;
804 	rMax += aNodeArgs.nMaxWidth;
805 	rMax += nLROffset;
806 	rMax += nAdd;
807 	if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
808 		rMax = rMin;  // in das Minimum ein
809 	pOut->SetMapMode( aOldMap );
810 }
811 
812 /*************************************************************************
813  *						SwTxtNode::GetScalingOfSelectedText()
814  *
815  * Calculates the width of the text part specified by nStt and nEnd,
816  * the height of the line containing nStt is devided by this width,
817  * indicating the scaling factor, if the text part is rotated.
818  * Having CH_BREAKs in the text part, this method returns the scaling
819  * factor for the longest of the text parts separated by the CH_BREAKs.
820  *
821  * changing this method very likely requires changing of "GetMinMaxSize"
822  *************************************************************************/
823 
824 sal_uInt16 SwTxtNode::GetScalingOfSelectedText(	xub_StrLen nStt, xub_StrLen nEnd )
825 	const
826 {
827     ViewShell* pSh = NULL;
828     OutputDevice* pOut = NULL;
829 	GetDoc()->GetEditShell( &pSh );
830 
831     if ( pSh )
832         pOut = &pSh->GetRefDev();
833     else
834     {
835         //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
836         if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) )
837             pOut = GetpApp()->GetDefaultDevice();
838         else
839             pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
840     }
841 
842     ASSERT( pOut, "GetScalingOfSelectedText without outdev" )
843 
844     MapMode aOldMap( pOut->GetMapMode() );
845 	pOut->SetMapMode( MapMode( MAP_TWIP ) );
846 
847     if ( nStt == nEnd )
848     {
849         if ( !pBreakIt->GetBreakIter().is() )
850             return 100;
851 
852         SwScriptInfo aScriptInfo;
853         SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
854         aIter.SeekAndChgAttrIter( nStt, pOut );
855 
856         Boundary aBound =
857             pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
858             pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
859             WordType::DICTIONARY_WORD, sal_True );
860 
861         if ( nStt == aBound.startPos )
862         {
863             // cursor is at left or right border of word
864             pOut->SetMapMode( aOldMap );
865             return 100;
866         }
867 
868         nStt = (xub_StrLen)aBound.startPos;
869         nEnd = (xub_StrLen)aBound.endPos;
870 
871         if ( nStt == nEnd )
872         {
873             pOut->SetMapMode( aOldMap );
874             return 100;
875         }
876     }
877 
878     SwScriptInfo aScriptInfo;
879 	SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
880 
881     // We do not want scaling attributes to be considered during this
882     // calculation. For this, we push a temporary scaling attribute with
883     // scaling value 100 and priority flag on top of the scaling stack
884     SwAttrHandler& rAH = aIter.GetAttrHandler();
885     SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
886     SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
887     aAttr.SetPriorityAttr( sal_True );
888     rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
889 
890     xub_StrLen nIdx = nStt;
891 
892 	sal_uLong nWidth = 0;
893 	sal_uLong nProWidth = 0;
894 
895 	while( nIdx < nEnd )
896 	{
897 		aIter.SeekAndChgAttrIter( nIdx, pOut );
898 
899 		// scan for end of portion
900 		xub_StrLen nNextChg = aIter.GetNextAttr();
901 		xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
902 		if( nNextChg > nStop )
903 			nNextChg = nStop;
904 
905 		nStop = nIdx;
906 		xub_Unicode cChar = CH_BLANK;
907         SwTxtAttr* pHint = NULL;
908 
909         // stop at special characters in [ nIdx, nNextChg ]
910         while( nStop < nEnd && nStop < nNextChg )
911         {
912             cChar = m_Text.GetChar( nStop );
913             if (
914                 CH_TAB == cChar ||
915                 CH_BREAK == cChar ||
916                 CHAR_HARDBLANK == cChar ||
917                 CHAR_HARDHYPHEN == cChar ||
918                 CHAR_SOFTHYPHEN == cChar ||
919                 (
920                   (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
921                   (0 == (pHint = aIter.GetAttr(nStop)))
922                 )
923                )
924             {
925                 break;
926             }
927             else
928                 ++nStop;
929         }
930 
931 		// calculate text widths up to cChar
932         if ( nStop > nIdx )
933         {
934             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
935             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
936         }
937 
938 		nIdx = nStop;
939 		aIter.SeekAndChgAttrIter( nIdx, pOut );
940 
941 		if ( cChar == CH_BREAK )
942 		{
943 			nWidth = Max( nWidth, nProWidth );
944 			nProWidth = 0;
945 			nIdx++;
946 		}
947 		else if ( cChar == CH_TAB )
948 		{
949 			// tab receives width of one space
950             XubString sTmp( CH_BLANK );
951             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
952             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
953 			nIdx++;
954 		}
955         else if ( cChar == CHAR_SOFTHYPHEN )
956             ++nIdx;
957         else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
958         {
959             XubString sTmp( cChar );
960             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
961             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
962 			nIdx++;
963         }
964 		else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
965 		{
966 			switch( pHint->Which() )
967 			{
968 				case RES_TXTATR_FTN :
969 				{
970 					const XubString aTxt = pHint->GetFtn().GetNumStr();
971                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
972 
973                     nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
974 					break;
975 				}
976 				case RES_TXTATR_FIELD :
977 				{
978 					SwField *pFld = (SwField*)pHint->GetFmtFld().GetField();
979                     String const aTxt = pFld->ExpandField(true);
980                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
981 
982                     nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
983 					break;
984 				}
985 				default:
986 				{
987 				// any suggestions for a default action?
988 				}
989 			} // end of switch
990 			nIdx++;
991 		} // end of while
992 	}
993 
994 	nWidth = Max( nWidth, nProWidth );
995 
996 	// search for a text frame this node belongs to
997 	SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this );
998     SwTxtFrm* pFrm = 0;
999     for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() )
1000 	{
1001 			if ( pTmpFrm->GetOfst() <= nStt &&
1002 				( !pTmpFrm->GetFollow() ||
1003 				   pTmpFrm->GetFollow()->GetOfst() > nStt )	)
1004 			{
1005 				pFrm = pTmpFrm;
1006 				break;
1007 			}
1008 		}
1009 
1010 	// search for the line containing nStt
1011     if ( pFrm && pFrm->HasPara() )
1012 	{
1013 		SwTxtInfo aInf( pFrm );
1014         SwTxtIter aLine( pFrm, &aInf );
1015 		aLine.CharToLine( nStt );
1016         pOut->SetMapMode( aOldMap );
1017         return (sal_uInt16)( nWidth ?
1018 			( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1019 	}
1020 	// no frame or no paragraph, we take the height of the character
1021 	// at nStt as line height
1022 
1023     aIter.SeekAndChgAttrIter( nStt, pOut );
1024     pOut->SetMapMode( aOldMap );
1025 
1026     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
1027     return (sal_uInt16)
1028            ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
1029 }
1030 
1031 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const
1032 {
1033     sal_uInt16 nRet = 0;
1034 
1035     xub_StrLen nIdx = 0;
1036     sal_Unicode cCh;
1037 
1038     while ( nIdx < GetTxt().Len() &&
1039              ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
1040                 ' ' == cCh ) )
1041         ++nIdx;
1042 
1043     if ( nIdx > 0 )
1044     {
1045         SwPosition aPos( *this );
1046         aPos.nContent += nIdx;
1047 
1048         // Find the non-follow text frame:
1049 	    SwIterator<SwTxtFrm,SwTxtNode> aIter( *this );
1050         for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1051         {
1052             // Only consider master frames:
1053             if ( !pFrm->IsFollow() )
1054             {
1055                 SWRECTFN( pFrm )
1056                 SwRect aRect;
1057                 pFrm->GetCharRect( aRect, aPos );
1058                 nRet = (sal_uInt16)
1059                        ( pFrm->IsRightToLeft() ?
1060                             (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1061                             (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
1062                 break;
1063             }
1064         }
1065     }
1066 
1067     return nRet;
1068 }
1069