xref: /AOO41X/main/sw/source/core/text/itratr.cxx (revision dec99bbd1eb6ae693d6ee672c1a69e3a32d917e7)
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 
Chg(SwTxtAttr * pHt)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 
Rst(SwTxtAttr * pHt)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 
~SwAttrIter()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 
GetAttr(const xub_StrLen nPosition) const121 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 
SeekAndChgAttrIter(const xub_StrLen nNewPos,OutputDevice * pOut)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 
IsSymbol(const xub_StrLen nNewPos)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 
SeekStartAndChgAttrIter(OutputDevice * pOut,const sal_Bool bParaFont)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 
SeekFwd(const xub_StrLen nNewPos)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 
Seek(const xub_StrLen nNewPos)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 
GetNextAttr() const316 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 
Dump(SvStream &) const350 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;
SwMinMaxArgs(OutputDevice * pOutI,ViewShell * pShI,sal_uLong & rMinI,sal_uLong & rMaxI,sal_uLong & rAbsI)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; }
Minimum(long nNew)372     void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; }
NewWord()373     void NewWord() { nWordAdd = nWordWidth = 0; }
374 };
375 
lcl_MinMaxString(SwMinMaxArgs & rArg,SwFont * pFnt,const XubString & rTxt,xub_StrLen nIdx,xub_StrLen nEnd)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 
IsSymbol(const xub_StrLen nBegin) const430 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
Minimum(long nNew)449     void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
450 };
451 
lcl_MinMaxNode(const SwFrmFmtPtr & rpNd,void * pArgs)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"
GetMinMaxSize(sal_uLong nIndex,sal_uLong & rMin,sal_uLong & rMax,sal_uLong & rAbsMin,OutputDevice * pOut) const588 void SwTxtNode::GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax,
589                                sal_uLong& rAbsMin, OutputDevice* pOut ) const
590 {
591     ViewShell* pSh = 0;
592     GetDoc()->GetEditShell( &pSh );
593     if( !pOut )
594     {
595         if( pSh )
596             pOut = pSh->GetWin();
597         if( !pOut )
598             pOut = GetpApp()->GetDefaultDevice();
599     }
600 
601     MapMode aOldMap( pOut->GetMapMode() );
602     pOut->SetMapMode( MapMode( MAP_TWIP ) );
603 
604     rMin = 0;
605     rMax = 0;
606     rAbsMin = 0;
607 
608     const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
609     long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True );
610     short nFLOffs;
611     // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich
612     // bereits gefuellt...
613     if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
614         nLROffset = nFLOffs;
615 
616     SwMinMaxNodeArgs aNodeArgs;
617     aNodeArgs.nMinWidth = 0;
618     aNodeArgs.nMaxWidth = 0;
619     aNodeArgs.nLeftRest = nLROffset;
620     aNodeArgs.nRightRest = rSpace.GetRight();
621     aNodeArgs.nLeftDiff = 0;
622     aNodeArgs.nRightDiff = 0;
623     if( nIndex )
624     {
625         SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts();
626         if( pTmp )
627         {
628             aNodeArgs.nIndx = nIndex;
629             pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs );
630         }
631     }
632     if( aNodeArgs.nLeftRest < 0 )
633         aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
634     aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
635     if( aNodeArgs.nLeftRest < 0 )
636         aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
637 
638     if( aNodeArgs.nRightRest < 0 )
639         aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
640     aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
641     if( aNodeArgs.nRightRest < 0 )
642         aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
643 
644     SwScriptInfo aScriptInfo;
645     SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
646     xub_StrLen nIdx = 0;
647     aIter.SeekAndChgAttrIter( nIdx, pOut );
648     xub_StrLen nLen = m_Text.Len();
649     long nAktWidth = 0;
650     MSHORT nAdd = 0;
651     SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
652     while( nIdx < nLen )
653     {
654         xub_StrLen nNextChg = aIter.GetNextAttr();
655         xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
656         if( nNextChg > nStop )
657             nNextChg = nStop;
658         SwTxtAttr *pHint = NULL;
659         xub_Unicode cChar = CH_BLANK;
660         nStop = nIdx;
661         while( nStop < nLen && nStop < nNextChg &&
662                CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) &&
663                CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
664                CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
665                !pHint )
666         {
667             if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
668                 || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
669                 ++nStop;
670         }
671         if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
672         {
673             nAdd = 20;
674         }
675         nIdx = nStop;
676         aIter.SeekAndChgAttrIter( nIdx, pOut );
677         switch( cChar )
678         {
679             case CH_BREAK  :
680             {
681                 if( (long)rMax < aArg.nRowWidth )
682                     rMax = aArg.nRowWidth;
683                 aArg.nRowWidth = 0;
684                 aArg.NewWord();
685                 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
686             }
687             break;
688             case CH_TAB    :
689             {
690                 aArg.NewWord();
691                 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
692             }
693             break;
694             case CHAR_SOFTHYPHEN:
695                 ++nIdx;
696             break;
697             case CHAR_HARDBLANK:
698             case CHAR_HARDHYPHEN:
699             {
700                 XubString sTmp( cChar );
701                 SwDrawTextInfo aDrawInf( const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()),
702                     *pOut, 0, sTmp, 0, 1, 0, sal_False );//swmod 080311
703                 nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
704                 aArg.nWordWidth += nAktWidth;
705                 aArg.nRowWidth += nAktWidth;
706                 if( (long)rAbsMin < aArg.nWordWidth )
707                     rAbsMin = aArg.nWordWidth;
708                 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
709                 aArg.nNoLineBreak = nIdx++;
710             }
711             break;
712             case CH_TXTATR_BREAKWORD:
713             case CH_TXTATR_INWORD:
714             {
715                 if( !pHint )
716                     break;
717                 long nOldWidth = aArg.nWordWidth;
718                 long nOldAdd = aArg.nWordAdd;
719                 aArg.NewWord();
720 
721                 switch( pHint->Which() )
722                 {
723                     case RES_TXTATR_FLYCNT :
724                     {
725                         SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt();
726                         const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace();
727                         if( RES_DRAWFRMFMT == pFrmFmt->Which() )
728                         {
729                             const SdrObject* pSObj = pFrmFmt->FindSdrObject();
730                             if( pSObj )
731                                 nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
732                             else
733                                 nAktWidth = 0;
734                         }
735                         else
736                         {
737                             const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize();
738                             if( RES_FLYFRMFMT == pFrmFmt->Which()
739                                 && rTmpSize.GetWidthPercent() )
740                             {
741 /*-----------------24.01.97 14:09----------------------------------------------
742  * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich
743  * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale
744  * Breite 0,5 cm und als maximale KSHRT_MAX.
745  * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt
746  * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen.
747  * --------------------------------------------------------------------------*/
748                                 nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm
749                                 if( (long)rMax < KSHRT_MAX )
750                                     rMax = KSHRT_MAX;
751                             }
752                             else
753                                 nAktWidth = pFrmFmt->GetFrmSize().GetWidth();
754                         }
755                         nAktWidth += rLR.GetLeft();
756                         nAktWidth += rLR.GetRight();
757                         aArg.nWordAdd = nOldWidth + nOldAdd;
758                         aArg.nWordWidth = nAktWidth;
759                         aArg.nRowWidth += nAktWidth;
760                         if( (long)rAbsMin < aArg.nWordWidth )
761                             rAbsMin = aArg.nWordWidth;
762                         aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
763                         break;
764                     }
765                     case RES_TXTATR_FTN :
766                     {
767                         const XubString aTxt = pHint->GetFtn().GetNumStr();
768                         if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
769                             aTxt.Len() ) )
770                             nAdd = 20;
771                         break;
772                     }
773 
774                     case RES_TXTATR_FIELD :
775                     case RES_TXTATR_ANNOTATION :
776                         {
777                             SwField *pFld = (SwField*)pHint->GetFmtFld().GetField();
778                             const String aTxt = pFld->ExpandField(true);
779                             if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
780                                 aTxt.Len() ) )
781                                 nAdd = 20;
782                             break;
783                         }
784 
785                     default: aArg.nWordWidth = nOldWidth;
786                         aArg.nWordAdd = nOldAdd;
787 
788                 }
789                 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
790             }
791             break;
792         }
793     }
794     if( (long)rMax < aArg.nRowWidth )
795         rMax = aArg.nRowWidth;
796 
797     nLROffset += rSpace.GetRight();
798 
799     rAbsMin += nLROffset;
800     rAbsMin += nAdd;
801     rMin += nLROffset;
802     rMin += nAdd;
803     if( (long)rMin < aNodeArgs.nMinWidth )
804         rMin = aNodeArgs.nMinWidth;
805     if( (long)rAbsMin < aNodeArgs.nMinWidth )
806         rAbsMin = aNodeArgs.nMinWidth;
807     rMax += aNodeArgs.nMaxWidth;
808     rMax += nLROffset;
809     rMax += nAdd;
810     if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
811         rMax = rMin;  // in das Minimum ein
812     pOut->SetMapMode( aOldMap );
813 }
814 
815 /*************************************************************************
816  *                      SwTxtNode::GetScalingOfSelectedText()
817  *
818  * Calculates the width of the text part specified by nStt and nEnd,
819  * the height of the line containing nStt is devided by this width,
820  * indicating the scaling factor, if the text part is rotated.
821  * Having CH_BREAKs in the text part, this method returns the scaling
822  * factor for the longest of the text parts separated by the CH_BREAKs.
823  *
824  * changing this method very likely requires changing of "GetMinMaxSize"
825  *************************************************************************/
826 
GetScalingOfSelectedText(xub_StrLen nStt,xub_StrLen nEnd) const827 sal_uInt16 SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd )
828     const
829 {
830     ViewShell* pSh = NULL;
831     OutputDevice* pOut = NULL;
832     GetDoc()->GetEditShell( &pSh );
833 
834     if ( pSh )
835         pOut = &pSh->GetRefDev();
836     else
837     {
838         //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
839         if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) )
840             pOut = GetpApp()->GetDefaultDevice();
841         else
842             pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
843     }
844 
845     ASSERT( pOut, "GetScalingOfSelectedText without outdev" )
846 
847     MapMode aOldMap( pOut->GetMapMode() );
848     pOut->SetMapMode( MapMode( MAP_TWIP ) );
849 
850     if ( nStt == nEnd )
851     {
852         if ( !pBreakIt->GetBreakIter().is() )
853             return 100;
854 
855         SwScriptInfo aScriptInfo;
856         SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
857         aIter.SeekAndChgAttrIter( nStt, pOut );
858 
859         Boundary aBound =
860             pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
861             pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
862             WordType::DICTIONARY_WORD, sal_True );
863 
864         if ( nStt == aBound.startPos )
865         {
866             // cursor is at left or right border of word
867             pOut->SetMapMode( aOldMap );
868             return 100;
869         }
870 
871         nStt = (xub_StrLen)aBound.startPos;
872         nEnd = (xub_StrLen)aBound.endPos;
873 
874         if ( nStt == nEnd )
875         {
876             pOut->SetMapMode( aOldMap );
877             return 100;
878         }
879     }
880 
881     SwScriptInfo aScriptInfo;
882     SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
883 
884     // We do not want scaling attributes to be considered during this
885     // calculation. For this, we push a temporary scaling attribute with
886     // scaling value 100 and priority flag on top of the scaling stack
887     SwAttrHandler& rAH = aIter.GetAttrHandler();
888     SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
889     SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
890     aAttr.SetPriorityAttr( sal_True );
891     rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
892 
893     xub_StrLen nIdx = nStt;
894 
895     sal_uLong nWidth = 0;
896     sal_uLong nProWidth = 0;
897 
898     while( nIdx < nEnd )
899     {
900         aIter.SeekAndChgAttrIter( nIdx, pOut );
901 
902         // scan for end of portion
903         xub_StrLen nNextChg = aIter.GetNextAttr();
904         xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
905         if( nNextChg > nStop )
906             nNextChg = nStop;
907 
908         nStop = nIdx;
909         xub_Unicode cChar = CH_BLANK;
910         SwTxtAttr* pHint = NULL;
911 
912         // stop at special characters in [ nIdx, nNextChg ]
913         while( nStop < nEnd && nStop < nNextChg )
914         {
915             cChar = m_Text.GetChar( nStop );
916             if (
917                 CH_TAB == cChar ||
918                 CH_BREAK == cChar ||
919                 CHAR_HARDBLANK == cChar ||
920                 CHAR_HARDHYPHEN == cChar ||
921                 CHAR_SOFTHYPHEN == cChar ||
922                 (
923                   (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
924                   (0 == (pHint = aIter.GetAttr(nStop)))
925                 )
926                )
927             {
928                 break;
929             }
930             else
931                 ++nStop;
932         }
933 
934         // calculate text widths up to cChar
935         if ( nStop > nIdx )
936         {
937             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
938             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
939         }
940 
941         nIdx = nStop;
942         aIter.SeekAndChgAttrIter( nIdx, pOut );
943 
944         if ( cChar == CH_BREAK )
945         {
946             nWidth = Max( nWidth, nProWidth );
947             nProWidth = 0;
948             nIdx++;
949         }
950         else if ( cChar == CH_TAB )
951         {
952             // tab receives width of one space
953             XubString sTmp( CH_BLANK );
954             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
955             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
956             nIdx++;
957         }
958         else if ( cChar == CHAR_SOFTHYPHEN )
959             ++nIdx;
960         else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
961         {
962             XubString sTmp( cChar );
963             SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
964             nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
965             nIdx++;
966         }
967         else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
968         {
969             switch( pHint->Which() )
970             {
971             case RES_TXTATR_FTN :
972                 {
973                     const XubString aTxt = pHint->GetFtn().GetNumStr();
974                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
975 
976                     nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
977                     break;
978                 }
979 
980             case RES_TXTATR_FIELD :
981             case RES_TXTATR_ANNOTATION :
982                 {
983                     SwField *pFld = (SwField*)pHint->GetFmtFld().GetField();
984                     String const aTxt = pFld->ExpandField(true);
985                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
986 
987                     nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
988                     break;
989                 }
990 
991             default:
992                 {
993                     // any suggestions for a default action?
994                 }
995             } // end of switch
996             nIdx++;
997         } // end of while
998     }
999 
1000     nWidth = Max( nWidth, nProWidth );
1001 
1002     // search for a text frame this node belongs to
1003     SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this );
1004     SwTxtFrm* pFrm = 0;
1005     for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() )
1006     {
1007             if ( pTmpFrm->GetOfst() <= nStt &&
1008                 ( !pTmpFrm->GetFollow() ||
1009                    pTmpFrm->GetFollow()->GetOfst() > nStt ) )
1010             {
1011                 pFrm = pTmpFrm;
1012                 break;
1013             }
1014         }
1015 
1016     // search for the line containing nStt
1017     if ( pFrm && pFrm->HasPara() )
1018     {
1019         SwTxtInfo aInf( pFrm );
1020         SwTxtIter aLine( pFrm, &aInf );
1021         aLine.CharToLine( nStt );
1022         pOut->SetMapMode( aOldMap );
1023         return (sal_uInt16)( nWidth ?
1024             ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1025     }
1026     // no frame or no paragraph, we take the height of the character
1027     // at nStt as line height
1028 
1029     aIter.SeekAndChgAttrIter( nStt, pOut );
1030     pOut->SetMapMode( aOldMap );
1031 
1032     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
1033     return (sal_uInt16)
1034            ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
1035 }
1036 
GetWidthOfLeadingTabs() const1037 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const
1038 {
1039     sal_uInt16 nRet = 0;
1040 
1041     xub_StrLen nIdx = 0;
1042     sal_Unicode cCh;
1043 
1044     while ( nIdx < GetTxt().Len() &&
1045              ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
1046                 ' ' == cCh ) )
1047         ++nIdx;
1048 
1049     if ( nIdx > 0 )
1050     {
1051         SwPosition aPos( *this );
1052         aPos.nContent += nIdx;
1053 
1054         // Find the non-follow text frame:
1055         SwIterator<SwTxtFrm,SwTxtNode> aIter( *this );
1056         for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1057         {
1058             // Only consider master frames:
1059             if ( !pFrm->IsFollow() )
1060             {
1061                 SWRECTFN( pFrm )
1062                 SwRect aRect;
1063                 pFrm->GetCharRect( aRect, aPos );
1064                 nRet = (sal_uInt16)
1065                        ( pFrm->IsRightToLeft() ?
1066                             (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1067                             (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
1068                 break;
1069             }
1070         }
1071     }
1072 
1073     return nRet;
1074 }
1075