xref: /AOO41X/main/sw/source/core/text/itratr.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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->GetFld().GetFld();
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->GetFld().GetFld();
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