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