xref: /AOO41X/main/sw/source/core/text/pormulti.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 
30 #include <com/sun/star/i18n/ScriptType.hdl>
31 #include <editeng/twolinesitem.hxx>
32 #include <editeng/charrotateitem.hxx>
33 #include <vcl/outdev.hxx>
34 #include <fmtfld.hxx>
35 #include <fldbas.hxx>      // SwField
36 #include <txatbase.hxx>
37 #include <fmtruby.hxx>  // SwFmtRuby
38 #include <txtatr.hxx>   // SwTxtRuby
39 #include <charfmt.hxx>
40 #include <txtinet.hxx>
41 #include <fchrfmt.hxx>
42 #include <layfrm.hxx>       // GetUpper()
43 #include <SwPortionHandler.hxx>
44 #include <pormulti.hxx>     // SwMultiPortion
45 #include <inftxt.hxx>       // SwTxtSizeInfo
46 #include <itrpaint.hxx>     // SwTxtPainter
47 #include <viewopt.hxx>      // SwViewOptions
48 #include <itrform2.hxx>     // SwTxtFormatter
49 #include <porfld.hxx>       // SwFldPortion
50 #include <porglue.hxx>
51 #include <breakit.hxx>
52 #include <pagefrm.hxx>
53 #include <rowfrm.hxx>
54 #include <pagedesc.hxx> // SwPageDesc
55 #include <tgrditem.hxx>
56 #include <swtable.hxx>
57 #include <fmtfsize.hxx>
58 
59 using namespace ::com::sun::star;
60 extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
61 
62 /*-----------------10.10.00 15:23-------------------
63  *  class SwMultiPortion
64  *
65  * A SwMultiPortion is not a simple portion,
66  * it's a container, which contains almost a SwLineLayoutPortion.
67  * This SwLineLayout could be followed by other textportions via pPortion
68  * and by another SwLineLayout via pNext to realize a doubleline portion.
69  * --------------------------------------------------*/
70 
~SwMultiPortion()71 SwMultiPortion::~SwMultiPortion()
72 {
73     delete pFldRest;
74 }
75 
Paint(const SwTxtPaintInfo &) const76 void SwMultiPortion::Paint( const SwTxtPaintInfo & ) const
77 {
78     ASSERT( sal_False,
79     "Don't try SwMultiPortion::Paint, try SwTxtPainter::PaintMultiPortion" );
80 }
81 
82 /*-----------------13.10.00 16:21-------------------
83  * Summarize the internal lines to calculate the (external) size.
84  * The internal line has to calculate first.
85  * --------------------------------------------------*/
86 
CalcSize(SwTxtFormatter & rLine,SwTxtFormatInfo & rInf)87 void SwMultiPortion::CalcSize( SwTxtFormatter& rLine, SwTxtFormatInfo &rInf )
88 {
89     Width( 0 );
90     Height( 0 );
91     SetAscent( 0 );
92     SetFlyInCntnt( sal_False );
93     SwLineLayout *pLay = &GetRoot();
94     do
95     {
96         pLay->CalcLine( rLine, rInf );
97         if( rLine.IsFlyInCntBase() )
98             SetFlyInCntnt( sal_True );
99         if( IsRuby() && ( OnTop() == ( pLay == &GetRoot() ) ) )
100         {
101             // An empty phonetic line don't need an ascent or a height.
102             if( !pLay->Width() )
103             {
104                 pLay->SetAscent( 0 );
105                 pLay->Height( 0 );
106             }
107             if( OnTop() )
108                 SetAscent( GetAscent() + pLay->Height() );
109         }
110         else
111             SetAscent( GetAscent() + pLay->GetAscent() );
112         Height( Height() + pLay->Height() );
113         if( Width() < pLay->Width() )
114             Width( pLay->Width() );
115         pLay = pLay->GetNext();
116     } while ( pLay );
117     if( HasBrackets() )
118     {
119         KSHORT nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nHeight;
120         if( nTmp > Height() )
121         {
122             KSHORT nAdd = ( nTmp - Height() ) / 2;
123             GetRoot().SetAscent( GetRoot().GetAscent() + nAdd );
124             GetRoot().Height( GetRoot().Height() + nAdd );
125             Height( nTmp );
126         }
127         nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nAscent;
128         if( nTmp > GetAscent() )
129             SetAscent( nTmp );
130     }
131 }
132 
CalcSpacing(long,const SwTxtSizeInfo &) const133 long SwMultiPortion::CalcSpacing( long , const SwTxtSizeInfo & ) const
134 {
135     return 0;
136 }
137 
ChgSpaceAdd(SwLineLayout *,long) const138 sal_Bool SwMultiPortion::ChgSpaceAdd( SwLineLayout*, long ) const
139 {
140     return sal_False;
141 }
142 
143 /*************************************************************************
144  *              virtual SwMultiPortion::HandlePortion()
145  *************************************************************************/
146 
HandlePortion(SwPortionHandler & rPH) const147 void SwMultiPortion::HandlePortion( SwPortionHandler& rPH ) const
148 {
149     rPH.Text( GetLen(), GetWhichPor() );
150 }
151 
152 /*-----------------01.11.00 14:21-------------------
153  * SwMultiPortion::ActualizeTabulator()
154  * sets the tabulator-flag, if there's any tabulator-portion inside.
155  * --------------------------------------------------*/
156 
ActualizeTabulator()157 void SwMultiPortion::ActualizeTabulator()
158 {
159     SwLinePortion* pPor = GetRoot().GetFirstPortion();
160     // First line
161     for( bTab1 = bTab2 = sal_False; pPor; pPor = pPor->GetPortion() )
162         if( pPor->InTabGrp() )
163             SetTab1( sal_True );
164     if( GetRoot().GetNext() )
165     {
166         // Second line
167         pPor = GetRoot().GetNext()->GetFirstPortion();
168         do
169         {
170             if( pPor->InTabGrp() )
171                 SetTab2( sal_True );
172             pPor = pPor->GetPortion();
173         } while ( pPor );
174     }
175 }
176 
177 /*-----------------16.02.01 12:07-------------------
178  * SwRotatedPortion::SwRotatedPortion(..)
179  * --------------------------------------------------*/
180 
SwRotatedPortion(const SwMultiCreator & rCreate,xub_StrLen nEnd,sal_Bool bRTL)181 SwRotatedPortion::SwRotatedPortion( const SwMultiCreator& rCreate,
182     xub_StrLen nEnd, sal_Bool bRTL ) : SwMultiPortion( nEnd )
183 {
184     const SvxCharRotateItem* pRot = (SvxCharRotateItem*)rCreate.pItem;
185     if( !pRot )
186     {
187         const SwTxtAttr& rAttr = *rCreate.pAttr;
188         const SfxPoolItem *const pItem =
189                 CharFmt::GetItem(rAttr, RES_CHRATR_ROTATE);
190         if ( pItem )
191         {
192             pRot = static_cast<const SvxCharRotateItem*>(pItem);
193         }
194     }
195     if( pRot )
196     {
197         sal_uInt8 nDir;
198         if ( bRTL )
199             nDir = pRot->IsBottomToTop() ? 3 : 1;
200         else
201             nDir = pRot->IsBottomToTop() ? 1 : 3;
202 
203         SetDirection( nDir );
204     }
205 }
206 
207 /*---------------------------------------------------
208  * SwBidiPortion::SwBidiPortion(..)
209  * --------------------------------------------------*/
210 
SwBidiPortion(xub_StrLen nEnd,sal_uInt8 nLv)211 SwBidiPortion::SwBidiPortion( xub_StrLen nEnd, sal_uInt8 nLv )
212     : SwMultiPortion( nEnd ), nLevel( nLv )
213 {
214     SetBidi();
215 
216     if ( nLevel % 2 )
217         SetDirection( DIR_RIGHT2LEFT );
218     else
219         SetDirection( DIR_LEFT2RIGHT );
220 }
221 
222 
CalcSpacing(long nSpaceAdd,const SwTxtSizeInfo & rInf) const223 long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo& rInf ) const
224 {
225     return HasTabulator() ? 0 : GetSpaceCnt(rInf) * nSpaceAdd / SPACING_PRECISION_FACTOR;
226 }
227 
ChgSpaceAdd(SwLineLayout * pCurr,long nSpaceAdd) const228 sal_Bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const
229 {
230     sal_Bool bRet = sal_False;
231     if( !HasTabulator() && nSpaceAdd > 0 && !pCurr->IsSpaceAdd() )
232     {
233         pCurr->CreateSpaceAdd();
234         pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
235         bRet = sal_True;
236     }
237 
238     return bRet;
239 }
240 
GetSpaceCnt(const SwTxtSizeInfo & rInf) const241 xub_StrLen SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf ) const
242 {
243     // Calculate number of blanks for justified alignment
244     SwLinePortion* pPor = GetRoot().GetFirstPortion();
245     xub_StrLen nTmpStart = rInf.GetIdx();
246     xub_StrLen nNull = 0;
247     xub_StrLen nBlanks;
248 
249     for( nBlanks = 0; pPor; pPor = pPor->GetPortion() )
250     {
251         if( pPor->InTxtGrp() )
252             nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
253         else if ( pPor->IsMultiPortion() &&
254                  ((SwMultiPortion*)pPor)->IsBidi() )
255             nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt( rInf );
256 
257         ((SwTxtSizeInfo &)rInf).SetIdx( rInf.GetIdx() + pPor->GetLen() );
258     }
259     ((SwTxtSizeInfo &)rInf).SetIdx( nTmpStart );
260     return nBlanks;
261 }
262 
263 /*-----------------01.11.00 14:22-------------------
264  * SwDoubleLinePortion::SwDoubleLinePortion(..)
265  * This constructor is for the continuation of a doubleline portion
266  * in the next line.
267  * It takes the same brackets and if the original has no content except
268  * brackets, these will be deleted.
269  * --------------------------------------------------*/
270 
SwDoubleLinePortion(SwDoubleLinePortion & rDouble,xub_StrLen nEnd)271 SwDoubleLinePortion::SwDoubleLinePortion( SwDoubleLinePortion& rDouble,
272                                           xub_StrLen nEnd ) :
273     SwMultiPortion( nEnd ),
274     pBracket( 0 )
275 {
276     SetDirection( rDouble.GetDirection() );
277     SetDouble();
278     if( rDouble.GetBrackets() )
279     {
280         SetBrackets( rDouble );
281         // An empty multiportion needs no brackets.
282         // Notice: GetLen() might be zero, if the multiportion contains
283         // the second part of a field and the width might be zero, if
284         // it contains a note only. In this cases the brackets are okay.
285         // But if the length and the width are both zero, the portion
286         // is really empty.
287         if( rDouble.Width() ==  rDouble.BracketWidth() )
288             rDouble.ClearBrackets();
289     }
290 }
291 
292 /*-----------------01.11.00 14:22-------------------
293  * SwDoubleLinePortion::SwDoubleLinePortion(..)
294  * This constructor uses the textattribut to get the right brackets.
295  * The textattribut could be a 2-line-attribute or a character- or
296  * internetstyle, which contains the 2-line-attribute.
297  * --------------------------------------------------*/
298 
SwDoubleLinePortion(const SwMultiCreator & rCreate,xub_StrLen nEnd)299 SwDoubleLinePortion::SwDoubleLinePortion( const SwMultiCreator& rCreate,
300     xub_StrLen nEnd ) : SwMultiPortion( nEnd ), pBracket( new SwBracket() )
301 {
302     SetDouble();
303     const SvxTwoLinesItem* pTwo = (SvxTwoLinesItem*)rCreate.pItem;
304     if( pTwo )
305         pBracket->nStart = 0;
306     else
307     {
308         const SwTxtAttr& rAttr = *rCreate.pAttr;
309         pBracket->nStart = *rAttr.GetStart();
310 
311         const SfxPoolItem * const pItem =
312             CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
313         if ( pItem )
314         {
315             pTwo = static_cast<const SvxTwoLinesItem*>(pItem);
316         }
317     }
318     if( pTwo )
319     {
320         pBracket->cPre = pTwo->GetStartBracket();
321         pBracket->cPost = pTwo->GetEndBracket();
322     }
323     else
324     {
325         pBracket->cPre = 0;
326         pBracket->cPost = 0;
327     }
328     sal_uInt8 nTmp = SW_SCRIPTS;
329     if( pBracket->cPre > 255 )
330     {
331         String aTxt( pBracket->cPre );
332         nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
333     }
334     pBracket->nPreScript = nTmp;
335     nTmp = SW_SCRIPTS;
336     if( pBracket->cPost > 255 )
337     {
338         String aTxt( pBracket->cPost );
339         nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
340     }
341     pBracket->nPostScript = nTmp;
342 
343     if( !pBracket->cPre && !pBracket->cPost )
344     {
345         delete pBracket;
346         pBracket = 0;
347     }
348 
349     // double line portions have the same direction as the frame directions
350     if ( rCreate.nLevel % 2 )
351         SetDirection( DIR_RIGHT2LEFT );
352     else
353         SetDirection( DIR_LEFT2RIGHT );
354 }
355 
356 
357 /*-----------------25.10.00 09:51-------------------
358  * SwMultiPortion::PaintBracket paints the wished bracket,
359  * if the multiportion has surrounding brackets.
360  * The X-position of the SwTxtPaintInfo will be modified:
361  * the open bracket sets position behind itself,
362  * the close bracket in front of itself.
363  * --------------------------------------------------*/
364 
PaintBracket(SwTxtPaintInfo & rInf,long nSpaceAdd,sal_Bool bOpen) const365 void SwDoubleLinePortion::PaintBracket( SwTxtPaintInfo &rInf,
366                                         long nSpaceAdd,
367                                         sal_Bool bOpen ) const
368 {
369     sal_Unicode cCh = bOpen ? pBracket->cPre : pBracket->cPost;
370     if( !cCh )
371         return;
372     KSHORT nChWidth = bOpen ? PreWidth() : PostWidth();
373     if( !nChWidth )
374         return;
375     if( !bOpen )
376         rInf.X( rInf.X() + Width() - PostWidth() +
377             ( nSpaceAdd > 0 ? CalcSpacing( nSpaceAdd, rInf ) : 0 ) );
378 
379     SwBlankPortion aBlank( cCh, sal_True );
380     aBlank.SetAscent( pBracket->nAscent );
381     aBlank.Width( nChWidth );
382     aBlank.Height( pBracket->nHeight );
383     {
384         SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
385         sal_uInt8 nAct = bOpen ? pBracket->nPreScript : pBracket->nPostScript;
386         if( SW_SCRIPTS > nAct )
387             pTmpFnt->SetActual( nAct );
388         pTmpFnt->SetProportion( 100 );
389         SwFontSave aSave( rInf, pTmpFnt );
390         aBlank.Paint( rInf );
391         delete pTmpFnt;
392     }
393     if( bOpen )
394         rInf.X( rInf.X() + PreWidth() );
395 }
396 
397 /*-----------------25.10.00 16:26-------------------
398  * SwDoubleLinePortion::SetBrackets creates the bracket-structur
399  * and fills it, if not both characters are 0x00.
400  * --------------------------------------------------*/
401 
SetBrackets(const SwDoubleLinePortion & rDouble)402 void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion& rDouble )
403 {
404     if( rDouble.pBracket )
405     {
406         pBracket = new SwBracket;
407         pBracket->cPre = rDouble.pBracket->cPre;
408         pBracket->cPost = rDouble.pBracket->cPost;
409         pBracket->nPreScript = rDouble.pBracket->nPreScript;
410         pBracket->nPostScript = rDouble.pBracket->nPostScript;
411         pBracket->nStart = rDouble.pBracket->nStart;
412     }
413 }
414 
415 /*-----------------25.10.00 16:29-------------------
416  * SwDoubleLinePortion::FormatBrackets
417  * calculates the size of the brackets => pBracket,
418  * reduces the nMaxWidth-parameter ( minus bracket-width )
419  * and moves the rInf-x-position behind the opening bracket.
420  * --------------------------------------------------*/
421 
FormatBrackets(SwTxtFormatInfo & rInf,SwTwips & nMaxWidth)422 void SwDoubleLinePortion::FormatBrackets( SwTxtFormatInfo &rInf, SwTwips& nMaxWidth )
423 {
424     nMaxWidth -= rInf.X();
425     SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
426     pTmpFnt->SetProportion( 100 );
427     pBracket->nAscent = 0;
428     pBracket->nHeight = 0;
429     if( pBracket->cPre )
430     {
431         String aStr( pBracket->cPre );
432         sal_uInt8 nActualScr = pTmpFnt->GetActual();
433         if( SW_SCRIPTS > pBracket->nPreScript )
434             pTmpFnt->SetActual( pBracket->nPreScript );
435         SwFontSave aSave( rInf, pTmpFnt );
436         SwPosSize aSize = rInf.GetTxtSize( aStr );
437         pBracket->nAscent = rInf.GetAscent();
438         pBracket->nHeight = aSize.Height();
439         pTmpFnt->SetActual( nActualScr );
440         if( nMaxWidth > aSize.Width() )
441         {
442             pBracket->nPreWidth = aSize.Width();
443             nMaxWidth -= aSize.Width();
444             rInf.X( rInf.X() + aSize.Width() );
445         }
446         else
447         {
448             pBracket->nPreWidth = 0;
449             nMaxWidth = 0;
450         }
451     }
452     else
453         pBracket->nPreWidth = 0;
454     if( pBracket->cPost )
455     {
456         String aStr( pBracket->cPost );
457         if( SW_SCRIPTS > pBracket->nPostScript )
458             pTmpFnt->SetActual( pBracket->nPostScript );
459         SwFontSave aSave( rInf, pTmpFnt );
460         SwPosSize aSize = rInf.GetTxtSize( aStr );
461         KSHORT nTmpAsc = rInf.GetAscent();
462         if( nTmpAsc > pBracket->nAscent )
463         {
464             pBracket->nHeight += nTmpAsc - pBracket->nAscent;
465             pBracket->nAscent = nTmpAsc;
466         }
467         if( aSize.Height() > pBracket->nHeight )
468             pBracket->nHeight = aSize.Height();
469         if( nMaxWidth > aSize.Width() )
470         {
471             pBracket->nPostWidth = aSize.Width();
472             nMaxWidth -= aSize.Width();
473         }
474         else
475         {
476             pBracket->nPostWidth = 0;
477             nMaxWidth = 0;
478         }
479     }
480     else
481         pBracket->nPostWidth = 0;
482     nMaxWidth += rInf.X();
483 }
484 
485 /*-----------------26.10.00 10:36-------------------
486  * SwDoubleLinePortion::CalcBlanks
487  * calculates the number of blanks in each line and
488  * the difference of the width of the two lines.
489  * These results are used from the text adjustment.
490  * --------------------------------------------------*/
491 
CalcBlanks(SwTxtFormatInfo & rInf)492 void SwDoubleLinePortion::CalcBlanks( SwTxtFormatInfo &rInf )
493 {
494     SwLinePortion* pPor = GetRoot().GetFirstPortion();
495     xub_StrLen nNull = 0;
496     xub_StrLen nStart = rInf.GetIdx();
497     SetTab1( sal_False );
498     SetTab2( sal_False );
499     for( nBlank1 = 0; pPor; pPor = pPor->GetPortion() )
500     {
501         if( pPor->InTxtGrp() )
502             nBlank1 = nBlank1 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
503         rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
504         if( pPor->InTabGrp() )
505             SetTab1( sal_True );
506     }
507     nLineDiff = GetRoot().Width();
508     if( GetRoot().GetNext() )
509     {
510         pPor = GetRoot().GetNext()->GetFirstPortion();
511         nLineDiff -= GetRoot().GetNext()->Width();
512     }
513     for( nBlank2 = 0; pPor; pPor = pPor->GetPortion() )
514     {
515         if( pPor->InTxtGrp() )
516             nBlank2 = nBlank2 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
517         rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
518         if( pPor->InTabGrp() )
519             SetTab2( sal_True );
520     }
521     rInf.SetIdx( nStart );
522 }
523 
CalcSpacing(long nSpaceAdd,const SwTxtSizeInfo &) const524 long SwDoubleLinePortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo & ) const
525 {
526     return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd / SPACING_PRECISION_FACTOR;
527 }
528 
529 /*-----------------01.11.00 14:29-------------------
530  * SwDoubleLinePortion::ChangeSpaceAdd(..)
531  * merges the spaces for text adjustment from the inner and outer part.
532  * Inside the doubleline portion the wider line has no spaceadd-array, the
533  * smaller line has such an array to reach width of the wider line.
534  * If the surrounding line has text adjustment and the doubleline portion
535  * contains no tabulator, it is necessary to create/manipulate the inner
536  * space arrays.
537  * --------------------------------------------------*/
538 
ChgSpaceAdd(SwLineLayout * pCurr,long nSpaceAdd) const539 sal_Bool SwDoubleLinePortion::ChgSpaceAdd( SwLineLayout* pCurr,
540                                            long nSpaceAdd ) const
541 {
542     sal_Bool bRet = sal_False;
543     if( !HasTabulator() && nSpaceAdd > 0 )
544     {
545         if( !pCurr->IsSpaceAdd() )
546         {
547             // The wider line gets the spaceadd from the surrounding line direct
548             pCurr->CreateSpaceAdd();
549             pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
550             bRet = sal_True;
551         }
552         else
553         {
554             xub_StrLen nMyBlank = GetSmallerSpaceCnt();
555             xub_StrLen nOther = GetSpaceCnt();
556             SwTwips nMultiSpace = pCurr->GetLLSpaceAdd( 0 ) * nMyBlank + nOther * nSpaceAdd;
557 
558             if( nMyBlank )
559                 nMultiSpace /= nMyBlank;
560 
561             if( nMultiSpace < KSHRT_MAX * SPACING_PRECISION_FACTOR )
562             {
563 //                pCurr->SetLLSpaceAdd( nMultiSpace, 0 );
564                 // --> FME 2006-07-11 #i65711# SetLLSpaceAdd replaces the first value,
565                 // instead we want to insert a new first value:
566                 std::vector<long>* pVec = pCurr->GetpLLSpaceAdd();
567                 pVec->insert( pVec->begin(), nMultiSpace );
568                 // <--
569                 bRet = sal_True;
570             }
571         }
572     }
573     return bRet;
574 }
575 /*-----------------01.11.00 14:29-------------------
576  * SwDoubleLinePortion::ResetSpaceAdd(..)
577  * cancels the manipulation from SwDoubleLinePortion::ChangeSpaceAdd(..)
578  * --------------------------------------------------*/
579 
ResetSpaceAdd(SwLineLayout * pCurr)580 void SwDoubleLinePortion::ResetSpaceAdd( SwLineLayout* pCurr )
581 {
582     pCurr->RemoveFirstLLSpaceAdd();;
583     if( !pCurr->GetLLSpaceAddCount() )
584         pCurr->FinishSpaceAdd();
585 }
586 
~SwDoubleLinePortion()587 SwDoubleLinePortion::~SwDoubleLinePortion()
588 {
589     delete pBracket;
590 }
591 
592 /*-----------------13.11.00 14:50-------------------
593  * SwRubyPortion::SwRubyPortion(..)
594  * constructs a ruby portion, i.e. an additional text is displayed
595  * beside the main text, e.g. phonetic characters.
596  * --------------------------------------------------*/
597 
598 
SwRubyPortion(const SwRubyPortion & rRuby,xub_StrLen nEnd)599 SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, xub_StrLen nEnd ) :
600     SwMultiPortion( nEnd ),
601     nRubyOffset( rRuby.GetRubyOffset() ),
602     nAdjustment( rRuby.GetAdjustment() )
603 {
604     SetDirection( rRuby.GetDirection() ),
605     SetTop( rRuby.OnTop() );
606     SetRuby();
607 }
608 
609 /*-----------------13.11.00 14:50-------------------
610  * SwRubyPortion::SwRubyPortion(..)
611  * constructs a ruby portion, i.e. an additional text is displayed
612  * beside the main text, e.g. phonetic characters.
613  * --------------------------------------------------*/
614 
SwRubyPortion(const SwMultiCreator & rCreate,const SwFont & rFnt,const IDocumentSettingAccess & rIDocumentSettingAccess,xub_StrLen nEnd,xub_StrLen nOffs,const sal_Bool * pForceRubyPos)615 SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt,
616                               const IDocumentSettingAccess& rIDocumentSettingAccess,
617                               xub_StrLen nEnd, xub_StrLen nOffs,
618                               const sal_Bool* pForceRubyPos )
619      : SwMultiPortion( nEnd )
620 {
621     SetRuby();
622     ASSERT( SW_MC_RUBY == rCreate.nId, "Ruby expected" );
623     ASSERT( RES_TXTATR_CJK_RUBY == rCreate.pAttr->Which(), "Wrong attribute" );
624     const SwFmtRuby& rRuby = rCreate.pAttr->GetRuby();
625     nAdjustment = rRuby.GetAdjustment();
626     nRubyOffset = nOffs;
627 
628     // in grid mode we force the ruby text to the upper or lower line
629     if ( pForceRubyPos )
630         SetTop( *pForceRubyPos );
631     else
632         SetTop( ! rRuby.GetPosition() );
633 
634     const SwCharFmt* pFmt = ((SwTxtRuby*)rCreate.pAttr)->GetCharFmt();
635     SwFont *pRubyFont;
636     if( pFmt )
637     {
638         const SwAttrSet& rSet = pFmt->GetAttrSet();
639         pRubyFont = new SwFont( rFnt );
640         pRubyFont->SetDiffFnt( &rSet, &rIDocumentSettingAccess );
641 
642         // we do not allow a vertical font for the ruby text
643         pRubyFont->SetVertical( rFnt.GetOrientation() );
644     }
645     else
646         pRubyFont = NULL;
647 
648     String aStr( rRuby.GetText(), nOffs, STRING_LEN );
649     SwFldPortion *pFld = new SwFldPortion( aStr, pRubyFont );
650     pFld->SetNextOffset( nOffs );
651     pFld->SetFollow( sal_True );
652 
653     if( OnTop() )
654         GetRoot().SetPortion( pFld );
655     else
656     {
657         GetRoot().SetNext( new SwLineLayout() );
658         GetRoot().GetNext()->SetPortion( pFld );
659     }
660 
661     // ruby portions have the same direction as the frame directions
662     if ( rCreate.nLevel % 2 )
663     {
664         // switch right and left ruby adjustment in rtl environment
665         if ( 0 == nAdjustment )
666             nAdjustment = 2;
667         else if ( 2 == nAdjustment )
668             nAdjustment = 0;
669 
670         SetDirection( DIR_RIGHT2LEFT );
671     }
672     else
673         SetDirection( DIR_LEFT2RIGHT );
674 }
675 
676 /*-----------------13.11.00 14:56-------------------
677  * SwRubyPortion::_Adjust(..)
678  * In ruby portion there are different alignments for
679  * the ruby text and the main text.
680  * Left, right, centered and two possibilities of block adjustment
681  * The block adjustment is realized by spacing between the characteres,
682  * either with a half space or no space in front of the first letter and
683  * a half space at the end of the last letter.
684  * Notice: the smaller line will be manipulated, normally it's the ruby line,
685  * but it could be the main text, too.
686  * If there is a tabulator in smaller line, no adjustment is possible.
687  * --------------------------------------------------*/
688 
_Adjust(SwTxtFormatInfo & rInf)689 void SwRubyPortion::_Adjust( SwTxtFormatInfo &rInf )
690 {
691     SwTwips nLineDiff = GetRoot().Width() - GetRoot().GetNext()->Width();
692     xub_StrLen nOldIdx = rInf.GetIdx();
693     if( !nLineDiff )
694         return;
695     SwLineLayout *pCurr;
696     if( nLineDiff < 0 )
697     {   // The first line has to be adjusted.
698         if( GetTab1() )
699             return;
700         pCurr = &GetRoot();
701         nLineDiff = -nLineDiff;
702     }
703     else
704     {   // The second line has to be adjusted.
705         if( GetTab2() )
706             return;
707         pCurr = GetRoot().GetNext();
708         rInf.SetIdx( nOldIdx + GetRoot().GetLen() );
709     }
710     KSHORT nLeft = 0;   // the space in front of the first letter
711     KSHORT nRight = 0;  // the space at the end of the last letter
712     sal_uInt16 nSub = 0;
713     switch ( nAdjustment )
714     {
715         case 1: nRight = static_cast<sal_uInt16>(nLineDiff / 2);    // no break
716         case 2: nLeft  = static_cast<sal_uInt16>(nLineDiff - nRight); break;
717         case 3: nSub   = 1; // no break
718         case 4:
719         {
720             xub_StrLen nCharCnt = 0;
721             SwLinePortion *pPor;
722             for( pPor = pCurr->GetFirstPortion(); pPor; pPor = pPor->GetPortion() )
723             {
724                 if( pPor->InTxtGrp() )
725                     ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nCharCnt );
726                 rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
727             }
728             if( nCharCnt > nSub )
729             {
730                 SwTwips nCalc = nLineDiff / ( nCharCnt - nSub );
731                 short nTmp;
732                 if( nCalc < SHRT_MAX )
733                     nTmp = -short(nCalc);
734                 else
735                     nTmp = SHRT_MIN;
736 
737                 pCurr->CreateSpaceAdd( SPACING_PRECISION_FACTOR * nTmp );
738                 nLineDiff -= nCalc * ( nCharCnt - 1 );
739             }
740             if( nLineDiff > 1 )
741             {
742                 nRight = static_cast<sal_uInt16>(nLineDiff / 2);
743                 nLeft  = static_cast<sal_uInt16>(nLineDiff - nRight);
744             }
745             break;
746         }
747         default: ASSERT( sal_False, "New ruby adjustment" );
748     }
749     if( nLeft || nRight )
750     {
751         if( !pCurr->GetPortion() )
752             pCurr->SetPortion( new SwTxtPortion( *pCurr ) );
753         SwMarginPortion *pMarg = new SwMarginPortion( 0 );
754         if( nLeft )
755         {
756             pMarg->AddPrtWidth( nLeft );
757             pMarg->SetPortion( pCurr->GetPortion() );
758             pCurr->SetPortion( pMarg );
759         }
760         if( nRight )
761         {
762             pMarg = new SwMarginPortion( 0 );
763             pMarg->AddPrtWidth( nRight );
764             pCurr->FindLastPortion()->Append( pMarg );
765         }
766     }
767 
768     pCurr->Width( Width() );
769     rInf.SetIdx( nOldIdx );
770 }
771 
772 /*-----------------08.11.00 14:14-------------------
773  * CalcRubyOffset()
774  * has to change the nRubyOffset, if there's a fieldportion
775  * in the phonetic line.
776  * The nRubyOffset is the position in the rubystring, where the
777  * next SwRubyPortion has start the displaying of the phonetics.
778  * --------------------------------------------------*/
779 
CalcRubyOffset()780 void SwRubyPortion::CalcRubyOffset()
781 {
782     const SwLineLayout *pCurr = &GetRoot();
783     if( !OnTop() )
784     {
785         pCurr = pCurr->GetNext();
786         if( !pCurr )
787             return;
788     }
789     const SwLinePortion *pPor = pCurr->GetFirstPortion();
790     const SwFldPortion *pFld = NULL;
791     while( pPor )
792     {
793         if( pPor->InFldGrp() )
794             pFld = (SwFldPortion*)pPor;
795         pPor = pPor->GetPortion();
796     }
797     if( pFld )
798     {
799         if( pFld->HasFollow() )
800             nRubyOffset = pFld->GetNextOffset();
801         else
802             nRubyOffset = STRING_LEN;
803     }
804 }
805 
806 /*-----------------13.10.00 16:22-------------------
807  * SwTxtSizeInfo::GetMultiCreator(..)
808  * If we (e.g. the position rPos) are inside a two-line-attribute or
809  * a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
810  * otherwise the function returns zero.
811  * The rPos parameter is set to the end of the multiportion,
812  * normally this is the end of the attribute,
813  * but sometimes it is the start of another attribute, which finished or
814  * interrupts the first attribute.
815  * E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute
816  * with different brackets interrupts another 2-line-attribute.
817  * --------------------------------------------------*/
818 
819 /*-----------------13.11.00 15:38-------------------
820  * lcl_Has2Lines(..)
821  * is a little help function for GetMultiCreator(..)
822  * It extracts the 2-line-format from a 2-line-attribute or a character style.
823  * The rValue is set to sal_True, if the 2-line-attribute's value is set and
824  * no 2-line-format reference is passed. If there is a 2-line-format reference,
825  * then the rValue is set only, if the 2-line-attribute's value is set _and_
826  * the 2-line-formats has the same brackets.
827  * --------------------------------------------------*/
828 
lcl_Has2Lines(const SwTxtAttr & rAttr,const SvxTwoLinesItem * & rpRef,sal_Bool & rValue)829 sal_Bool lcl_Has2Lines( const SwTxtAttr& rAttr, const SvxTwoLinesItem* &rpRef,
830     sal_Bool &rValue )
831 {
832     const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
833     if( pItem )
834     {
835         rValue = ((SvxTwoLinesItem*)pItem)->GetValue();
836         if( !rpRef )
837             rpRef = (SvxTwoLinesItem*)pItem;
838         else if( ((SvxTwoLinesItem*)pItem)->GetEndBracket() !=
839                     rpRef->GetEndBracket() ||
840                     ((SvxTwoLinesItem*)pItem)->GetStartBracket() !=
841                     rpRef->GetStartBracket() )
842             rValue = sal_False;
843         return sal_True;
844     }
845     return sal_False;
846 }
847 
848 /*-----------------16.02.01 16:39-------------------
849  * lcl_HasRotation(..)
850  * is a little help function for GetMultiCreator(..)
851  * It extracts the charrotation from a charrotate-attribute or a character style.
852  * The rValue is set to sal_True, if the charrotate-attribute's value is set and
853  * no charrotate-format reference is passed.
854  * If there is a charrotate-format reference, then the rValue is set only,
855  * if the charrotate-attribute's value is set _and_ identical
856  * to the charrotate-format's value.
857  * --------------------------------------------------*/
858 
lcl_HasRotation(const SwTxtAttr & rAttr,const SvxCharRotateItem * & rpRef,sal_Bool & rValue)859 sal_Bool lcl_HasRotation( const SwTxtAttr& rAttr,
860     const SvxCharRotateItem* &rpRef, sal_Bool &rValue )
861 {
862     const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_ROTATE );
863     if ( pItem )
864     {
865         rValue = 0 != ((SvxCharRotateItem*)pItem)->GetValue();
866         if( !rpRef )
867             rpRef = (SvxCharRotateItem*)pItem;
868         else if( ((SvxCharRotateItem*)pItem)->GetValue() !=
869                     rpRef->GetValue() )
870             rValue = sal_False;
871         return sal_True;
872     }
873 
874     return sal_False;
875 }
876 
GetMultiCreator(xub_StrLen & rPos,SwMultiPortion * pMulti) const877 SwMultiCreator* SwTxtSizeInfo::GetMultiCreator( xub_StrLen &rPos,
878                                                 SwMultiPortion* pMulti ) const
879 {
880     SwScriptInfo& rSI = ((SwParaPortion*)GetParaPortion())->GetScriptInfo();
881 
882     // get the last embedding level
883     sal_uInt8 nCurrLevel;
884     if ( pMulti )
885     {
886         ASSERT( pMulti->IsBidi(), "Nested MultiPortion is not BidiPortion" )
887         // level associated with bidi-portion;
888         nCurrLevel = ((SwBidiPortion*)pMulti)->GetLevel();
889     }
890     else
891         // no nested bidi portion required
892         nCurrLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
893 
894     // check if there is a field at rPos:
895     sal_uInt8 nNextLevel = nCurrLevel;
896     sal_Bool bFldBidi = sal_False;
897 
898     if ( CH_TXTATR_BREAKWORD == GetChar( rPos ) )
899     {
900         bFldBidi = sal_True;
901 /*
902         // examining the script of the field text should be sufficient
903         // for 99% of all cases
904         XubString aTxt = GetTxtFrm()->GetTxtNode()->GetExpandTxt( rPos, 1 );
905 
906         if ( pBreakIt->GetBreakIter().is() && aTxt.Len() )
907         {
908             sal_Bool bFldDir = ( i18n::ScriptType::COMPLEX ==
909                                  pBreakIt->GetRealScriptOfText( aTxt, 0 ) );
910             sal_Bool bCurrDir = ( 0 != ( nCurrLevel % 2 ) );
911             if ( bFldDir != bCurrDir )
912             {
913                 nNextLevel = nCurrLevel + 1;
914                 bFldBidi = sal_True;
915             }
916         }*/
917     }
918     else
919         nNextLevel = rSI.DirType( rPos );
920 
921     if ( GetTxt().Len() != rPos && nNextLevel > nCurrLevel )
922     {
923         rPos = bFldBidi ? rPos + 1 : rSI.NextDirChg( rPos, &nCurrLevel );
924         if ( STRING_LEN == rPos )
925             return NULL;
926         SwMultiCreator *pRet = new SwMultiCreator;
927         pRet->pItem = NULL;
928         pRet->pAttr = NULL;
929         pRet->nId = SW_MC_BIDI;
930         pRet->nLevel = nCurrLevel + 1;
931         return pRet;
932     }
933 
934     // a bidi portion can only contain other bidi portions
935     if ( pMulti )
936         return NULL;
937 
938     const SvxCharRotateItem* pRotate = NULL;
939     const SfxPoolItem* pRotItem;
940     if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
941         GetItemState( RES_CHRATR_ROTATE, sal_True, &pRotItem ) &&
942         ((SvxCharRotateItem*)pRotItem)->GetValue() )
943         pRotate = (SvxCharRotateItem*)pRotItem;
944     else
945         pRotItem = NULL;
946     const SvxTwoLinesItem* p2Lines = NULL;
947     const SfxPoolItem* pItem;
948     if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
949         GetItemState( RES_CHRATR_TWO_LINES, sal_True, &pItem ) &&
950         ((SvxTwoLinesItem*)pItem)->GetValue() )
951         p2Lines = (SvxTwoLinesItem*)pItem;
952     else
953         pItem = NULL;
954 
955     const SwpHints *pHints = pFrm->GetTxtNode()->GetpSwpHints();
956     if( !pHints && !p2Lines && !pRotate )
957         return NULL;
958     const SwTxtAttr *pRuby = NULL;
959     sal_Bool bTwo = sal_False;
960     sal_Bool bRot = sal_False;
961     sal_uInt16 n2Lines = USHRT_MAX;
962     sal_uInt16 nRotate = USHRT_MAX;
963     sal_uInt16 nCount = pHints ? pHints->Count() : 0;
964     sal_uInt16 i;
965     for( i = 0; i < nCount; ++i )
966     {
967         const SwTxtAttr *pTmp = (*pHints)[i];
968         xub_StrLen nStart = *pTmp->GetStart();
969         if( rPos < nStart )
970             break;
971         if( *pTmp->GetAnyEnd() > rPos )
972         {
973             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
974                 pRuby = pTmp;
975             else
976             {
977                 const SvxCharRotateItem* pRoTmp = NULL;
978                 if( lcl_HasRotation( *pTmp, pRoTmp, bRot ) )
979                 {
980                     nRotate = bRot ? i : nCount;
981                     pRotate = pRoTmp;
982                 }
983                 const SvxTwoLinesItem* p2Tmp = NULL;
984                 if( lcl_Has2Lines( *pTmp, p2Tmp, bTwo ) )
985                 {
986                     n2Lines = bTwo ? i : nCount;
987                     p2Lines = p2Tmp;
988                 }
989             }
990         }
991     }
992     if( pRuby )
993     {   // The winner is ... a ruby attribute and so
994         // the end of the multiportion is the end of the ruby attribute.
995         rPos = *pRuby->End();
996         SwMultiCreator *pRet = new SwMultiCreator;
997         pRet->pItem = NULL;
998         pRet->pAttr = pRuby;
999         pRet->nId = SW_MC_RUBY;
1000         pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1001         return pRet;
1002     }
1003     if( n2Lines < nCount || ( pItem && pItem == p2Lines &&
1004         rPos < GetTxt().Len() ) )
1005     {   // The winner is a 2-line-attribute,
1006         // the end of the multiportion depends on the following attributes...
1007         SwMultiCreator *pRet = new SwMultiCreator;
1008 
1009         // We note the endpositions of the 2-line attributes in aEnd as stack
1010         SvXub_StrLens aEnd;
1011 
1012         // The bOn flag signs the state of the last 2-line attribute in the
1013         // aEnd-stack, it is compatible with the winner-attribute or
1014         // it interrupts the other attribute.
1015         sal_Bool bOn = sal_True;
1016 
1017         if( n2Lines < nCount )
1018         {
1019             pRet->pItem = NULL;
1020             pRet->pAttr = (*pHints)[n2Lines];
1021             aEnd.push_front( *pRet->pAttr->End() );
1022             if( pItem )
1023             {
1024                 aEnd.front() = GetTxt().Len();
1025                 bOn = ((SvxTwoLinesItem*)pItem)->GetEndBracket() ==
1026                         p2Lines->GetEndBracket() &&
1027                       ((SvxTwoLinesItem*)pItem)->GetStartBracket() ==
1028                         p2Lines->GetStartBracket();
1029             }
1030         }
1031         else
1032         {
1033             pRet->pItem = pItem;
1034             pRet->pAttr = NULL;
1035             aEnd.push_front( GetTxt().Len() );
1036         }
1037         pRet->nId = SW_MC_DOUBLE;
1038         pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1039 
1040         // n2Lines is the index of the last 2-line-attribute, which contains
1041         // the actual position.
1042         i = 0;
1043         // At this moment we know that at position rPos the "winner"-attribute
1044         // causes a 2-line-portion. The end of the attribute is the end of the
1045         // portion, if there's no interrupting attribute.
1046         // There are two kinds of interruptors:
1047         // - ruby attributes stops the 2-line-attribute, the end of the
1048         //   multiline is the start of the ruby attribute
1049         // - 2-line-attributes with value "Off" or with different brackets,
1050         //   these attributes may interrupt the winner, but they could be
1051         //   neutralized by another 2-line-attribute starting at the same
1052         //   position with the same brackets as the winner-attribute.
1053 
1054         // In the following loop rPos is the critical position and it will be
1055         // evaluated, if at rPos starts a interrupting or a maintaining
1056         // continuity attribute.
1057         while( i < nCount )
1058         {
1059             const SwTxtAttr *pTmp = (*pHints)[i++];
1060             if( *pTmp->GetAnyEnd() <= rPos )
1061                 continue;
1062             if( rPos < *pTmp->GetStart() )
1063             {
1064                 // If bOn is sal_False and the next attribute starts later than rPos
1065                 // the winner attribute is interrupted at rPos.
1066                 // If the start of the next atribute is behind the end of
1067                 // the last attribute on the aEnd-stack, this is the endposition
1068                 // on the stack is the end of the 2-line portion.
1069                 if( !bOn || aEnd.back() < *pTmp->GetStart() )
1070                     break;
1071                 // At this moment, bOn is sal_True and the next attribute starts
1072                 // behind rPos, so we could move rPos to the next startpoint
1073                 rPos = *pTmp->GetStart();
1074                 // We clean up the aEnd-stack, endpositions equal to rPos are
1075                 // superfluous.
1076                 while( !aEnd.empty() && aEnd.back() <= rPos )
1077                 {
1078                     bOn = !bOn;
1079                     aEnd.pop_back();
1080                 }
1081                 // If the endstack is empty, we simulate an attribute with
1082                 // state sal_True and endposition rPos
1083                 if( aEnd.empty() )
1084                 {
1085                     aEnd.push_front( rPos );
1086                     bOn = sal_True;
1087                 }
1088             }
1089             // A ruby attribute stops the 2-line immediately
1090             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1091                 return pRet;
1092             if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
1093             {   // We have an interesting attribute..
1094                 if( bTwo == bOn )
1095                 {   // .. with the same state, so the last attribute could
1096                     // be continued.
1097                     if( aEnd.back() < *pTmp->End() )
1098                         aEnd.back() = *pTmp->End();
1099                 }
1100                 else
1101                 {   // .. with a different state.
1102                     bOn = bTwo;
1103                     // If this is smaller than the last on the stack, we put
1104                     // it on the stack. If it has the same endposition, the last
1105                     // could be removed.
1106                     if( aEnd.back() > *pTmp->End() )
1107                         aEnd.push_back( *pTmp->End() );
1108                     else if( aEnd.size() > 1 )
1109                         aEnd.pop_back();
1110                     else
1111                         aEnd.back() = *pTmp->End();
1112                 }
1113             }
1114         }
1115         if( bOn && !aEnd.empty() )
1116             rPos = aEnd.back();
1117         return pRet;
1118     }
1119     if( nRotate < nCount || ( pRotItem && pRotItem == pRotate &&
1120         rPos < GetTxt().Len() ) )
1121     {   // The winner is a rotate-attribute,
1122         // the end of the multiportion depends on the following attributes...
1123         SwMultiCreator *pRet = new SwMultiCreator;
1124         pRet->nId = SW_MC_ROTATE;
1125 
1126         // We note the endpositions of the 2-line attributes in aEnd as stack
1127         SvXub_StrLens aEnd;
1128 
1129         // The bOn flag signs the state of the last 2-line attribute in the
1130         // aEnd-stack, which could interrupts the winning rotation attribute.
1131         sal_Bool bOn = pItem ? sal_True : sal_False;
1132         aEnd.push_front( GetTxt().Len() );
1133         // n2Lines is the index of the last 2-line-attribute, which contains
1134         // the actual position.
1135         i = 0;
1136         xub_StrLen n2Start = rPos;
1137         while( i < nCount )
1138         {
1139             const SwTxtAttr *pTmp = (*pHints)[i++];
1140             if( *pTmp->GetAnyEnd() <= n2Start )
1141                 continue;
1142             if( n2Start < *pTmp->GetStart() )
1143             {
1144                 if( bOn || aEnd.back() < *pTmp->GetStart() )
1145                     break;
1146                 n2Start = *pTmp->GetStart();
1147                 while( !aEnd.empty() && aEnd.back() <= n2Start )
1148                 {
1149                     bOn = !bOn;
1150                     aEnd.pop_back();
1151                 }
1152                 if( aEnd.empty() )
1153                 {
1154                     aEnd.push_front( n2Start );
1155                     bOn = sal_False;
1156                 }
1157             }
1158             // A ruby attribute stops immediately
1159             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1160             {
1161                 bOn = sal_True;
1162                 break;
1163             }
1164             p2Lines = NULL;
1165             if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
1166             {
1167                 if( bTwo == bOn )
1168                 {
1169                     if( aEnd.back() < *pTmp->End() )
1170                         aEnd.back() = *pTmp->End();
1171                 }
1172                 else
1173                 {
1174                     bOn = bTwo;
1175                     if( aEnd.back() > *pTmp->End() )
1176                         aEnd.push_back( *pTmp->End() );
1177                     else if( aEnd.size() > 1 )
1178                         aEnd.pop_back();
1179                     else
1180                         aEnd.back() = *pTmp->End();
1181                 }
1182             }
1183         }
1184         if( !bOn && !aEnd.empty() )
1185             n2Start = aEnd.back();
1186 
1187         if( !aEnd.empty() )
1188             aEnd.clear();
1189 
1190         bOn = sal_True;
1191         if( nRotate < nCount )
1192         {
1193             pRet->pItem = NULL;
1194             pRet->pAttr = (*pHints)[nRotate];
1195             aEnd.push_front( *pRet->pAttr->End() );
1196             if( pRotItem )
1197             {
1198                 aEnd.front() = GetTxt().Len();
1199                 bOn = ((SvxCharRotateItem*)pRotItem)->GetValue() ==
1200                         pRotate->GetValue();
1201             }
1202         }
1203         else
1204         {
1205             pRet->pItem = pRotItem;
1206             pRet->pAttr = NULL;
1207             aEnd.push_front( GetTxt().Len() );
1208         }
1209         i = 0;
1210         while( i < nCount )
1211         {
1212             const SwTxtAttr *pTmp = (*pHints)[i++];
1213             if( *pTmp->GetAnyEnd() <= rPos )
1214                 continue;
1215             if( rPos < *pTmp->GetStart() )
1216             {
1217                 if( !bOn || aEnd.back() < *pTmp->GetStart() )
1218                     break;
1219                 rPos = *pTmp->GetStart();
1220                 while( !aEnd.empty() && aEnd.back() <= rPos )
1221                 {
1222                     bOn = !bOn;
1223                     aEnd.pop_back();
1224                 }
1225                 if( aEnd.empty() )
1226                 {
1227                     aEnd.push_front( rPos );
1228                     bOn = sal_True;
1229                 }
1230             }
1231             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1232             {
1233                 bOn = sal_False;
1234                 break;
1235             }
1236             if( lcl_HasRotation( *pTmp, pRotate, bTwo ) )
1237             {
1238                 if( bTwo == bOn )
1239                 {
1240                     if( aEnd.back() < *pTmp->End() )
1241                         aEnd.back() = *pTmp->End();
1242                 }
1243                 else
1244                 {
1245                     bOn = bTwo;
1246                     if( aEnd.back() > *pTmp->End() )
1247                         aEnd.push_back( *pTmp->End() );
1248                     else if( aEnd.size() > 1 )
1249                         aEnd.pop_back();
1250                     else
1251                         aEnd.back() = *pTmp->End();
1252                 }
1253             }
1254         }
1255         if( bOn && !aEnd.empty() )
1256             rPos = aEnd.back();
1257         if( rPos > n2Start )
1258             rPos = n2Start;
1259         return pRet;
1260     }
1261     return NULL;
1262 }
1263 
1264 /*-----------------01.11.00 14:52-------------------
1265  * SwSpaceManipulator
1266  * is a little helper class to manage the spaceadd-arrays of the text adjustment
1267  * during a PaintMultiPortion.
1268  * The constructor prepares the array for the first line of multiportion,
1269  * the SecondLine-function restores the values for the first line and prepares
1270  * the second line.
1271  * The destructor restores the values of the last manipulation.
1272  * --------------------------------------------------*/
1273 
1274 class SwSpaceManipulator
1275 {
1276     SwTxtPaintInfo& rInfo;
1277     SwMultiPortion& rMulti;
1278     std::vector<long>* pOldSpaceAdd;
1279     MSHORT nOldSpIdx;
1280     long nSpaceAdd;
1281     sal_Bool bSpaceChg  : 1;
1282     sal_uInt8 nOldDir   : 2;
1283 public:
1284     SwSpaceManipulator( SwTxtPaintInfo& rInf, SwMultiPortion& rMult );
1285     ~SwSpaceManipulator();
1286     void SecondLine();
GetSpaceAdd() const1287     inline long GetSpaceAdd() const { return nSpaceAdd; }
1288 };
1289 
SwSpaceManipulator(SwTxtPaintInfo & rInf,SwMultiPortion & rMult)1290 SwSpaceManipulator::SwSpaceManipulator( SwTxtPaintInfo& rInf,
1291                                         SwMultiPortion& rMult ) :
1292          rInfo( rInf ), rMulti( rMult )
1293 {
1294     pOldSpaceAdd = rInfo.GetpSpaceAdd();
1295     nOldSpIdx = rInfo.GetSpaceIdx();
1296     nOldDir = rInfo.GetDirection();
1297     rInfo.SetDirection( rMulti.GetDirection() );
1298     bSpaceChg = sal_False;
1299 
1300     if( rMulti.IsDouble() )
1301     {
1302         nSpaceAdd = ( pOldSpaceAdd && !rMulti.HasTabulator() ) ?
1303                       rInfo.GetSpaceAdd() : 0;
1304         if( rMulti.GetRoot().IsSpaceAdd() )
1305         {
1306             rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
1307             rInfo.ResetSpaceIdx();
1308             bSpaceChg = rMulti.ChgSpaceAdd( &rMulti.GetRoot(), nSpaceAdd );
1309         }
1310         else if( rMulti.HasTabulator() )
1311             rInfo.SetpSpaceAdd( NULL );
1312     }
1313     else if ( ! rMulti.IsBidi() )
1314     {
1315         rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
1316         rInfo.ResetSpaceIdx();
1317     }
1318 }
1319 
SecondLine()1320 void SwSpaceManipulator::SecondLine()
1321 {
1322     if( bSpaceChg )
1323     {
1324         rInfo.RemoveFirstSpaceAdd();
1325         bSpaceChg = sal_False;
1326     }
1327     SwLineLayout *pLay = rMulti.GetRoot().GetNext();
1328     if( pLay->IsSpaceAdd() )
1329     {
1330         rInfo.SetpSpaceAdd( pLay->GetpLLSpaceAdd() );
1331         rInfo.ResetSpaceIdx();
1332         bSpaceChg = rMulti.ChgSpaceAdd( pLay, nSpaceAdd );
1333     }
1334     else
1335     {
1336         rInfo.SetpSpaceAdd( (!rMulti.IsDouble() || rMulti.HasTabulator() ) ?
1337                                 0 : pOldSpaceAdd );
1338         rInfo.SetSpaceIdx( nOldSpIdx);
1339     }
1340 }
1341 
~SwSpaceManipulator()1342 SwSpaceManipulator::~SwSpaceManipulator()
1343 {
1344     if( bSpaceChg )
1345     {
1346         rInfo.RemoveFirstSpaceAdd();
1347         bSpaceChg = sal_False;
1348     }
1349     rInfo.SetpSpaceAdd( pOldSpaceAdd );
1350     rInfo.SetSpaceIdx( nOldSpIdx);
1351     rInfo.SetDirection( nOldDir );
1352 }
1353 
1354 /*-----------------13.10.00 16:24-------------------
1355  * SwTxtPainter::PaintMultiPortion manages the paint for a SwMultiPortion.
1356  * External, for the calling function, it seems to be a normal Paint-function,
1357  * internal it is like a SwTxtFrm::Paint with multiple DrawTextLines
1358  * --------------------------------------------------*/
1359 
PaintMultiPortion(const SwRect & rPaint,SwMultiPortion & rMulti,const SwMultiPortion * pEnvPor)1360 void SwTxtPainter::PaintMultiPortion( const SwRect &rPaint,
1361     SwMultiPortion& rMulti, const SwMultiPortion* pEnvPor )
1362 {
1363     GETGRID( pFrm->FindPageFrm() )
1364     const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
1365     sal_uInt16 nGridWidth = 0;
1366     sal_uInt16 nRubyHeight = 0;
1367     sal_Bool bRubyTop = sal_False;
1368 
1369     if ( bHasGrid )
1370     {
1371         nGridWidth = pGrid->GetBaseHeight();
1372         nRubyHeight = pGrid->GetRubyHeight();
1373         bRubyTop = ! pGrid->GetRubyTextBelow();
1374     }
1375 
1376     // do not allow grid mode for first line in ruby portion
1377     const sal_Bool bRubyInGrid = bHasGrid && rMulti.IsRuby();
1378 
1379     const sal_uInt16 nOldHeight = rMulti.Height();
1380     const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
1381 
1382     if ( bRubyInGrid )
1383     {
1384         GetInfo().SetSnapToGrid( ! bRubyTop );
1385         rMulti.Height( pCurr->Height() );
1386     }
1387 
1388     SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1389     sal_uInt8 nEnvDir = 0;
1390     sal_uInt8 nThisDir = 0;
1391     sal_uInt8 nFrmDir = 0;
1392     if ( rMulti.IsBidi() )
1393     {
1394         // these values are needed for the calculation of the x coordinate
1395         // and the layout mode
1396         ASSERT( ! pEnvPor || pEnvPor->IsBidi(),
1397                 "Oh no, I expected a BidiPortion" )
1398         nFrmDir = GetInfo().GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1399         nEnvDir = pEnvPor ? ((SwBidiPortion*)pEnvPor)->GetLevel() % 2 : nFrmDir;
1400         nThisDir = ((SwBidiPortion&)rMulti).GetLevel() % 2;
1401     }
1402 
1403 #if OSL_DEBUG_LEVEL > 1
1404     // only paint first level bidi portions
1405     if( rMulti.Width() > 1 && ! pEnvPor )
1406         GetInfo().DrawViewOpt( rMulti, POR_FLD );
1407 #endif
1408 
1409     if ( bRubyInGrid )
1410         rMulti.Height( nOldHeight );
1411 
1412     // do we have to repaint a post it portion?
1413     if( GetInfo().OnWin() && rMulti.GetPortion() &&
1414         ! rMulti.GetPortion()->Width() )
1415         rMulti.GetPortion()->PrePaint( GetInfo(), &rMulti );
1416 
1417     // old values must be saved and restored at the end
1418     xub_StrLen nOldLen = GetInfo().GetLen();
1419     KSHORT nOldX = KSHORT(GetInfo().X());
1420     long nOldY = GetInfo().Y();
1421     xub_StrLen nOldIdx = GetInfo().GetIdx();
1422 
1423     SwSpaceManipulator aManip( GetInfo(), rMulti );
1424 
1425     SwFontSave *pFontSave;
1426     SwFont* pTmpFnt;
1427 
1428     if( rMulti.IsDouble() )
1429     {
1430         pTmpFnt = new SwFont( *GetInfo().GetFont() );
1431         if( rMulti.IsDouble() )
1432         {
1433             SetPropFont( 50 );
1434             pTmpFnt->SetProportion( GetPropFont() );
1435         }
1436         pFontSave = new SwFontSave( GetInfo(), pTmpFnt, this );
1437     }
1438     else
1439     {
1440         pFontSave = NULL;
1441         pTmpFnt = NULL;
1442     }
1443 
1444     if( rMulti.HasBrackets() )
1445     {
1446         xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
1447         GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
1448         SeekAndChg( GetInfo() );
1449         ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(), 0, sal_True );
1450         GetInfo().SetIdx( nTmpOldIdx );
1451     }
1452 
1453     KSHORT nTmpX = KSHORT(GetInfo().X());
1454 
1455     SwLineLayout* pLay = &rMulti.GetRoot();// the first line of the multiportion
1456     SwLinePortion* pPor = pLay->GetFirstPortion();//first portion of these line
1457     SwTwips nOfst = 0;
1458 
1459     // GetInfo().Y() is the baseline from the surrounding line. We must switch
1460     // this temporary to the baseline of the inner lines of the multiportion.
1461     if( rMulti.HasRotation() )
1462     {
1463         if( rMulti.IsRevers() )
1464         {
1465             GetInfo().Y( nOldY - rMulti.GetAscent() );
1466             nOfst = nTmpX + rMulti.Width();
1467         }
1468         else
1469         {
1470             GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
1471             nOfst = nTmpX;
1472         }
1473     }
1474     else if ( rMulti.IsBidi() )
1475     {
1476         // does the current bidi portion has the same direction
1477         // as its environment?
1478         if ( nEnvDir != nThisDir )
1479         {
1480             // different directions, we have to adjust the x coordinate
1481             SwTwips nMultiWidth = rMulti.Width() +
1482                     rMulti.CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
1483 
1484             if ( nFrmDir == nThisDir )
1485                 GetInfo().X( GetInfo().X() - nMultiWidth );
1486             else
1487                 GetInfo().X( GetInfo().X() + nMultiWidth );
1488         }
1489 
1490         nOfst = nOldY - rMulti.GetAscent();
1491 
1492         // set layout mode
1493         aLayoutModeModifier.Modify( nThisDir );
1494     }
1495     else
1496         nOfst = nOldY - rMulti.GetAscent();
1497 
1498     sal_Bool bRest = pLay->IsRest();
1499     sal_Bool bFirst = sal_True;
1500 
1501     ASSERT( 0 == GetInfo().GetUnderFnt() || rMulti.IsBidi(),
1502             " Only BiDi portions are allowed to use the common underlining font" )
1503 
1504     do
1505     {
1506         if ( bHasGrid )
1507         {
1508             if( rMulti.HasRotation() )
1509             {
1510                 const sal_uInt16 nAdjustment = ( pLay->Height() - pPor->Height() ) / 2 +
1511                                             pPor->GetAscent();
1512                 if( rMulti.IsRevers() )
1513                     GetInfo().X( nOfst - nAdjustment );
1514                 else
1515                     GetInfo().X( nOfst + nAdjustment );
1516             }
1517             else
1518             {
1519                 // special treatment for ruby portions in grid mode
1520                 SwTwips nAdjustment = 0;
1521                 if ( rMulti.IsRuby() )
1522                 {
1523                     if ( bRubyTop != ( pLay == &rMulti.GetRoot() ) )
1524                         // adjust base text
1525                         nAdjustment = ( pCurr->Height() - nRubyHeight - pPor->Height() ) / 2;
1526                     else if ( bRubyTop )
1527                         // adjust upper ruby text
1528                         nAdjustment = nRubyHeight - pPor->Height();
1529                     // else adjust lower ruby text
1530                 }
1531 
1532                 GetInfo().Y( nOfst + nAdjustment + pPor->GetAscent() );
1533             }
1534         }
1535         else if( rMulti.HasRotation() )
1536         {
1537             if( rMulti.IsRevers() )
1538                 GetInfo().X( nOfst - AdjustBaseLine( *pLay, pPor, 0, 0, sal_True ) );
1539             else
1540                 GetInfo().X( nOfst + AdjustBaseLine( *pLay, pPor ) );
1541         }
1542         else
1543             GetInfo().Y( nOfst + AdjustBaseLine( *pLay, pPor ) );
1544 
1545         sal_Bool bSeeked = sal_True;
1546         GetInfo().SetLen( pPor->GetLen() );
1547 
1548         if( bRest && pPor->InFldGrp() && !pPor->GetLen() )
1549         {
1550             if( ((SwFldPortion*)pPor)->HasFont() )
1551                 bSeeked = sal_False;
1552             else
1553                 SeekAndChgBefore( GetInfo() );
1554         }
1555         else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
1556             SeekAndChg( GetInfo() );
1557         else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
1558         {
1559             if( GetRedln() )
1560                 SeekAndChg( GetInfo() );
1561             else
1562                 SeekAndChgBefore( GetInfo() );
1563         }
1564         else
1565             bSeeked = sal_False;
1566 
1567         SwLinePortion *pNext = pPor->GetPortion();
1568         if(GetInfo().OnWin() && pNext && !pNext->Width() )
1569         {
1570             if ( !bSeeked )
1571                 SeekAndChg( GetInfo() );
1572             pNext->PrePaint( GetInfo(), pPor );
1573         }
1574 
1575         CheckSpecialUnderline( pPor );
1576         SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
1577         if ( pUnderLineFnt )
1578         {
1579             if ( rMulti.IsDouble() )
1580                 pUnderLineFnt->GetFont().SetProportion( 50 );
1581             pUnderLineFnt->SetPos( GetInfo().GetPos() );
1582         }
1583 
1584         if ( rMulti.IsBidi() )
1585         {
1586             // we do not allow any rotation inside a bidi portion
1587             SwFont* pTmpFont = GetInfo().GetFont();
1588             pTmpFont->SetVertical( 0, GetInfo().GetTxtFrm()->IsVertical() );
1589         }
1590 
1591         if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() )
1592         {
1593             // but we do allow nested bidi portions
1594             ASSERT( rMulti.IsBidi(), "Only nesting of bidi portions is allowed" )
1595             PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor, &rMulti );
1596         }
1597         else
1598             pPor->Paint( GetInfo() );
1599 
1600         if( GetFnt()->IsURL() && pPor->InTxtGrp() )
1601             GetInfo().NotifyURL( *pPor );
1602 
1603         bFirst &= !pPor->GetLen();
1604         if( pNext || !pPor->IsMarginPortion() )
1605             pPor->Move( GetInfo() );
1606 
1607         pPor = pNext;
1608 
1609         // If there's no portion left, we go to the next line
1610         if( !pPor && pLay->GetNext() )
1611         {
1612             pLay = pLay->GetNext();
1613             pPor = pLay->GetFirstPortion();
1614             bRest = pLay->IsRest();
1615             aManip.SecondLine();
1616 
1617             // delete underline font
1618             delete GetInfo().GetUnderFnt();
1619             GetInfo().SetUnderFnt( 0 );
1620 
1621             if( rMulti.HasRotation() )
1622             {
1623                 if( rMulti.IsRevers() )
1624                 {
1625                     nOfst += pLay->Height();
1626                     GetInfo().Y( nOldY - rMulti.GetAscent() );
1627                 }
1628                 else
1629                 {
1630                     nOfst -= pLay->Height();
1631                     GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
1632                 }
1633             }
1634             else if ( bHasGrid && rMulti.IsRuby() )
1635             {
1636                 GetInfo().X( nTmpX );
1637                 if ( bRubyTop )
1638                 {
1639                     nOfst += nRubyHeight;
1640                     GetInfo().SetSnapToGrid( sal_True );
1641                 }
1642                 else
1643                 {
1644                     nOfst += pCurr->Height() - nRubyHeight;
1645                     GetInfo().SetSnapToGrid( sal_False );
1646                 }
1647             } else
1648             {
1649                 GetInfo().X( nTmpX );
1650                 // We switch to the baseline of the next inner line
1651                 nOfst += rMulti.GetRoot().Height();
1652             }
1653         }
1654     } while( pPor );
1655 
1656     if ( bRubyInGrid )
1657         GetInfo().SetSnapToGrid( bOldGridModeAllowed );
1658 
1659     // delete underline font
1660     if ( ! rMulti.IsBidi() )
1661     {
1662         delete GetInfo().GetUnderFnt();
1663         GetInfo().SetUnderFnt( 0 );
1664     }
1665 
1666     GetInfo().SetIdx( nOldIdx );
1667     GetInfo().Y( nOldY );
1668 
1669     if( rMulti.HasBrackets() )
1670     {
1671         xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
1672         GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
1673         SeekAndChg( GetInfo() );
1674         GetInfo().X( nOldX );
1675         ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(),
1676             aManip.GetSpaceAdd(), sal_False );
1677         GetInfo().SetIdx( nTmpOldIdx );
1678     }
1679     // Restore the saved values
1680     GetInfo().X( nOldX );
1681     GetInfo().SetLen( nOldLen );
1682     delete pFontSave;
1683     delete pTmpFnt;
1684     SetPropFont( 0 );
1685 }
1686 
lcl_ExtractFieldFollow(SwLineLayout * pLine,SwLinePortion * & rpFld)1687 sal_Bool lcl_ExtractFieldFollow( SwLineLayout* pLine, SwLinePortion* &rpFld )
1688 {
1689     SwLinePortion* pLast = pLine;
1690     rpFld = pLine->GetPortion();
1691     while( rpFld && !rpFld->InFldGrp() )
1692     {
1693         pLast = rpFld;
1694         rpFld = rpFld->GetPortion();
1695     }
1696     sal_Bool bRet = rpFld != 0;
1697     if( bRet )
1698     {
1699         if( ((SwFldPortion*)rpFld)->IsFollow() )
1700         {
1701             rpFld->Truncate();
1702             pLast->SetPortion( NULL );
1703         }
1704         else
1705             rpFld = NULL;
1706     }
1707     pLine->Truncate();
1708     return bRet;
1709 }
1710 
1711 /*----------------------------------------------------
1712  *              lcl_TruncateMultiPortion
1713  * If a multi portion completely has to go to the
1714  * next line, this function is called to trunctate
1715  * the rest of the remaining multi portion
1716  * --------------------------------------------------*/
1717 
lcl_TruncateMultiPortion(SwMultiPortion & rMulti,SwTxtFormatInfo & rInf,xub_StrLen nStartIdx)1718 void lcl_TruncateMultiPortion( SwMultiPortion& rMulti, SwTxtFormatInfo& rInf,
1719                                xub_StrLen nStartIdx )
1720 {
1721     rMulti.GetRoot().Truncate();
1722     rMulti.GetRoot().SetLen(0);
1723     rMulti.GetRoot().Width(0);
1724 //  rMulti.CalcSize( *this, aInf );
1725     if ( rMulti.GetRoot().GetNext() )
1726     {
1727         rMulti.GetRoot().GetNext()->Truncate();
1728         rMulti.GetRoot().GetNext()->SetLen( 0 );
1729         rMulti.GetRoot().GetNext()->Width( 0 );
1730     }
1731     rMulti.Width( 0 );
1732     rMulti.SetLen(0);
1733     rInf.SetIdx( nStartIdx );
1734 }
1735 
1736 /*-----------------------------------------------------------------------------
1737  *              SwTxtFormatter::BuildMultiPortion
1738  * manages the formatting of a SwMultiPortion. External, for the calling
1739  * function, it seems to be a normal Format-function, internal it is like a
1740  * SwTxtFrm::_Format with multiple BuildPortions
1741  *---------------------------------------------------------------------------*/
1742 
BuildMultiPortion(SwTxtFormatInfo & rInf,SwMultiPortion & rMulti)1743 sal_Bool SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
1744     SwMultiPortion& rMulti )
1745 {
1746     SwTwips nMaxWidth = rInf.Width();
1747     KSHORT nOldX = 0;
1748 
1749     if( rMulti.HasBrackets() )
1750     {
1751         xub_StrLen nOldIdx = rInf.GetIdx();
1752         rInf.SetIdx( ((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart );
1753         SeekAndChg( rInf );
1754         nOldX = KSHORT(GetInfo().X());
1755         ((SwDoubleLinePortion&)rMulti).FormatBrackets( rInf, nMaxWidth );
1756         rInf.SetIdx( nOldIdx );
1757     }
1758 
1759     SeekAndChg( rInf );
1760     SwFontSave *pFontSave;
1761     if( rMulti.IsDouble() )
1762     {
1763         SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
1764         if( rMulti.IsDouble() )
1765         {
1766             SetPropFont( 50 );
1767             pTmpFnt->SetProportion( GetPropFont() );
1768         }
1769         pFontSave = new SwFontSave( rInf, pTmpFnt, this );
1770     }
1771     else
1772         pFontSave = NULL;
1773 
1774     SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1775     if ( rMulti.IsBidi() )
1776     {
1777         // set layout mode
1778         aLayoutModeModifier.Modify( ! rInf.GetTxtFrm()->IsRightToLeft() );
1779     }
1780 
1781     SwTwips nTmpX = 0;
1782 
1783     if( rMulti.HasRotation() )
1784     {
1785         // For nMaxWidth we take the height of the body frame.
1786         // #i25067#: If the current frame is inside a table, we restrict
1787         // nMaxWidth to the current frame height, unless the frame size
1788         // attribute is set to variable size:
1789 
1790         // We set nTmpX (which is used for portion calculating) to the
1791         // current Y value
1792         const SwPageFrm* pPage = pFrm->FindPageFrm();
1793         ASSERT( pPage, "No page in frame!");
1794         const SwLayoutFrm* pUpperFrm = pPage;
1795 
1796         if ( pFrm->IsInTab() )
1797         {
1798             pUpperFrm = pFrm->GetUpper();
1799             while ( pUpperFrm && !pUpperFrm->IsCellFrm() )
1800                 pUpperFrm = pUpperFrm->GetUpper();
1801             ASSERT( pUpperFrm, "pFrm is in table but does not have an upper cell frame" )
1802             const SwTableLine* pLine = ((SwRowFrm*)pUpperFrm->GetUpper())->GetTabLine();
1803             const SwFmtFrmSize& rFrmFmtSize = pLine->GetFrmFmt()->GetFrmSize();
1804             if ( ATT_VAR_SIZE == rFrmFmtSize.GetHeightSizeType() )
1805                 pUpperFrm = pPage;
1806         }
1807         if ( pUpperFrm == pPage && !pFrm->IsInFtn() )
1808             pUpperFrm = pPage->FindBodyCont();
1809 
1810         nMaxWidth = pUpperFrm ?
1811                     ( rInf.GetTxtFrm()->IsVertical() ?
1812                       pUpperFrm->Prt().Width() :
1813                       pUpperFrm->Prt().Height() ) :
1814                     USHRT_MAX;
1815     }
1816     else
1817         nTmpX = rInf.X();
1818 
1819     SwMultiPortion* pOldMulti = pMulti;
1820 
1821     pMulti = &rMulti;
1822     SwLineLayout *pOldCurr = pCurr;
1823     xub_StrLen nOldStart = GetStart();
1824     SwTwips nMinWidth = nTmpX + 1;
1825     SwTwips nActWidth = nMaxWidth;
1826     const xub_StrLen nStartIdx = rInf.GetIdx();
1827     xub_StrLen nMultiLen = rMulti.GetLen();
1828 
1829     SwLinePortion *pFirstRest;
1830     SwLinePortion *pSecondRest;
1831     if( rMulti.IsFormatted() )
1832     {
1833         if( !lcl_ExtractFieldFollow( &rMulti.GetRoot(), pFirstRest )
1834             && rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
1835             lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pFirstRest );
1836         if( !rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
1837             lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pSecondRest );
1838         else
1839             pSecondRest = NULL;
1840     }
1841     else
1842     {
1843         pFirstRest = rMulti.GetRoot().GetPortion();
1844         pSecondRest = rMulti.GetRoot().GetNext() ?
1845                       rMulti.GetRoot().GetNext()->GetPortion() : NULL;
1846         if( pFirstRest )
1847             rMulti.GetRoot().SetPortion( NULL );
1848         if( pSecondRest )
1849             rMulti.GetRoot().GetNext()->SetPortion( NULL );
1850         rMulti.SetFormatted();
1851         nMultiLen = nMultiLen - rInf.GetIdx();
1852     }
1853 
1854     // save some values
1855     const XubString* pOldTxt = &(rInf.GetTxt());
1856     const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
1857 
1858     XubString aMultiStr( rInf.GetTxt(), 0, nMultiLen + rInf.GetIdx() );
1859     rInf.SetTxt( aMultiStr );
1860     SwTxtFormatInfo aInf( rInf, rMulti.GetRoot(), nActWidth );
1861     // Do we allow break cuts? The FirstMulti-Flag is evaluated during
1862     // line break determination.
1863     sal_Bool bFirstMulti = rInf.GetIdx() != rInf.GetLineStart();
1864 
1865     SwLinePortion *pNextFirst = NULL;
1866     SwLinePortion *pNextSecond = NULL;
1867     sal_Bool bRet = sal_False;
1868 
1869     GETGRID( pFrm->FindPageFrm() )
1870     const sal_Bool bHasGrid = pGrid && GRID_LINES_CHARS == pGrid->GetGridType();
1871 
1872     sal_uInt16 nGridWidth = 0;
1873     sal_uInt16 nRubyHeight = 0;
1874     sal_Bool bRubyTop = sal_False;
1875 
1876     if ( bHasGrid )
1877     {
1878         nGridWidth = pGrid->GetBaseHeight();
1879         nRubyHeight = pGrid->GetRubyHeight();
1880         bRubyTop = ! pGrid->GetRubyTextBelow();
1881     }
1882 
1883     do
1884     {
1885         pCurr = &rMulti.GetRoot();
1886         nStart = nStartIdx;
1887         bRet = sal_False;
1888         FormatReset( aInf );
1889         aInf.X( nTmpX );
1890         aInf.Width( KSHORT(nActWidth) );
1891         aInf.RealWidth( KSHORT(nActWidth) );
1892         aInf.SetFirstMulti( bFirstMulti );
1893         aInf.SetNumDone( rInf.IsNumDone() );
1894         aInf.SetFtnDone( rInf.IsFtnDone() );
1895 
1896         if( pFirstRest )
1897         {
1898             ASSERT( pFirstRest->InFldGrp(), "BuildMulti: Fieldrest expected");
1899             SwFldPortion *pFld =
1900                 ((SwFldPortion*)pFirstRest)->Clone(
1901                     ((SwFldPortion*)pFirstRest)->GetExp() );
1902             pFld->SetFollow( sal_True );
1903             aInf.SetRest( pFld );
1904         }
1905         aInf.SetRuby( rMulti.IsRuby() && rMulti.OnTop() );
1906 
1907         // in grid mode we temporarily have to disable the grid for the ruby line
1908         const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
1909         if ( bHasGrid && aInf.IsRuby() && bRubyTop )
1910             aInf.SetSnapToGrid( sal_False );
1911 
1912         // If there's no more rubytext, then buildportion is forbidden
1913         if( pFirstRest || !aInf.IsRuby() )
1914             BuildPortions( aInf );
1915 
1916         aInf.SetSnapToGrid( bOldGridModeAllowed );
1917 
1918         rMulti.CalcSize( *this, aInf );
1919         pCurr->SetRealHeight( pCurr->Height() );
1920 
1921         if( rMulti.IsBidi() )
1922         {
1923             pNextFirst = aInf.GetRest();
1924             break;
1925         }
1926 
1927         if( rMulti.HasRotation() && !rMulti.IsDouble() )
1928             break;
1929         // second line has to be formatted
1930         else if( pCurr->GetLen()<nMultiLen || rMulti.IsRuby() || aInf.GetRest())
1931         {
1932             xub_StrLen nFirstLen = pCurr->GetLen();
1933             delete pCurr->GetNext();
1934             pCurr->SetNext( new SwLineLayout() );
1935             pCurr = pCurr->GetNext();
1936             nStart = aInf.GetIdx();
1937             aInf.X( nTmpX );
1938             SwTxtFormatInfo aTmp( aInf, *pCurr, nActWidth );
1939             if( rMulti.IsRuby() )
1940             {
1941                 aTmp.SetRuby( !rMulti.OnTop() );
1942                 pNextFirst = aInf.GetRest();
1943                 if( pSecondRest )
1944                 {
1945                     ASSERT( pSecondRest->InFldGrp(), "Fieldrest expected");
1946                     SwFldPortion *pFld = ((SwFldPortion*)pSecondRest)->Clone(
1947                                     ((SwFldPortion*)pSecondRest)->GetExp() );
1948                     pFld->SetFollow( sal_True );
1949                     aTmp.SetRest( pFld );
1950                 }
1951                 if( !rMulti.OnTop() && nFirstLen < nMultiLen )
1952                     bRet = sal_True;
1953             }
1954             else
1955                 aTmp.SetRest( aInf.GetRest() );
1956             aInf.SetRest( NULL );
1957 
1958             // in grid mode we temporarily have to disable the grid for the ruby line
1959             if ( bHasGrid && aTmp.IsRuby() && ! bRubyTop )
1960                 aTmp.SetSnapToGrid( sal_False );
1961 
1962             BuildPortions( aTmp );
1963 
1964             aTmp.SetSnapToGrid( bOldGridModeAllowed );
1965 
1966             rMulti.CalcSize( *this, aInf );
1967             rMulti.GetRoot().SetRealHeight( rMulti.GetRoot().Height() );
1968             pCurr->SetRealHeight( pCurr->Height() );
1969             if( rMulti.IsRuby() )
1970             {
1971                 pNextSecond = aTmp.GetRest();
1972                 if( pNextFirst )
1973                     bRet = sal_True;
1974             }
1975             else
1976                 pNextFirst = aTmp.GetRest();
1977             if( ( !aTmp.IsRuby() && nFirstLen + pCurr->GetLen() < nMultiLen )
1978                 || aTmp.GetRest() )
1979                 // our guess for width of multiportion was too small,
1980                 // text did not fit into multiportion
1981                 bRet = sal_True;
1982         }
1983         if( rMulti.IsRuby() )
1984             break;
1985         if( bRet )
1986         {
1987             // our guess for multiportion width was too small,
1988             // we set min to act
1989             nMinWidth = nActWidth;
1990             nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
1991             if ( nActWidth == nMaxWidth && rInf.GetLineStart() == rInf.GetIdx() )
1992             // we have too less space, we must allow break cuts
1993             // ( the first multi flag is considered during TxtPortion::_Format() )
1994                 bFirstMulti = sal_False;
1995             if( nActWidth <= nMinWidth )
1996                 break;
1997         }
1998         else
1999         {
2000             // For Solaris, this optimisation can causes trouble:
2001             // Setting this to the portion width ( = rMulti.Width() )
2002             // can make GetTextBreak inside SwTxtGuess::Guess return to small
2003             // values. Therefore we add some extra twips.
2004             if( nActWidth > nTmpX + rMulti.Width() + 6 )
2005                 nActWidth = nTmpX + rMulti.Width() + 6;
2006             nMaxWidth = nActWidth;
2007             nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
2008             if( nActWidth >= nMaxWidth )
2009                 break;
2010             // we do not allow break cuts during formatting
2011             bFirstMulti = sal_True;
2012         }
2013         delete pNextFirst;
2014         pNextFirst = NULL;
2015     } while ( sal_True );
2016 
2017     pMulti = pOldMulti;
2018 
2019     pCurr = pOldCurr;
2020     nStart = nOldStart;
2021     SetPropFont( 0 );
2022 
2023     rMulti.SetLen( rMulti.GetRoot().GetLen() + ( rMulti.GetRoot().GetNext() ?
2024         rMulti.GetRoot().GetNext()->GetLen() : 0 ) );
2025 
2026     if( rMulti.IsDouble() )
2027     {
2028         ((SwDoubleLinePortion&)rMulti).CalcBlanks( rInf );
2029         if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() )
2030         {
2031             SwLineLayout* pLine = &rMulti.GetRoot();
2032             if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() > 0 )
2033             {
2034                 rInf.SetIdx( nStartIdx + pLine->GetLen() );
2035                 pLine = pLine->GetNext();
2036             }
2037             if( pLine )
2038             {
2039                 GetInfo().SetMulti( sal_True );
2040                 CalcNewBlock( pLine, NULL, rMulti.Width() );
2041                 GetInfo().SetMulti( sal_False );
2042             }
2043             rInf.SetIdx( nStartIdx );
2044         }
2045         if( ((SwDoubleLinePortion&)rMulti).GetBrackets() )
2046         {
2047             rMulti.Width( rMulti.Width() +
2048                     ((SwDoubleLinePortion&)rMulti).BracketWidth() );
2049             GetInfo().X( nOldX );
2050         }
2051     }
2052     else
2053     {
2054         rMulti.ActualizeTabulator();
2055         if( rMulti.IsRuby() )
2056         {
2057             ((SwRubyPortion&)rMulti).Adjust( rInf );
2058             ((SwRubyPortion&)rMulti).CalcRubyOffset();
2059         }
2060     }
2061     if( rMulti.HasRotation() )
2062     {
2063         SwTwips nH = rMulti.Width();
2064         SwTwips nAsc = rMulti.GetAscent() + ( nH - rMulti.Height() )/2;
2065         if( nAsc > nH )
2066             nAsc = nH;
2067         else if( nAsc < 0 )
2068             nAsc = 0;
2069         rMulti.Width( rMulti.Height() );
2070         rMulti.Height( KSHORT(nH) );
2071         rMulti.SetAscent( KSHORT(nAsc) );
2072         bRet = ( rInf.GetPos().X() + rMulti.Width() > rInf.Width() ) &&
2073                  nStartIdx != rInf.GetLineStart();
2074     }
2075     else if ( rMulti.IsBidi() )
2076     {
2077         bRet = rMulti.GetLen() < nMultiLen || pNextFirst;
2078     }
2079 
2080     // line break has to be performed!
2081     if( bRet )
2082     {
2083         ASSERT( !pNextFirst || pNextFirst->InFldGrp(),
2084             "BuildMultiPortion: Surprising restportion, field expected" );
2085         SwMultiPortion *pTmp;
2086         if( rMulti.IsDouble() )
2087             pTmp = new SwDoubleLinePortion( ((SwDoubleLinePortion&)rMulti),
2088                                             nMultiLen + rInf.GetIdx() );
2089         else if( rMulti.IsRuby() )
2090         {
2091             ASSERT( !pNextSecond || pNextSecond->InFldGrp(),
2092                 "BuildMultiPortion: Surprising restportion, field expected" );
2093 
2094             if ( rInf.GetIdx() == rInf.GetLineStart() )
2095             {
2096                 // the ruby portion has to be split in two portions
2097                 pTmp = new SwRubyPortion( ((SwRubyPortion&)rMulti),
2098                                           nMultiLen + rInf.GetIdx() );
2099 
2100                 if( pNextSecond )
2101                 {
2102                     pTmp->GetRoot().SetNext( new SwLineLayout() );
2103                     pTmp->GetRoot().GetNext()->SetPortion( pNextSecond );
2104                 }
2105                 pTmp->SetFollowFld();
2106             }
2107             else
2108             {
2109                 // we try to keep our ruby portion together
2110                 lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2111                 pTmp = 0;
2112             }
2113         }
2114         else if( rMulti.HasRotation() )
2115         {
2116             // we try to keep our rotated portion together
2117             lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2118             pTmp = new SwRotatedPortion( nMultiLen + rInf.GetIdx(),
2119                                          rMulti.GetDirection() );
2120         }
2121         // during a recursion of BuildMultiPortions we may not build
2122         // a new SwBidiPortion, this would cause a memory leak
2123         else if( rMulti.IsBidi() && ! pMulti )
2124         {
2125             if ( ! rMulti.GetLen() )
2126                 lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2127 
2128             // If there is a HolePortion at the end of the bidi portion,
2129             // it has to be moved behind the bidi portion. Otherwise
2130             // the visual cursor travelling gets into trouble.
2131             SwLineLayout& aRoot = rMulti.GetRoot();
2132             SwLinePortion* pPor = aRoot.GetFirstPortion();
2133             while ( pPor )
2134             {
2135                 if ( pPor->GetPortion() && pPor->GetPortion()->IsHolePortion() )
2136                 {
2137                     SwLinePortion* pHolePor = pPor->GetPortion();
2138                     pPor->SetPortion( NULL );
2139                     aRoot.SetLen( aRoot.GetLen() - pHolePor->GetLen() );
2140                     rMulti.SetLen( rMulti.GetLen() - pHolePor->GetLen() );
2141                     rMulti.SetPortion( pHolePor );
2142                     break;
2143                 }
2144                 pPor = pPor->GetPortion();
2145             }
2146 
2147             pTmp = new SwBidiPortion( nMultiLen + rInf.GetIdx(),
2148                                     ((SwBidiPortion&)rMulti).GetLevel() );
2149         }
2150         else
2151             pTmp = NULL;
2152 
2153         if ( ! rMulti.GetLen() && rInf.GetLast() )
2154         {
2155             SeekAndChgBefore( rInf );
2156             rInf.GetLast()->FormatEOL( rInf );
2157         }
2158 
2159         if( pNextFirst && pTmp )
2160         {
2161             pTmp->SetFollowFld();
2162             pTmp->GetRoot().SetPortion( pNextFirst );
2163         }
2164         else
2165             // A follow field portion is still waiting. If nobody wants it,
2166             // we delete it.
2167             delete pNextFirst;
2168 
2169         rInf.SetRest( pTmp );
2170     }
2171 
2172     rInf.SetTxt( *pOldTxt );
2173     rInf.SetPaintOfst( nOldPaintOfst );
2174     rInf.SetStop( aInf.IsStop() );
2175     rInf.SetNumDone( sal_True );
2176     rInf.SetFtnDone( sal_True );
2177     SeekAndChg( rInf );
2178     delete pFirstRest;
2179     delete pSecondRest;
2180     delete pFontSave;
2181     return bRet;
2182 }
2183 
2184 /*-----------------08.11.00 09:29-------------------
2185  * SwTxtFormatter::MakeRestPortion(..)
2186  * When a fieldportion at the end of line breaks and needs a following
2187  * fieldportion in the next line, then the "restportion" of the formatinfo
2188  * has to be set. Normally this happens during the formatting of the first
2189  * part of the fieldportion.
2190  * But sometimes the formatting starts at the line with the following part,
2191  * exspecally when the following part is on the next page.
2192  * In this case the MakeRestPortion-function has to create the following part.
2193  * The first parameter is the line that contains possibly a first part
2194  * of a field. When the function finds such field part, it creates the right
2195  * restportion. This may be a multiportion, e.g. if the field is surrounded by
2196  * a doubleline- or ruby-portion.
2197  * The second parameter is the start index of the line.
2198  * --------------------------------------------------*/
2199 
MakeRestPortion(const SwLineLayout * pLine,xub_StrLen nPosition)2200 SwLinePortion* SwTxtFormatter::MakeRestPortion( const SwLineLayout* pLine,
2201     xub_StrLen nPosition )
2202 {
2203     if( !nPosition )
2204         return NULL;
2205     xub_StrLen nMultiPos = nPosition - pLine->GetLen();
2206     const SwMultiPortion *pTmpMulti = NULL;
2207     const SwMultiPortion *pHelpMulti = NULL;
2208     const SwLinePortion* pPor = pLine->GetFirstPortion();
2209     SwFldPortion *pFld = NULL;
2210     while( pPor )
2211     {
2212         if( pPor->GetLen() )
2213         {
2214             if( !pHelpMulti )
2215             {
2216                 nMultiPos = nMultiPos + pPor->GetLen();
2217                 pTmpMulti = NULL;
2218             }
2219         }
2220         if( pPor->InFldGrp() )
2221         {
2222             if( !pHelpMulti )
2223                 pTmpMulti = NULL;
2224             pFld = (SwFldPortion*)pPor;
2225         }
2226         else if( pPor->IsMultiPortion() )
2227         {
2228             ASSERT( !pHelpMulti || pHelpMulti->IsBidi(),
2229                     "Nested multiportions are forbidden." );
2230 
2231             pFld = NULL;
2232             pTmpMulti = (SwMultiPortion*)pPor;
2233         }
2234         pPor = pPor->GetPortion();
2235         // If the last portion is a multi-portion, we enter it
2236         // and look for a field portion inside.
2237         // If we are already in a multiportion, we could change to the
2238         // next line
2239         if( !pPor && pTmpMulti )
2240         {
2241             if( pHelpMulti )
2242             {   // We're already inside the multiportion, let's take the second
2243                 // line, if we are in a double line portion
2244                 if( !pHelpMulti->IsRuby() )
2245                     pPor = pHelpMulti->GetRoot().GetNext();
2246                 pTmpMulti = NULL;
2247             }
2248             else
2249             {   // Now we enter a multiportion, in a ruby portion we take the
2250                 // main line, not the phonetic line, in a doublelineportion we
2251                 // starts with the first line.
2252                 pHelpMulti = pTmpMulti;
2253                 nMultiPos = nMultiPos - pHelpMulti->GetLen();
2254                 if( pHelpMulti->IsRuby() && pHelpMulti->OnTop() )
2255                     pPor = pHelpMulti->GetRoot().GetNext();
2256                 else
2257                     pPor = pHelpMulti->GetRoot().GetFirstPortion();
2258             }
2259         }
2260     }
2261     if( pFld && !pFld->HasFollow() )
2262         pFld = NULL;
2263 
2264     SwLinePortion *pRest = NULL;
2265     if( pFld )
2266     {
2267         const SwTxtAttr *pHint = GetAttr( nPosition - 1 );
2268         if ( pHint
2269              && ( pHint->Which() == RES_TXTATR_FIELD
2270                   || pHint->Which() == RES_TXTATR_ANNOTATION ) )
2271         {
2272             pRest = NewFldPortion( GetInfo(), pHint );
2273             if( pRest->InFldGrp() )
2274                 ((SwFldPortion*)pRest)->TakeNextOffset( pFld );
2275             else
2276             {
2277                 delete pRest;
2278                 pRest = NULL;
2279             }
2280         }
2281     }
2282     if( !pHelpMulti )
2283         return pRest;
2284 
2285     nPosition = nMultiPos + pHelpMulti->GetLen();
2286     SwMultiCreator* pCreate = GetInfo().GetMultiCreator( nMultiPos, 0 );
2287 
2288     if ( !pCreate )
2289     {
2290         ASSERT( !pHelpMulti->GetLen(), "Multiportion without attribut?" );
2291         if ( nMultiPos )
2292             --nMultiPos;
2293         pCreate = GetInfo().GetMultiCreator( --nMultiPos, 0 );
2294     }
2295 
2296     if( pRest || nMultiPos > nPosition || ( pHelpMulti->IsRuby() &&
2297         ((SwRubyPortion*)pHelpMulti)->GetRubyOffset() < STRING_LEN ) )
2298     {
2299         SwMultiPortion* pTmp;
2300         if( pHelpMulti->IsDouble() )
2301             pTmp = new SwDoubleLinePortion( *pCreate, nMultiPos );
2302         else if( pHelpMulti->IsBidi() )
2303             pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel );
2304         else if( pHelpMulti->IsRuby() )
2305         {
2306             sal_Bool bRubyTop;
2307             sal_Bool* pRubyPos = 0;
2308 
2309             if ( GetInfo().SnapToGrid() )
2310             {
2311                 GETGRID( pFrm->FindPageFrm() )
2312                 if ( pGrid )
2313                 {
2314                     bRubyTop = ! pGrid->GetRubyTextBelow();
2315                     pRubyPos = &bRubyTop;
2316                 }
2317             }
2318 
2319             pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(),
2320                                       *pFrm->GetTxtNode()->getIDocumentSettingAccess(),
2321                                        nMultiPos, ((SwRubyPortion*)pHelpMulti)->GetRubyOffset(),
2322                                        pRubyPos );
2323         }
2324         else if( pHelpMulti->HasRotation() )
2325             pTmp = new SwRotatedPortion( nMultiPos, pHelpMulti->GetDirection() );
2326         else
2327         {
2328             delete pCreate;
2329             return pRest;
2330         }
2331         delete pCreate;
2332         pTmp->SetFollowFld();
2333         if( pRest )
2334         {
2335             SwLineLayout *pLay = &pTmp->GetRoot();
2336             if( pTmp->IsRuby() && pTmp->OnTop() )
2337             {
2338                 pLay->SetNext( new SwLineLayout() );
2339                 pLay = pLay->GetNext();
2340             }
2341             pLay->SetPortion( pRest );
2342         }
2343         return pTmp;
2344     }
2345     return pRest;
2346 }
2347 
2348 
2349 
2350 /*-----------------23.10.00 10:47-------------------
2351  * SwTxtCursorSave notes the start and current line of a SwTxtCursor,
2352  * sets them to the values for GetCrsrOfst inside a multiportion
2353  * and restores them in the destructor.
2354  * --------------------------------------------------*/
2355 
SwTxtCursorSave(SwTxtCursor * pTxtCursor,SwMultiPortion * pMulti,SwTwips nY,sal_uInt16 & nX,xub_StrLen nCurrStart,long nSpaceAdd)2356 SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor* pTxtCursor,
2357                                   SwMultiPortion* pMulti,
2358                                   SwTwips nY,
2359                                   sal_uInt16& nX,
2360                                   xub_StrLen nCurrStart,
2361                                   long nSpaceAdd )
2362 {
2363     pTxtCrsr = pTxtCursor;
2364     nStart = pTxtCursor->nStart;
2365     pTxtCursor->nStart = nCurrStart;
2366     pCurr = pTxtCursor->pCurr;
2367     pTxtCursor->pCurr = &pMulti->GetRoot();
2368     while( pTxtCursor->Y() + pTxtCursor->GetLineHeight() < nY &&
2369         pTxtCursor->Next() )
2370         ; // nothing
2371     nWidth = pTxtCursor->pCurr->Width();
2372     nOldProp = pTxtCursor->GetPropFont();
2373 
2374     if ( pMulti->IsDouble() || pMulti->IsBidi() )
2375     {
2376         bSpaceChg = pMulti->ChgSpaceAdd( pTxtCursor->pCurr, nSpaceAdd );
2377 
2378         sal_uInt16 nSpaceCnt;
2379         if ( pMulti->IsDouble() )
2380         {
2381             pTxtCursor->SetPropFont( 50 );
2382             nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
2383         }
2384         else
2385         {
2386             const xub_StrLen nOldIdx = pTxtCursor->GetInfo().GetIdx();
2387             pTxtCursor->GetInfo().SetIdx ( nCurrStart );
2388             nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
2389             pTxtCursor->GetInfo().SetIdx ( nOldIdx );
2390         }
2391 
2392         if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
2393             pTxtCursor->pCurr->Width( static_cast<sal_uInt16>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
2394 
2395         // For a BidiPortion we have to calculate the offset from the
2396         // end of the portion
2397         if ( nX && pMulti->IsBidi() )
2398             nX = pTxtCursor->pCurr->Width() - nX;
2399     }
2400     else
2401         bSpaceChg = sal_False;
2402 }
2403 
~SwTxtCursorSave()2404 SwTxtCursorSave::~SwTxtCursorSave()
2405 {
2406     if( bSpaceChg )
2407         SwDoubleLinePortion::ResetSpaceAdd( pTxtCrsr->pCurr );
2408     pTxtCrsr->pCurr->Width( KSHORT(nWidth) );
2409     pTxtCrsr->pCurr = pCurr;
2410     pTxtCrsr->nStart = nStart;
2411     pTxtCrsr->SetPropFont( nOldProp );
2412 }
2413 
2414