1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pormulti.cxx,v $
10 * $Revision: 1.89.112.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
37 #include <com/sun/star/i18n/ScriptType.hdl>
38 #include <svx/twolinesitem.hxx>
39 #include <svx/charrotateitem.hxx>
40 #include <vcl/outdev.hxx>
42 #include <fldbas.hxx> // SwField
43 #include <txatbase.hxx>
44 #include <fmtruby.hxx> // SwFmtRuby
45 #include <txtatr.hxx> // SwTxtRuby
46 #include <charfmt.hxx>
47 #include <txtinet.hxx>
48 #include <fchrfmt.hxx>
49 #include <layfrm.hxx> // GetUpper()
50 #include <SwPortionHandler.hxx>
51 #include <pormulti.hxx> // SwMultiPortion
52 #include <inftxt.hxx> // SwTxtSizeInfo
53 #include <itrpaint.hxx> // SwTxtPainter
54 #include <viewopt.hxx> // SwViewOptions
55 #include <itrform2.hxx> // SwTxtFormatter
56 #include <porfld.hxx> // SwFldPortion
57 #include <porglue.hxx>
58 #include <breakit.hxx>
59 #include <pagefrm.hxx>
61 #include <pagedesc.hxx> // SwPageDesc
62 #include <tgrditem.hxx>
63 #include <swtable.hxx>
64 #include <fmtfsize.hxx>
66 using namespace ::com::sun::star
;
67 extern sal_Bool
IsUnderlineBreak( const SwLinePortion
& rPor
, const SwFont
& rFnt
);
69 /*-----------------10.10.00 15:23-------------------
70 * class SwMultiPortion
72 * A SwMultiPortion is not a simple portion,
73 * it's a container, which contains almost a SwLineLayoutPortion.
74 * This SwLineLayout could be followed by other textportions via pPortion
75 * and by another SwLineLayout via pNext to realize a doubleline portion.
76 * --------------------------------------------------*/
78 SwMultiPortion::~SwMultiPortion()
83 void SwMultiPortion::Paint( const SwTxtPaintInfo
& ) const
86 "Don't try SwMultiPortion::Paint, try SwTxtPainter::PaintMultiPortion" );
89 /*-----------------13.10.00 16:21-------------------
90 * Summarize the internal lines to calculate the (external) size.
91 * The internal line has to calculate first.
92 * --------------------------------------------------*/
94 void SwMultiPortion::CalcSize( SwTxtFormatter
& rLine
, SwTxtFormatInfo
&rInf
)
99 SetFlyInCntnt( sal_False
);
100 SwLineLayout
*pLay
= &GetRoot();
103 pLay
->CalcLine( rLine
, rInf
);
104 if( rLine
.IsFlyInCntBase() )
105 SetFlyInCntnt( sal_True
);
106 if( IsRuby() && ( OnTop() == ( pLay
== &GetRoot() ) ) )
108 // An empty phonetic line don't need an ascent or a height.
111 pLay
->SetAscent( 0 );
115 SetAscent( GetAscent() + pLay
->Height() );
118 SetAscent( GetAscent() + pLay
->GetAscent() );
119 Height( Height() + pLay
->Height() );
120 if( Width() < pLay
->Width() )
121 Width( pLay
->Width() );
122 pLay
= pLay
->GetNext();
126 KSHORT nTmp
= ((SwDoubleLinePortion
*)this)->GetBrackets()->nHeight
;
127 if( nTmp
> Height() )
129 KSHORT nAdd
= ( nTmp
- Height() ) / 2;
130 GetRoot().SetAscent( GetRoot().GetAscent() + nAdd
);
131 GetRoot().Height( GetRoot().Height() + nAdd
);
134 nTmp
= ((SwDoubleLinePortion
*)this)->GetBrackets()->nAscent
;
135 if( nTmp
> GetAscent() )
140 long SwMultiPortion::CalcSpacing( long , const SwTxtSizeInfo
& ) const
145 sal_Bool
SwMultiPortion::ChgSpaceAdd( SwLineLayout
*, long ) const
150 /*************************************************************************
151 * virtual SwMultiPortion::HandlePortion()
152 *************************************************************************/
154 void SwMultiPortion::HandlePortion( SwPortionHandler
& rPH
) const
156 rPH
.Text( GetLen(), GetWhichPor() );
159 /*-----------------01.11.00 14:21-------------------
160 * SwMultiPortion::ActualizeTabulator()
161 * sets the tabulator-flag, if there's any tabulator-portion inside.
162 * --------------------------------------------------*/
164 void SwMultiPortion::ActualizeTabulator()
166 SwLinePortion
* pPor
= GetRoot().GetFirstPortion();
168 for( bTab1
= bTab2
= sal_False
; pPor
; pPor
= pPor
->GetPortion() )
169 if( pPor
->InTabGrp() )
171 if( GetRoot().GetNext() )
174 pPor
= GetRoot().GetNext()->GetFirstPortion();
177 if( pPor
->InTabGrp() )
179 pPor
= pPor
->GetPortion();
184 /*-----------------16.02.01 12:07-------------------
185 * SwRotatedPortion::SwRotatedPortion(..)
186 * --------------------------------------------------*/
188 SwRotatedPortion::SwRotatedPortion( const SwMultiCreator
& rCreate
,
189 xub_StrLen nEnd
, sal_Bool bRTL
) : SwMultiPortion( nEnd
)
191 const SvxCharRotateItem
* pRot
= (SvxCharRotateItem
*)rCreate
.pItem
;
194 const SwTxtAttr
& rAttr
= *rCreate
.pAttr
;
195 const SfxPoolItem
*const pItem
=
196 CharFmt::GetItem(rAttr
, RES_CHRATR_ROTATE
);
199 pRot
= static_cast<const SvxCharRotateItem
*>(pItem
);
206 nDir
= pRot
->IsBottomToTop() ? 3 : 1;
208 nDir
= pRot
->IsBottomToTop() ? 1 : 3;
210 SetDirection( nDir
);
214 /*---------------------------------------------------
215 * SwBidiPortion::SwBidiPortion(..)
216 * --------------------------------------------------*/
218 SwBidiPortion::SwBidiPortion( xub_StrLen nEnd
, BYTE nLv
)
219 : SwMultiPortion( nEnd
), nLevel( nLv
)
224 SetDirection( DIR_RIGHT2LEFT
);
226 SetDirection( DIR_LEFT2RIGHT
);
230 long SwBidiPortion::CalcSpacing( long nSpaceAdd
, const SwTxtSizeInfo
& rInf
) const
232 return HasTabulator() ? 0 : GetSpaceCnt(rInf
) * nSpaceAdd
/ SPACING_PRECISION_FACTOR
;
235 sal_Bool
SwBidiPortion::ChgSpaceAdd( SwLineLayout
* pCurr
, long nSpaceAdd
) const
237 sal_Bool bRet
= sal_False
;
238 if( !HasTabulator() && nSpaceAdd
> 0 && !pCurr
->IsSpaceAdd() )
240 pCurr
->CreateSpaceAdd();
241 pCurr
->SetLLSpaceAdd( nSpaceAdd
, 0 );
248 xub_StrLen
SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo
&rInf
) const
250 // Calculate number of blanks for justified alignment
251 SwLinePortion
* pPor
= GetRoot().GetFirstPortion();
252 xub_StrLen nTmpStart
= rInf
.GetIdx();
253 xub_StrLen nNull
= 0;
256 for( nBlanks
= 0; pPor
; pPor
= pPor
->GetPortion() )
258 if( pPor
->InTxtGrp() )
259 nBlanks
= nBlanks
+ ((SwTxtPortion
*)pPor
)->GetSpaceCnt( rInf
, nNull
);
260 else if ( pPor
->IsMultiPortion() &&
261 ((SwMultiPortion
*)pPor
)->IsBidi() )
262 nBlanks
= nBlanks
+ ((SwBidiPortion
*)pPor
)->GetSpaceCnt( rInf
);
264 ((SwTxtSizeInfo
&)rInf
).SetIdx( rInf
.GetIdx() + pPor
->GetLen() );
266 ((SwTxtSizeInfo
&)rInf
).SetIdx( nTmpStart
);
270 /*-----------------01.11.00 14:22-------------------
271 * SwDoubleLinePortion::SwDoubleLinePortion(..)
272 * This constructor is for the continuation of a doubleline portion
274 * It takes the same brackets and if the original has no content except
275 * brackets, these will be deleted.
276 * --------------------------------------------------*/
278 SwDoubleLinePortion::SwDoubleLinePortion( SwDoubleLinePortion
& rDouble
,
280 SwMultiPortion( nEnd
),
283 SetDirection( rDouble
.GetDirection() );
285 if( rDouble
.GetBrackets() )
287 SetBrackets( rDouble
);
288 // An empty multiportion needs no brackets.
289 // Notice: GetLen() might be zero, if the multiportion contains
290 // the second part of a field and the width might be zero, if
291 // it contains a note only. In this cases the brackets are okay.
292 // But if the length and the width are both zero, the portion
294 if( rDouble
.Width() == rDouble
.BracketWidth() )
295 rDouble
.ClearBrackets();
299 /*-----------------01.11.00 14:22-------------------
300 * SwDoubleLinePortion::SwDoubleLinePortion(..)
301 * This constructor uses the textattribut to get the right brackets.
302 * The textattribut could be a 2-line-attribute or a character- or
303 * internetstyle, which contains the 2-line-attribute.
304 * --------------------------------------------------*/
306 SwDoubleLinePortion::SwDoubleLinePortion( const SwMultiCreator
& rCreate
,
307 xub_StrLen nEnd
) : SwMultiPortion( nEnd
), pBracket( new SwBracket() )
310 const SvxTwoLinesItem
* pTwo
= (SvxTwoLinesItem
*)rCreate
.pItem
;
312 pBracket
->nStart
= 0;
315 const SwTxtAttr
& rAttr
= *rCreate
.pAttr
;
316 pBracket
->nStart
= *rAttr
.GetStart();
318 const SfxPoolItem
* const pItem
=
319 CharFmt::GetItem( rAttr
, RES_CHRATR_TWO_LINES
);
322 pTwo
= static_cast<const SvxTwoLinesItem
*>(pItem
);
327 pBracket
->cPre
= pTwo
->GetStartBracket();
328 pBracket
->cPost
= pTwo
->GetEndBracket();
335 BYTE nTmp
= SW_SCRIPTS
;
336 if( pBracket
->cPre
> 255 )
338 String
aTxt( pBracket
->cPre
);
339 nTmp
= SwScriptInfo::WhichFont( 0, &aTxt
, 0 );
341 pBracket
->nPreScript
= nTmp
;
343 if( pBracket
->cPost
> 255 )
345 String
aTxt( pBracket
->cPost
);
346 nTmp
= SwScriptInfo::WhichFont( 0, &aTxt
, 0 );
348 pBracket
->nPostScript
= nTmp
;
350 if( !pBracket
->cPre
&& !pBracket
->cPost
)
356 // double line portions have the same direction as the frame directions
357 if ( rCreate
.nLevel
% 2 )
358 SetDirection( DIR_RIGHT2LEFT
);
360 SetDirection( DIR_LEFT2RIGHT
);
364 /*-----------------25.10.00 09:51-------------------
365 * SwMultiPortion::PaintBracket paints the wished bracket,
366 * if the multiportion has surrounding brackets.
367 * The X-position of the SwTxtPaintInfo will be modified:
368 * the open bracket sets position behind itself,
369 * the close bracket in front of itself.
370 * --------------------------------------------------*/
372 void SwDoubleLinePortion::PaintBracket( SwTxtPaintInfo
&rInf
,
374 sal_Bool bOpen
) const
376 sal_Unicode cCh
= bOpen
? pBracket
->cPre
: pBracket
->cPost
;
379 KSHORT nChWidth
= bOpen
? PreWidth() : PostWidth();
383 rInf
.X( rInf
.X() + Width() - PostWidth() +
384 ( nSpaceAdd
> 0 ? CalcSpacing( nSpaceAdd
, rInf
) : 0 ) );
386 SwBlankPortion
aBlank( cCh
, sal_True
);
387 aBlank
.SetAscent( pBracket
->nAscent
);
388 aBlank
.Width( nChWidth
);
389 aBlank
.Height( pBracket
->nHeight
);
391 SwFont
* pTmpFnt
= new SwFont( *rInf
.GetFont() );
392 BYTE nAct
= bOpen
? pBracket
->nPreScript
: pBracket
->nPostScript
;
393 if( SW_SCRIPTS
> nAct
)
394 pTmpFnt
->SetActual( nAct
);
395 pTmpFnt
->SetProportion( 100 );
396 SwFontSave
aSave( rInf
, pTmpFnt
);
397 aBlank
.Paint( rInf
);
401 rInf
.X( rInf
.X() + PreWidth() );
404 /*-----------------25.10.00 16:26-------------------
405 * SwDoubleLinePortion::SetBrackets creates the bracket-structur
406 * and fills it, if not both characters are 0x00.
407 * --------------------------------------------------*/
409 void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion
& rDouble
)
411 if( rDouble
.pBracket
)
413 pBracket
= new SwBracket
;
414 pBracket
->cPre
= rDouble
.pBracket
->cPre
;
415 pBracket
->cPost
= rDouble
.pBracket
->cPost
;
416 pBracket
->nPreScript
= rDouble
.pBracket
->nPreScript
;
417 pBracket
->nPostScript
= rDouble
.pBracket
->nPostScript
;
418 pBracket
->nStart
= rDouble
.pBracket
->nStart
;
422 /*-----------------25.10.00 16:29-------------------
423 * SwDoubleLinePortion::FormatBrackets
424 * calculates the size of the brackets => pBracket,
425 * reduces the nMaxWidth-parameter ( minus bracket-width )
426 * and moves the rInf-x-position behind the opening bracket.
427 * --------------------------------------------------*/
429 void SwDoubleLinePortion::FormatBrackets( SwTxtFormatInfo
&rInf
, SwTwips
& nMaxWidth
)
431 nMaxWidth
-= rInf
.X();
432 SwFont
* pTmpFnt
= new SwFont( *rInf
.GetFont() );
433 pTmpFnt
->SetProportion( 100 );
434 pBracket
->nAscent
= 0;
435 pBracket
->nHeight
= 0;
438 String
aStr( pBracket
->cPre
);
439 BYTE nActualScr
= pTmpFnt
->GetActual();
440 if( SW_SCRIPTS
> pBracket
->nPreScript
)
441 pTmpFnt
->SetActual( pBracket
->nPreScript
);
442 SwFontSave
aSave( rInf
, pTmpFnt
);
443 SwPosSize aSize
= rInf
.GetTxtSize( aStr
);
444 pBracket
->nAscent
= rInf
.GetAscent();
445 pBracket
->nHeight
= aSize
.Height();
446 pTmpFnt
->SetActual( nActualScr
);
447 if( nMaxWidth
> aSize
.Width() )
449 pBracket
->nPreWidth
= aSize
.Width();
450 nMaxWidth
-= aSize
.Width();
451 rInf
.X( rInf
.X() + aSize
.Width() );
455 pBracket
->nPreWidth
= 0;
460 pBracket
->nPreWidth
= 0;
461 if( pBracket
->cPost
)
463 String
aStr( pBracket
->cPost
);
464 if( SW_SCRIPTS
> pBracket
->nPostScript
)
465 pTmpFnt
->SetActual( pBracket
->nPostScript
);
466 SwFontSave
aSave( rInf
, pTmpFnt
);
467 SwPosSize aSize
= rInf
.GetTxtSize( aStr
);
468 KSHORT nTmpAsc
= rInf
.GetAscent();
469 if( nTmpAsc
> pBracket
->nAscent
)
471 pBracket
->nHeight
+= nTmpAsc
- pBracket
->nAscent
;
472 pBracket
->nAscent
= nTmpAsc
;
474 if( aSize
.Height() > pBracket
->nHeight
)
475 pBracket
->nHeight
= aSize
.Height();
476 if( nMaxWidth
> aSize
.Width() )
478 pBracket
->nPostWidth
= aSize
.Width();
479 nMaxWidth
-= aSize
.Width();
483 pBracket
->nPostWidth
= 0;
488 pBracket
->nPostWidth
= 0;
489 nMaxWidth
+= rInf
.X();
492 /*-----------------26.10.00 10:36-------------------
493 * SwDoubleLinePortion::CalcBlanks
494 * calculates the number of blanks in each line and
495 * the difference of the width of the two lines.
496 * These results are used from the text adjustment.
497 * --------------------------------------------------*/
499 void SwDoubleLinePortion::CalcBlanks( SwTxtFormatInfo
&rInf
)
501 SwLinePortion
* pPor
= GetRoot().GetFirstPortion();
502 xub_StrLen nNull
= 0;
503 xub_StrLen nStart
= rInf
.GetIdx();
504 SetTab1( sal_False
);
505 SetTab2( sal_False
);
506 for( nBlank1
= 0; pPor
; pPor
= pPor
->GetPortion() )
508 if( pPor
->InTxtGrp() )
509 nBlank1
= nBlank1
+ ((SwTxtPortion
*)pPor
)->GetSpaceCnt( rInf
, nNull
);
510 rInf
.SetIdx( rInf
.GetIdx() + pPor
->GetLen() );
511 if( pPor
->InTabGrp() )
514 nLineDiff
= GetRoot().Width();
515 if( GetRoot().GetNext() )
517 pPor
= GetRoot().GetNext()->GetFirstPortion();
518 nLineDiff
-= GetRoot().GetNext()->Width();
520 for( nBlank2
= 0; pPor
; pPor
= pPor
->GetPortion() )
522 if( pPor
->InTxtGrp() )
523 nBlank2
= nBlank2
+ ((SwTxtPortion
*)pPor
)->GetSpaceCnt( rInf
, nNull
);
524 rInf
.SetIdx( rInf
.GetIdx() + pPor
->GetLen() );
525 if( pPor
->InTabGrp() )
528 rInf
.SetIdx( nStart
);
531 long SwDoubleLinePortion::CalcSpacing( long nSpaceAdd
, const SwTxtSizeInfo
& ) const
533 return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd
/ SPACING_PRECISION_FACTOR
;
536 /*-----------------01.11.00 14:29-------------------
537 * SwDoubleLinePortion::ChangeSpaceAdd(..)
538 * merges the spaces for text adjustment from the inner and outer part.
539 * Inside the doubleline portion the wider line has no spaceadd-array, the
540 * smaller line has such an array to reach width of the wider line.
541 * If the surrounding line has text adjustment and the doubleline portion
542 * contains no tabulator, it is necessary to create/manipulate the inner
544 * --------------------------------------------------*/
546 sal_Bool
SwDoubleLinePortion::ChgSpaceAdd( SwLineLayout
* pCurr
,
547 long nSpaceAdd
) const
549 sal_Bool bRet
= sal_False
;
550 if( !HasTabulator() && nSpaceAdd
> 0 )
552 if( !pCurr
->IsSpaceAdd() )
554 // The wider line gets the spaceadd from the surrounding line direct
555 pCurr
->CreateSpaceAdd();
556 pCurr
->SetLLSpaceAdd( nSpaceAdd
, 0 );
561 xub_StrLen nMyBlank
= GetSmallerSpaceCnt();
562 xub_StrLen nOther
= GetSpaceCnt();
563 SwTwips nMultiSpace
= pCurr
->GetLLSpaceAdd( 0 ) * nMyBlank
+ nOther
* nSpaceAdd
;
566 nMultiSpace
/= nMyBlank
;
568 if( nMultiSpace
< KSHRT_MAX
* SPACING_PRECISION_FACTOR
)
570 // pCurr->SetLLSpaceAdd( nMultiSpace, 0 );
571 // --> FME 2006-07-11 #i65711# SetLLSpaceAdd replaces the first value,
572 // instead we want to insert a new first value:
573 std::vector
<long>* pVec
= pCurr
->GetpLLSpaceAdd();
574 pVec
->insert( pVec
->begin(), nMultiSpace
);
582 /*-----------------01.11.00 14:29-------------------
583 * SwDoubleLinePortion::ResetSpaceAdd(..)
584 * cancels the manipulation from SwDoubleLinePortion::ChangeSpaceAdd(..)
585 * --------------------------------------------------*/
587 void SwDoubleLinePortion::ResetSpaceAdd( SwLineLayout
* pCurr
)
589 pCurr
->RemoveFirstLLSpaceAdd();;
590 if( !pCurr
->GetLLSpaceAddCount() )
591 pCurr
->FinishSpaceAdd();
594 SwDoubleLinePortion::~SwDoubleLinePortion()
599 /*-----------------13.11.00 14:50-------------------
600 * SwRubyPortion::SwRubyPortion(..)
601 * constructs a ruby portion, i.e. an additional text is displayed
602 * beside the main text, e.g. phonetic characters.
603 * --------------------------------------------------*/
606 SwRubyPortion::SwRubyPortion( const SwRubyPortion
& rRuby
, xub_StrLen nEnd
) :
607 SwMultiPortion( nEnd
),
608 nRubyOffset( rRuby
.GetRubyOffset() ),
609 nAdjustment( rRuby
.GetAdjustment() )
611 SetDirection( rRuby
.GetDirection() ),
612 SetTop( rRuby
.OnTop() );
616 /*-----------------13.11.00 14:50-------------------
617 * SwRubyPortion::SwRubyPortion(..)
618 * constructs a ruby portion, i.e. an additional text is displayed
619 * beside the main text, e.g. phonetic characters.
620 * --------------------------------------------------*/
622 SwRubyPortion::SwRubyPortion( const SwMultiCreator
& rCreate
, const SwFont
& rFnt
,
623 const IDocumentSettingAccess
& rIDocumentSettingAccess
,
624 xub_StrLen nEnd
, xub_StrLen nOffs
,
625 const sal_Bool
* pForceRubyPos
)
626 : SwMultiPortion( nEnd
)
629 ASSERT( SW_MC_RUBY
== rCreate
.nId
, "Ruby expected" );
630 ASSERT( RES_TXTATR_CJK_RUBY
== rCreate
.pAttr
->Which(), "Wrong attribute" );
631 const SwFmtRuby
& rRuby
= rCreate
.pAttr
->GetRuby();
632 nAdjustment
= rRuby
.GetAdjustment();
635 // in grid mode we force the ruby text to the upper or lower line
637 SetTop( *pForceRubyPos
);
639 SetTop( ! rRuby
.GetPosition() );
641 const SwCharFmt
* pFmt
= ((SwTxtRuby
*)rCreate
.pAttr
)->GetCharFmt();
645 const SwAttrSet
& rSet
= pFmt
->GetAttrSet();
646 pRubyFont
= new SwFont( rFnt
);
647 pRubyFont
->SetDiffFnt( &rSet
, &rIDocumentSettingAccess
);
649 // we do not allow a vertical font for the ruby text
650 pRubyFont
->SetVertical( rFnt
.GetOrientation() );
655 String
aStr( rRuby
.GetText(), nOffs
, STRING_LEN
);
656 SwFldPortion
*pFld
= new SwFldPortion( aStr
, pRubyFont
);
657 pFld
->SetNextOffset( nOffs
);
658 pFld
->SetFollow( sal_True
);
661 GetRoot().SetPortion( pFld
);
664 GetRoot().SetNext( new SwLineLayout() );
665 GetRoot().GetNext()->SetPortion( pFld
);
668 // ruby portions have the same direction as the frame directions
669 if ( rCreate
.nLevel
% 2 )
671 // switch right and left ruby adjustment in rtl environment
672 if ( 0 == nAdjustment
)
674 else if ( 2 == nAdjustment
)
677 SetDirection( DIR_RIGHT2LEFT
);
680 SetDirection( DIR_LEFT2RIGHT
);
683 /*-----------------13.11.00 14:56-------------------
684 * SwRubyPortion::_Adjust(..)
685 * In ruby portion there are different alignments for
686 * the ruby text and the main text.
687 * Left, right, centered and two possibilities of block adjustment
688 * The block adjustment is realized by spacing between the characteres,
689 * either with a half space or no space in front of the first letter and
690 * a half space at the end of the last letter.
691 * Notice: the smaller line will be manipulated, normally it's the ruby line,
692 * but it could be the main text, too.
693 * If there is a tabulator in smaller line, no adjustment is possible.
694 * --------------------------------------------------*/
696 void SwRubyPortion::_Adjust( SwTxtFormatInfo
&rInf
)
698 SwTwips nLineDiff
= GetRoot().Width() - GetRoot().GetNext()->Width();
699 xub_StrLen nOldIdx
= rInf
.GetIdx();
704 { // The first line has to be adjusted.
708 nLineDiff
= -nLineDiff
;
711 { // The second line has to be adjusted.
714 pCurr
= GetRoot().GetNext();
715 rInf
.SetIdx( nOldIdx
+ GetRoot().GetLen() );
717 KSHORT nLeft
= 0; // the space in front of the first letter
718 KSHORT nRight
= 0; // the space at the end of the last letter
720 switch ( nAdjustment
)
722 case 1: nRight
= static_cast<USHORT
>(nLineDiff
/ 2); // no break
723 case 2: nLeft
= static_cast<USHORT
>(nLineDiff
- nRight
); break;
724 case 3: nSub
= 1; // no break
727 xub_StrLen nCharCnt
= 0;
729 for( pPor
= pCurr
->GetFirstPortion(); pPor
; pPor
= pPor
->GetPortion() )
731 if( pPor
->InTxtGrp() )
732 ((SwTxtPortion
*)pPor
)->GetSpaceCnt( rInf
, nCharCnt
);
733 rInf
.SetIdx( rInf
.GetIdx() + pPor
->GetLen() );
735 if( nCharCnt
> nSub
)
737 SwTwips nCalc
= nLineDiff
/ ( nCharCnt
- nSub
);
739 if( nCalc
< SHRT_MAX
)
740 nTmp
= -short(nCalc
);
744 pCurr
->CreateSpaceAdd( SPACING_PRECISION_FACTOR
* nTmp
);
745 nLineDiff
-= nCalc
* ( nCharCnt
- 1 );
749 nRight
= static_cast<USHORT
>(nLineDiff
/ 2);
750 nLeft
= static_cast<USHORT
>(nLineDiff
- nRight
);
754 default: ASSERT( sal_False
, "New ruby adjustment" );
756 if( nLeft
|| nRight
)
758 if( !pCurr
->GetPortion() )
759 pCurr
->SetPortion( new SwTxtPortion( *pCurr
) );
760 SwMarginPortion
*pMarg
= new SwMarginPortion( 0 );
763 pMarg
->AddPrtWidth( nLeft
);
764 pMarg
->SetPortion( pCurr
->GetPortion() );
765 pCurr
->SetPortion( pMarg
);
769 pMarg
= new SwMarginPortion( 0 );
770 pMarg
->AddPrtWidth( nRight
);
771 pCurr
->FindLastPortion()->Append( pMarg
);
775 pCurr
->Width( Width() );
776 rInf
.SetIdx( nOldIdx
);
779 /*-----------------08.11.00 14:14-------------------
781 * has to change the nRubyOffset, if there's a fieldportion
782 * in the phonetic line.
783 * The nRubyOffset is the position in the rubystring, where the
784 * next SwRubyPortion has start the displaying of the phonetics.
785 * --------------------------------------------------*/
787 void SwRubyPortion::CalcRubyOffset()
789 const SwLineLayout
*pCurr
= &GetRoot();
792 pCurr
= pCurr
->GetNext();
796 const SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
797 const SwFldPortion
*pFld
= NULL
;
800 if( pPor
->InFldGrp() )
801 pFld
= (SwFldPortion
*)pPor
;
802 pPor
= pPor
->GetPortion();
806 if( pFld
->HasFollow() )
807 nRubyOffset
= pFld
->GetNextOffset();
809 nRubyOffset
= STRING_LEN
;
813 /*-----------------13.10.00 16:22-------------------
814 * SwTxtSizeInfo::GetMultiCreator(..)
815 * If we (e.g. the position rPos) are inside a two-line-attribute or
816 * a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
817 * otherwise the function returns zero.
818 * The rPos parameter is set to the end of the multiportion,
819 * normally this is the end of the attribute,
820 * but sometimes it is the start of another attribute, which finished or
821 * interrupts the first attribute.
822 * E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute
823 * with different brackets interrupts another 2-line-attribute.
824 * --------------------------------------------------*/
826 /*-----------------13.11.00 15:38-------------------
828 * is a little help function for GetMultiCreator(..)
829 * It extracts the 2-line-format from a 2-line-attribute or a character style.
830 * The rValue is set to TRUE, if the 2-line-attribute's value is set and
831 * no 2-line-format reference is passed. If there is a 2-line-format reference,
832 * then the rValue is set only, if the 2-line-attribute's value is set _and_
833 * the 2-line-formats has the same brackets.
834 * --------------------------------------------------*/
836 sal_Bool
lcl_Has2Lines( const SwTxtAttr
& rAttr
, const SvxTwoLinesItem
* &rpRef
,
839 const SfxPoolItem
* pItem
= CharFmt::GetItem( rAttr
, RES_CHRATR_TWO_LINES
);
842 rValue
= ((SvxTwoLinesItem
*)pItem
)->GetValue();
844 rpRef
= (SvxTwoLinesItem
*)pItem
;
845 else if( ((SvxTwoLinesItem
*)pItem
)->GetEndBracket() !=
846 rpRef
->GetEndBracket() ||
847 ((SvxTwoLinesItem
*)pItem
)->GetStartBracket() !=
848 rpRef
->GetStartBracket() )
855 /*-----------------16.02.01 16:39-------------------
856 * lcl_HasRotation(..)
857 * is a little help function for GetMultiCreator(..)
858 * It extracts the charrotation from a charrotate-attribute or a character style.
859 * The rValue is set to TRUE, if the charrotate-attribute's value is set and
860 * no charrotate-format reference is passed.
861 * If there is a charrotate-format reference, then the rValue is set only,
862 * if the charrotate-attribute's value is set _and_ identical
863 * to the charrotate-format's value.
864 * --------------------------------------------------*/
866 sal_Bool
lcl_HasRotation( const SwTxtAttr
& rAttr
,
867 const SvxCharRotateItem
* &rpRef
, sal_Bool
&rValue
)
869 const SfxPoolItem
* pItem
= CharFmt::GetItem( rAttr
, RES_CHRATR_ROTATE
);
872 rValue
= 0 != ((SvxCharRotateItem
*)pItem
)->GetValue();
874 rpRef
= (SvxCharRotateItem
*)pItem
;
875 else if( ((SvxCharRotateItem
*)pItem
)->GetValue() !=
884 SwMultiCreator
* SwTxtSizeInfo::GetMultiCreator( xub_StrLen
&rPos
,
885 SwMultiPortion
* pMulti
) const
887 SwScriptInfo
& rSI
= ((SwParaPortion
*)GetParaPortion())->GetScriptInfo();
889 // get the last embedding level
893 ASSERT( pMulti
->IsBidi(), "Nested MultiPortion is not BidiPortion" )
894 // level associated with bidi-portion;
895 nCurrLevel
= ((SwBidiPortion
*)pMulti
)->GetLevel();
898 // no nested bidi portion required
899 nCurrLevel
= GetTxtFrm()->IsRightToLeft() ? 1 : 0;
901 // check if there is a field at rPos:
902 BYTE nNextLevel
= nCurrLevel
;
903 sal_Bool bFldBidi
= sal_False
;
905 if ( CH_TXTATR_BREAKWORD
== GetChar( rPos
) )
909 // examining the script of the field text should be sufficient
910 // for 99% of all cases
911 XubString aTxt = GetTxtFrm()->GetTxtNode()->GetExpandTxt( rPos, 1 );
913 if ( pBreakIt->GetBreakIter().is() && aTxt.Len() )
915 sal_Bool bFldDir = ( i18n::ScriptType::COMPLEX ==
916 pBreakIt->GetRealScriptOfText( aTxt, 0 ) );
917 sal_Bool bCurrDir = ( 0 != ( nCurrLevel % 2 ) );
918 if ( bFldDir != bCurrDir )
920 nNextLevel = nCurrLevel + 1;
926 nNextLevel
= rSI
.DirType( rPos
);
928 if ( GetTxt().Len() != rPos
&& nNextLevel
> nCurrLevel
)
930 rPos
= bFldBidi
? rPos
+ 1 : rSI
.NextDirChg( rPos
, &nCurrLevel
);
931 if ( STRING_LEN
== rPos
)
933 SwMultiCreator
*pRet
= new SwMultiCreator
;
936 pRet
->nId
= SW_MC_BIDI
;
937 pRet
->nLevel
= nCurrLevel
+ 1;
941 // a bidi portion can only contain other bidi portions
945 const SvxCharRotateItem
* pRotate
= NULL
;
946 const SfxPoolItem
* pRotItem
;
947 if( SFX_ITEM_SET
== pFrm
->GetTxtNode()->GetSwAttrSet().
948 GetItemState( RES_CHRATR_ROTATE
, TRUE
, &pRotItem
) &&
949 ((SvxCharRotateItem
*)pRotItem
)->GetValue() )
950 pRotate
= (SvxCharRotateItem
*)pRotItem
;
953 const SvxTwoLinesItem
* p2Lines
= NULL
;
954 const SfxPoolItem
* pItem
;
955 if( SFX_ITEM_SET
== pFrm
->GetTxtNode()->GetSwAttrSet().
956 GetItemState( RES_CHRATR_TWO_LINES
, TRUE
, &pItem
) &&
957 ((SvxTwoLinesItem
*)pItem
)->GetValue() )
958 p2Lines
= (SvxTwoLinesItem
*)pItem
;
962 const SwpHints
*pHints
= pFrm
->GetTxtNode()->GetpSwpHints();
963 if( !pHints
&& !p2Lines
&& !pRotate
)
965 const SwTxtAttr
*pRuby
= NULL
;
966 sal_Bool bTwo
= sal_False
;
967 sal_Bool bRot
= sal_False
;
968 USHORT n2Lines
= USHRT_MAX
;
969 USHORT nRotate
= USHRT_MAX
;
970 USHORT nCount
= pHints
? pHints
->Count() : 0;
972 for( i
= 0; i
< nCount
; ++i
)
974 const SwTxtAttr
*pTmp
= (*pHints
)[i
];
975 xub_StrLen nStart
= *pTmp
->GetStart();
978 if( *pTmp
->GetAnyEnd() > rPos
)
980 if( RES_TXTATR_CJK_RUBY
== pTmp
->Which() )
984 const SvxCharRotateItem
* pRoTmp
= NULL
;
985 if( lcl_HasRotation( *pTmp
, pRoTmp
, bRot
) )
987 nRotate
= bRot
? i
: nCount
;
990 const SvxTwoLinesItem
* p2Tmp
= NULL
;
991 if( lcl_Has2Lines( *pTmp
, p2Tmp
, bTwo
) )
993 n2Lines
= bTwo
? i
: nCount
;
1000 { // The winner is ... a ruby attribute and so
1001 // the end of the multiportion is the end of the ruby attribute.
1002 rPos
= *pRuby
->GetEnd();
1003 SwMultiCreator
*pRet
= new SwMultiCreator
;
1005 pRet
->pAttr
= pRuby
;
1006 pRet
->nId
= SW_MC_RUBY
;
1007 pRet
->nLevel
= GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1010 if( n2Lines
< nCount
|| ( pItem
&& pItem
== p2Lines
&&
1011 rPos
< GetTxt().Len() ) )
1012 { // The winner is a 2-line-attribute,
1013 // the end of the multiportion depends on the following attributes...
1014 SwMultiCreator
*pRet
= new SwMultiCreator
;
1016 // We note the endpositions of the 2-line attributes in aEnd as stack
1019 // The bOn flag signs the state of the last 2-line attribute in the
1020 // aEnd-stack, it is compatible with the winner-attribute or
1021 // it interrupts the other attribute.
1022 sal_Bool bOn
= sal_True
;
1024 if( n2Lines
< nCount
)
1027 pRet
->pAttr
= (*pHints
)[n2Lines
];
1028 aEnd
.Insert( *pRet
->pAttr
->GetEnd(), 0 );
1031 aEnd
[ 0 ] = GetTxt().Len();
1032 bOn
= ((SvxTwoLinesItem
*)pItem
)->GetEndBracket() ==
1033 p2Lines
->GetEndBracket() &&
1034 ((SvxTwoLinesItem
*)pItem
)->GetStartBracket() ==
1035 p2Lines
->GetStartBracket();
1040 pRet
->pItem
= pItem
;
1042 aEnd
.Insert( GetTxt().Len(), 0 );
1044 pRet
->nId
= SW_MC_DOUBLE
;
1045 pRet
->nLevel
= GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1047 // n2Lines is the index of the last 2-line-attribute, which contains
1048 // the actual position.
1050 // At this moment we know that at position rPos the "winner"-attribute
1051 // causes a 2-line-portion. The end of the attribute is the end of the
1052 // portion, if there's no interrupting attribute.
1053 // There are two kinds of interruptors:
1054 // - ruby attributes stops the 2-line-attribute, the end of the
1055 // multiline is the start of the ruby attribute
1056 // - 2-line-attributes with value "Off" or with different brackets,
1057 // these attributes may interrupt the winner, but they could be
1058 // neutralized by another 2-line-attribute starting at the same
1059 // position with the same brackets as the winner-attribute.
1061 // In the following loop rPos is the critical position and it will be
1062 // evaluated, if at rPos starts a interrupting or a maintaining
1063 // continuity attribute.
1066 const SwTxtAttr
*pTmp
= (*pHints
)[i
++];
1067 if( *pTmp
->GetAnyEnd() <= rPos
)
1069 if( rPos
< *pTmp
->GetStart() )
1071 // If bOn is FALSE and the next attribute starts later than rPos
1072 // the winner attribute is interrupted at rPos.
1073 // If the start of the next atribute is behind the end of
1074 // the last attribute on the aEnd-stack, this is the endposition
1075 // on the stack is the end of the 2-line portion.
1076 if( !bOn
|| aEnd
[ aEnd
.Count()-1 ] < *pTmp
->GetStart() )
1078 // At this moment, bOn is TRUE and the next attribute starts
1079 // behind rPos, so we could move rPos to the next startpoint
1080 rPos
= *pTmp
->GetStart();
1081 // We clean up the aEnd-stack, endpositions equal to rPos are
1083 while( aEnd
.Count() && aEnd
[ aEnd
.Count()-1 ] <= rPos
)
1086 aEnd
.Remove( aEnd
.Count()-1, 1 );
1088 // If the endstack is empty, we simulate an attribute with
1089 // state TRUE and endposition rPos
1092 aEnd
.Insert( rPos
, 0 );
1096 // A ruby attribute stops the 2-line immediately
1097 if( RES_TXTATR_CJK_RUBY
== pTmp
->Which() )
1099 if( lcl_Has2Lines( *pTmp
, p2Lines
, bTwo
) )
1100 { // We have an interesting attribute..
1102 { // .. with the same state, so the last attribute could
1104 if( aEnd
[ aEnd
.Count()-1 ] < *pTmp
->GetEnd() )
1105 aEnd
[ aEnd
.Count()-1 ] = *pTmp
->GetEnd();
1108 { // .. with a different state.
1110 // If this is smaller than the last on the stack, we put
1111 // it on the stack. If it has the same endposition, the last
1112 // could be removed.
1113 if( aEnd
[ aEnd
.Count()-1 ] > *pTmp
->GetEnd() )
1114 aEnd
.Insert( *pTmp
->GetEnd(), aEnd
.Count() );
1115 else if( aEnd
.Count() > 1 )
1116 aEnd
.Remove( aEnd
.Count()-1, 1 );
1118 aEnd
[ aEnd
.Count()-1 ] = *pTmp
->GetEnd();
1122 if( bOn
&& aEnd
.Count() )
1123 rPos
= aEnd
[ aEnd
.Count()-1 ];
1126 if( nRotate
< nCount
|| ( pRotItem
&& pRotItem
== pRotate
&&
1127 rPos
< GetTxt().Len() ) )
1128 { // The winner is a rotate-attribute,
1129 // the end of the multiportion depends on the following attributes...
1130 SwMultiCreator
*pRet
= new SwMultiCreator
;
1131 pRet
->nId
= SW_MC_ROTATE
;
1133 // We note the endpositions of the 2-line attributes in aEnd as stack
1136 // The bOn flag signs the state of the last 2-line attribute in the
1137 // aEnd-stack, which could interrupts the winning rotation attribute.
1138 sal_Bool bOn
= pItem
? sal_True
: sal_False
;
1139 aEnd
.Insert( GetTxt().Len(), 0 );
1140 // n2Lines is the index of the last 2-line-attribute, which contains
1141 // the actual position.
1143 xub_StrLen n2Start
= rPos
;
1146 const SwTxtAttr
*pTmp
= (*pHints
)[i
++];
1147 if( *pTmp
->GetAnyEnd() <= n2Start
)
1149 if( n2Start
< *pTmp
->GetStart() )
1151 if( bOn
|| aEnd
[ aEnd
.Count()-1 ] < *pTmp
->GetStart() )
1153 n2Start
= *pTmp
->GetStart();
1154 while( aEnd
.Count() && aEnd
[ aEnd
.Count()-1 ] <= n2Start
)
1157 aEnd
.Remove( aEnd
.Count()-1, 1 );
1161 aEnd
.Insert( n2Start
, 0 );
1165 // A ruby attribute stops immediately
1166 if( RES_TXTATR_CJK_RUBY
== pTmp
->Which() )
1172 if( lcl_Has2Lines( *pTmp
, p2Lines
, bTwo
) )
1176 if( aEnd
[ aEnd
.Count()-1 ] < *pTmp
->GetEnd() )
1177 aEnd
[ aEnd
.Count()-1 ] = *pTmp
->GetEnd();
1182 if( aEnd
[ aEnd
.Count()-1 ] > *pTmp
->GetEnd() )
1183 aEnd
.Insert( *pTmp
->GetEnd(), aEnd
.Count() );
1184 else if( aEnd
.Count() > 1 )
1185 aEnd
.Remove( aEnd
.Count()-1, 1 );
1187 aEnd
[ aEnd
.Count()-1 ] = *pTmp
->GetEnd();
1191 if( !bOn
&& aEnd
.Count() )
1192 n2Start
= aEnd
[ aEnd
.Count()-1 ];
1195 aEnd
.Remove( 0, aEnd
.Count() );
1198 if( nRotate
< nCount
)
1201 pRet
->pAttr
= (*pHints
)[nRotate
];
1202 aEnd
.Insert( *pRet
->pAttr
->GetEnd(), 0 );
1205 aEnd
[ 0 ] = GetTxt().Len();
1206 bOn
= ((SvxCharRotateItem
*)pRotItem
)->GetValue() ==
1207 pRotate
->GetValue();
1212 pRet
->pItem
= pRotItem
;
1214 aEnd
.Insert( GetTxt().Len(), 0 );
1219 const SwTxtAttr
*pTmp
= (*pHints
)[i
++];
1220 if( *pTmp
->GetAnyEnd() <= rPos
)
1222 if( rPos
< *pTmp
->GetStart() )
1224 if( !bOn
|| aEnd
[ aEnd
.Count()-1 ] < *pTmp
->GetStart() )
1226 rPos
= *pTmp
->GetStart();
1227 while( aEnd
.Count() && aEnd
[ aEnd
.Count()-1 ] <= rPos
)
1230 aEnd
.Remove( aEnd
.Count()-1, 1 );
1234 aEnd
.Insert( rPos
, 0 );
1238 if( RES_TXTATR_CJK_RUBY
== pTmp
->Which() )
1243 if( lcl_HasRotation( *pTmp
, pRotate
, bTwo
) )
1247 if( aEnd
[ aEnd
.Count()-1 ] < *pTmp
->GetEnd() )
1248 aEnd
[ aEnd
.Count()-1 ] = *pTmp
->GetEnd();
1253 if( aEnd
[ aEnd
.Count()-1 ] > *pTmp
->GetEnd() )
1254 aEnd
.Insert( *pTmp
->GetEnd(), aEnd
.Count() );
1255 else if( aEnd
.Count() > 1 )
1256 aEnd
.Remove( aEnd
.Count()-1, 1 );
1258 aEnd
[ aEnd
.Count()-1 ] = *pTmp
->GetEnd();
1262 if( bOn
&& aEnd
.Count() )
1263 rPos
= aEnd
[ aEnd
.Count()-1 ];
1264 if( rPos
> n2Start
)
1271 /*-----------------01.11.00 14:52-------------------
1272 * SwSpaceManipulator
1273 * is a little helper class to manage the spaceadd-arrays of the text adjustment
1274 * during a PaintMultiPortion.
1275 * The constructor prepares the array for the first line of multiportion,
1276 * the SecondLine-function restores the values for the first line and prepares
1278 * The destructor restores the values of the last manipulation.
1279 * --------------------------------------------------*/
1281 class SwSpaceManipulator
1283 SwTxtPaintInfo
& rInfo
;
1284 SwMultiPortion
& rMulti
;
1285 std::vector
<long>* pOldSpaceAdd
;
1288 sal_Bool bSpaceChg
: 1;
1289 sal_uInt8 nOldDir
: 2;
1291 SwSpaceManipulator( SwTxtPaintInfo
& rInf
, SwMultiPortion
& rMult
);
1292 ~SwSpaceManipulator();
1294 inline long GetSpaceAdd() const { return nSpaceAdd
; }
1297 SwSpaceManipulator::SwSpaceManipulator( SwTxtPaintInfo
& rInf
,
1298 SwMultiPortion
& rMult
) :
1299 rInfo( rInf
), rMulti( rMult
)
1301 pOldSpaceAdd
= rInfo
.GetpSpaceAdd();
1302 nOldSpIdx
= rInfo
.GetSpaceIdx();
1303 nOldDir
= rInfo
.GetDirection();
1304 rInfo
.SetDirection( rMulti
.GetDirection() );
1305 bSpaceChg
= sal_False
;
1307 if( rMulti
.IsDouble() )
1309 nSpaceAdd
= ( pOldSpaceAdd
&& !rMulti
.HasTabulator() ) ?
1310 rInfo
.GetSpaceAdd() : 0;
1311 if( rMulti
.GetRoot().IsSpaceAdd() )
1313 rInfo
.SetpSpaceAdd( rMulti
.GetRoot().GetpLLSpaceAdd() );
1314 rInfo
.ResetSpaceIdx();
1315 bSpaceChg
= rMulti
.ChgSpaceAdd( &rMulti
.GetRoot(), nSpaceAdd
);
1317 else if( rMulti
.HasTabulator() )
1318 rInfo
.SetpSpaceAdd( NULL
);
1320 else if ( ! rMulti
.IsBidi() )
1322 rInfo
.SetpSpaceAdd( rMulti
.GetRoot().GetpLLSpaceAdd() );
1323 rInfo
.ResetSpaceIdx();
1327 void SwSpaceManipulator::SecondLine()
1331 rInfo
.RemoveFirstSpaceAdd();
1332 bSpaceChg
= sal_False
;
1334 SwLineLayout
*pLay
= rMulti
.GetRoot().GetNext();
1335 if( pLay
->IsSpaceAdd() )
1337 rInfo
.SetpSpaceAdd( pLay
->GetpLLSpaceAdd() );
1338 rInfo
.ResetSpaceIdx();
1339 bSpaceChg
= rMulti
.ChgSpaceAdd( pLay
, nSpaceAdd
);
1343 rInfo
.SetpSpaceAdd( (!rMulti
.IsDouble() || rMulti
.HasTabulator() ) ?
1345 rInfo
.SetSpaceIdx( nOldSpIdx
);
1349 SwSpaceManipulator::~SwSpaceManipulator()
1353 rInfo
.RemoveFirstSpaceAdd();
1354 bSpaceChg
= sal_False
;
1356 rInfo
.SetpSpaceAdd( pOldSpaceAdd
);
1357 rInfo
.SetSpaceIdx( nOldSpIdx
);
1358 rInfo
.SetDirection( nOldDir
);
1361 /*-----------------13.10.00 16:24-------------------
1362 * SwTxtPainter::PaintMultiPortion manages the paint for a SwMultiPortion.
1363 * External, for the calling function, it seems to be a normal Paint-function,
1364 * internal it is like a SwTxtFrm::Paint with multiple DrawTextLines
1365 * --------------------------------------------------*/
1367 void SwTxtPainter::PaintMultiPortion( const SwRect
&rPaint
,
1368 SwMultiPortion
& rMulti
, const SwMultiPortion
* pEnvPor
)
1370 GETGRID( pFrm
->FindPageFrm() )
1371 const sal_Bool bHasGrid
= pGrid
&& GetInfo().SnapToGrid();
1372 USHORT nGridWidth
= 0;
1373 USHORT nRubyHeight
= 0;
1374 sal_Bool bRubyTop
= sal_False
;
1378 nGridWidth
= pGrid
->GetBaseHeight();
1379 nRubyHeight
= pGrid
->GetRubyHeight();
1380 bRubyTop
= ! pGrid
->GetRubyTextBelow();
1383 // do not allow grid mode for first line in ruby portion
1384 const sal_Bool bRubyInGrid
= bHasGrid
&& rMulti
.IsRuby();
1386 const USHORT nOldHeight
= rMulti
.Height();
1387 const sal_Bool bOldGridModeAllowed
= GetInfo().SnapToGrid();
1391 GetInfo().SetSnapToGrid( ! bRubyTop
);
1392 rMulti
.Height( pCurr
->Height() );
1395 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
1399 if ( rMulti
.IsBidi() )
1401 // these values are needed for the calculation of the x coordinate
1402 // and the layout mode
1403 ASSERT( ! pEnvPor
|| pEnvPor
->IsBidi(),
1404 "Oh no, I expected a BidiPortion" )
1405 nFrmDir
= GetInfo().GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1406 nEnvDir
= pEnvPor
? ((SwBidiPortion
*)pEnvPor
)->GetLevel() % 2 : nFrmDir
;
1407 nThisDir
= ((SwBidiPortion
&)rMulti
).GetLevel() % 2;
1410 #if OSL_DEBUG_LEVEL > 1
1411 // only paint first level bidi portions
1412 if( rMulti
.Width() > 1 && ! pEnvPor
)
1413 GetInfo().DrawViewOpt( rMulti
, POR_FLD
);
1417 rMulti
.Height( nOldHeight
);
1419 // do we have to repaint a post it portion?
1420 if( GetInfo().OnWin() && rMulti
.GetPortion() &&
1421 ! rMulti
.GetPortion()->Width() )
1422 rMulti
.GetPortion()->PrePaint( GetInfo(), &rMulti
);
1424 // old values must be saved and restored at the end
1425 xub_StrLen nOldLen
= GetInfo().GetLen();
1426 KSHORT nOldX
= KSHORT(GetInfo().X());
1427 long nOldY
= GetInfo().Y();
1428 xub_StrLen nOldIdx
= GetInfo().GetIdx();
1430 SwSpaceManipulator
aManip( GetInfo(), rMulti
);
1432 SwFontSave
*pFontSave
;
1435 if( rMulti
.IsDouble() )
1437 pTmpFnt
= new SwFont( *GetInfo().GetFont() );
1438 if( rMulti
.IsDouble() )
1441 pTmpFnt
->SetProportion( GetPropFont() );
1443 pFontSave
= new SwFontSave( GetInfo(), pTmpFnt
, this );
1451 if( rMulti
.HasBrackets() )
1453 xub_StrLen nTmpOldIdx
= GetInfo().GetIdx();
1454 GetInfo().SetIdx(((SwDoubleLinePortion
&)rMulti
).GetBrackets()->nStart
);
1455 SeekAndChg( GetInfo() );
1456 ((SwDoubleLinePortion
&)rMulti
).PaintBracket( GetInfo(), 0, sal_True
);
1457 GetInfo().SetIdx( nTmpOldIdx
);
1460 KSHORT nTmpX
= KSHORT(GetInfo().X());
1462 SwLineLayout
* pLay
= &rMulti
.GetRoot();// the first line of the multiportion
1463 SwLinePortion
* pPor
= pLay
->GetFirstPortion();//first portion of these line
1466 // GetInfo().Y() is the baseline from the surrounding line. We must switch
1467 // this temporary to the baseline of the inner lines of the multiportion.
1468 if( rMulti
.HasRotation() )
1470 if( rMulti
.IsRevers() )
1472 GetInfo().Y( nOldY
- rMulti
.GetAscent() );
1473 nOfst
= nTmpX
+ rMulti
.Width();
1477 GetInfo().Y( nOldY
- rMulti
.GetAscent() + rMulti
.Height() );
1481 else if ( rMulti
.IsBidi() )
1483 // does the current bidi portion has the same direction
1484 // as its environment?
1485 if ( nEnvDir
!= nThisDir
)
1487 // different directions, we have to adjust the x coordinate
1488 SwTwips nMultiWidth
= rMulti
.Width() +
1489 rMulti
.CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
1491 if ( nFrmDir
== nThisDir
)
1492 GetInfo().X( GetInfo().X() - nMultiWidth
);
1494 GetInfo().X( GetInfo().X() + nMultiWidth
);
1497 nOfst
= nOldY
- rMulti
.GetAscent();
1500 aLayoutModeModifier
.Modify( nThisDir
);
1503 nOfst
= nOldY
- rMulti
.GetAscent();
1505 sal_Bool bRest
= pLay
->IsRest();
1506 sal_Bool bFirst
= sal_True
;
1508 ASSERT( 0 == GetInfo().GetUnderFnt() || rMulti
.IsBidi(),
1509 " Only BiDi portions are allowed to use the common underlining font" )
1515 if( rMulti
.HasRotation() )
1517 const USHORT nAdjustment
= ( pLay
->Height() - pPor
->Height() ) / 2 +
1519 if( rMulti
.IsRevers() )
1520 GetInfo().X( nOfst
- nAdjustment
);
1522 GetInfo().X( nOfst
+ nAdjustment
);
1526 // special treatment for ruby portions in grid mode
1527 SwTwips nAdjustment
= 0;
1528 if ( rMulti
.IsRuby() )
1530 if ( bRubyTop
!= ( pLay
== &rMulti
.GetRoot() ) )
1532 nAdjustment
= ( pCurr
->Height() - nRubyHeight
- pPor
->Height() ) / 2;
1533 else if ( bRubyTop
)
1534 // adjust upper ruby text
1535 nAdjustment
= nRubyHeight
- pPor
->Height();
1536 // else adjust lower ruby text
1539 GetInfo().Y( nOfst
+ nAdjustment
+ pPor
->GetAscent() );
1542 else if( rMulti
.HasRotation() )
1544 if( rMulti
.IsRevers() )
1545 GetInfo().X( nOfst
- AdjustBaseLine( *pLay
, pPor
, 0, 0, sal_True
) );
1547 GetInfo().X( nOfst
+ AdjustBaseLine( *pLay
, pPor
) );
1550 GetInfo().Y( nOfst
+ AdjustBaseLine( *pLay
, pPor
) );
1552 sal_Bool bSeeked
= sal_True
;
1553 GetInfo().SetLen( pPor
->GetLen() );
1555 if( bRest
&& pPor
->InFldGrp() && !pPor
->GetLen() )
1557 if( ((SwFldPortion
*)pPor
)->HasFont() )
1558 bSeeked
= sal_False
;
1560 SeekAndChgBefore( GetInfo() );
1562 else if( pPor
->InTxtGrp() || pPor
->InFldGrp() || pPor
->InTabGrp() )
1563 SeekAndChg( GetInfo() );
1564 else if ( !bFirst
&& pPor
->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
1567 SeekAndChg( GetInfo() );
1569 SeekAndChgBefore( GetInfo() );
1572 bSeeked
= sal_False
;
1574 SwLinePortion
*pNext
= pPor
->GetPortion();
1575 if(GetInfo().OnWin() && pNext
&& !pNext
->Width() )
1578 SeekAndChg( GetInfo() );
1579 pNext
->PrePaint( GetInfo(), pPor
);
1582 CheckSpecialUnderline( pPor
);
1583 SwUnderlineFont
* pUnderLineFnt
= GetInfo().GetUnderFnt();
1584 if ( pUnderLineFnt
)
1586 if ( rMulti
.IsDouble() )
1587 pUnderLineFnt
->GetFont().SetProportion( 50 );
1588 pUnderLineFnt
->SetPos( GetInfo().GetPos() );
1591 if ( rMulti
.IsBidi() )
1593 // we do not allow any rotation inside a bidi portion
1594 SwFont
* pTmpFont
= GetInfo().GetFont();
1595 pTmpFont
->SetVertical( 0, GetInfo().GetTxtFrm()->IsVertical() );
1598 if( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->IsBidi() )
1600 // but we do allow nested bidi portions
1601 ASSERT( rMulti
.IsBidi(), "Only nesting of bidi portions is allowed" )
1602 PaintMultiPortion( rPaint
, (SwMultiPortion
&)*pPor
, &rMulti
);
1605 pPor
->Paint( GetInfo() );
1607 if( GetFnt()->IsURL() && pPor
->InTxtGrp() )
1608 GetInfo().NotifyURL( *pPor
);
1610 bFirst
&= !pPor
->GetLen();
1611 if( pNext
|| !pPor
->IsMarginPortion() )
1612 pPor
->Move( GetInfo() );
1616 // If there's no portion left, we go to the next line
1617 if( !pPor
&& pLay
->GetNext() )
1619 pLay
= pLay
->GetNext();
1620 pPor
= pLay
->GetFirstPortion();
1621 bRest
= pLay
->IsRest();
1622 aManip
.SecondLine();
1624 // delete underline font
1625 delete GetInfo().GetUnderFnt();
1626 GetInfo().SetUnderFnt( 0 );
1628 if( rMulti
.HasRotation() )
1630 if( rMulti
.IsRevers() )
1632 nOfst
+= pLay
->Height();
1633 GetInfo().Y( nOldY
- rMulti
.GetAscent() );
1637 nOfst
-= pLay
->Height();
1638 GetInfo().Y( nOldY
- rMulti
.GetAscent() + rMulti
.Height() );
1641 else if ( bHasGrid
&& rMulti
.IsRuby() )
1643 GetInfo().X( nTmpX
);
1646 nOfst
+= nRubyHeight
;
1647 GetInfo().SetSnapToGrid( sal_True
);
1651 nOfst
+= pCurr
->Height() - nRubyHeight
;
1652 GetInfo().SetSnapToGrid( sal_False
);
1656 GetInfo().X( nTmpX
);
1657 // We switch to the baseline of the next inner line
1658 nOfst
+= rMulti
.GetRoot().Height();
1664 GetInfo().SetSnapToGrid( bOldGridModeAllowed
);
1666 // delete underline font
1667 if ( ! rMulti
.IsBidi() )
1669 delete GetInfo().GetUnderFnt();
1670 GetInfo().SetUnderFnt( 0 );
1673 GetInfo().SetIdx( nOldIdx
);
1674 GetInfo().Y( nOldY
);
1676 if( rMulti
.HasBrackets() )
1678 xub_StrLen nTmpOldIdx
= GetInfo().GetIdx();
1679 GetInfo().SetIdx(((SwDoubleLinePortion
&)rMulti
).GetBrackets()->nStart
);
1680 SeekAndChg( GetInfo() );
1681 GetInfo().X( nOldX
);
1682 ((SwDoubleLinePortion
&)rMulti
).PaintBracket( GetInfo(),
1683 aManip
.GetSpaceAdd(), sal_False
);
1684 GetInfo().SetIdx( nTmpOldIdx
);
1686 // Restore the saved values
1687 GetInfo().X( nOldX
);
1688 GetInfo().SetLen( nOldLen
);
1694 sal_Bool
lcl_ExtractFieldFollow( SwLineLayout
* pLine
, SwLinePortion
* &rpFld
)
1696 SwLinePortion
* pLast
= pLine
;
1697 rpFld
= pLine
->GetPortion();
1698 while( rpFld
&& !rpFld
->InFldGrp() )
1701 rpFld
= rpFld
->GetPortion();
1703 sal_Bool bRet
= rpFld
!= 0;
1706 if( ((SwFldPortion
*)rpFld
)->IsFollow() )
1709 pLast
->SetPortion( NULL
);
1718 /*----------------------------------------------------
1719 * lcl_TruncateMultiPortion
1720 * If a multi portion completely has to go to the
1721 * next line, this function is called to trunctate
1722 * the rest of the remaining multi portion
1723 * --------------------------------------------------*/
1725 void lcl_TruncateMultiPortion( SwMultiPortion
& rMulti
, SwTxtFormatInfo
& rInf
,
1726 xub_StrLen nStartIdx
)
1728 rMulti
.GetRoot().Truncate();
1729 rMulti
.GetRoot().SetLen(0);
1730 rMulti
.GetRoot().Width(0);
1731 // rMulti.CalcSize( *this, aInf );
1732 if ( rMulti
.GetRoot().GetNext() )
1734 rMulti
.GetRoot().GetNext()->Truncate();
1735 rMulti
.GetRoot().GetNext()->SetLen( 0 );
1736 rMulti
.GetRoot().GetNext()->Width( 0 );
1740 rInf
.SetIdx( nStartIdx
);
1743 /*-----------------------------------------------------------------------------
1744 * SwTxtFormatter::BuildMultiPortion
1745 * manages the formatting of a SwMultiPortion. External, for the calling
1746 * function, it seems to be a normal Format-function, internal it is like a
1747 * SwTxtFrm::_Format with multiple BuildPortions
1748 *---------------------------------------------------------------------------*/
1750 BOOL
SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo
&rInf
,
1751 SwMultiPortion
& rMulti
)
1753 SwTwips nMaxWidth
= rInf
.Width();
1756 if( rMulti
.HasBrackets() )
1758 xub_StrLen nOldIdx
= rInf
.GetIdx();
1759 rInf
.SetIdx( ((SwDoubleLinePortion
&)rMulti
).GetBrackets()->nStart
);
1761 nOldX
= KSHORT(GetInfo().X());
1762 ((SwDoubleLinePortion
&)rMulti
).FormatBrackets( rInf
, nMaxWidth
);
1763 rInf
.SetIdx( nOldIdx
);
1767 SwFontSave
*pFontSave
;
1768 if( rMulti
.IsDouble() )
1770 SwFont
* pTmpFnt
= new SwFont( *rInf
.GetFont() );
1771 if( rMulti
.IsDouble() )
1774 pTmpFnt
->SetProportion( GetPropFont() );
1776 pFontSave
= new SwFontSave( rInf
, pTmpFnt
, this );
1781 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
1782 if ( rMulti
.IsBidi() )
1785 aLayoutModeModifier
.Modify( ! rInf
.GetTxtFrm()->IsRightToLeft() );
1790 if( rMulti
.HasRotation() )
1792 // For nMaxWidth we take the height of the body frame.
1793 // #i25067#: If the current frame is inside a table, we restrict
1794 // nMaxWidth to the current frame height, unless the frame size
1795 // attribute is set to variable size:
1797 // We set nTmpX (which is used for portion calculating) to the
1799 const SwPageFrm
* pPage
= pFrm
->FindPageFrm();
1800 ASSERT( pPage
, "No page in frame!");
1801 const SwLayoutFrm
* pUpperFrm
= pPage
;
1803 if ( pFrm
->IsInTab() )
1805 pUpperFrm
= pFrm
->GetUpper();
1806 while ( pUpperFrm
&& !pUpperFrm
->IsCellFrm() )
1807 pUpperFrm
= pUpperFrm
->GetUpper();
1808 ASSERT( pUpperFrm
, "pFrm is in table but does not have an upper cell frame" )
1809 const SwTableLine
* pLine
= ((SwRowFrm
*)pUpperFrm
->GetUpper())->GetTabLine();
1810 const SwFmtFrmSize
& rFrmFmtSize
= pLine
->GetFrmFmt()->GetFrmSize();
1811 if ( ATT_VAR_SIZE
== rFrmFmtSize
.GetHeightSizeType() )
1814 if ( pUpperFrm
== pPage
&& !pFrm
->IsInFtn() )
1815 pUpperFrm
= pPage
->FindBodyCont();
1817 nMaxWidth
= pUpperFrm
?
1818 ( rInf
.GetTxtFrm()->IsVertical() ?
1819 pUpperFrm
->Prt().Width() :
1820 pUpperFrm
->Prt().Height() ) :
1826 SwMultiPortion
* pOldMulti
= pMulti
;
1829 SwLineLayout
*pOldCurr
= pCurr
;
1830 xub_StrLen nOldStart
= GetStart();
1831 SwTwips nMinWidth
= nTmpX
+ 1;
1832 SwTwips nActWidth
= nMaxWidth
;
1833 const xub_StrLen nStartIdx
= rInf
.GetIdx();
1834 xub_StrLen nMultiLen
= rMulti
.GetLen();
1836 SwLinePortion
*pFirstRest
;
1837 SwLinePortion
*pSecondRest
;
1838 if( rMulti
.IsFormatted() )
1840 if( !lcl_ExtractFieldFollow( &rMulti
.GetRoot(), pFirstRest
)
1841 && rMulti
.IsDouble() && rMulti
.GetRoot().GetNext() )
1842 lcl_ExtractFieldFollow( rMulti
.GetRoot().GetNext(), pFirstRest
);
1843 if( !rMulti
.IsDouble() && rMulti
.GetRoot().GetNext() )
1844 lcl_ExtractFieldFollow( rMulti
.GetRoot().GetNext(), pSecondRest
);
1850 pFirstRest
= rMulti
.GetRoot().GetPortion();
1851 pSecondRest
= rMulti
.GetRoot().GetNext() ?
1852 rMulti
.GetRoot().GetNext()->GetPortion() : NULL
;
1854 rMulti
.GetRoot().SetPortion( NULL
);
1856 rMulti
.GetRoot().GetNext()->SetPortion( NULL
);
1857 rMulti
.SetFormatted();
1858 nMultiLen
= nMultiLen
- rInf
.GetIdx();
1862 const XubString
* pOldTxt
= &(rInf
.GetTxt());
1863 const SwTwips nOldPaintOfst
= rInf
.GetPaintOfst();
1865 XubString
aMultiStr( rInf
.GetTxt(), 0, nMultiLen
+ rInf
.GetIdx() );
1866 rInf
.SetTxt( aMultiStr
);
1867 SwTxtFormatInfo
aInf( rInf
, rMulti
.GetRoot(), nActWidth
);
1868 // Do we allow break cuts? The FirstMulti-Flag is evaluated during
1869 // line break determination.
1870 sal_Bool bFirstMulti
= rInf
.GetIdx() != rInf
.GetLineStart();
1872 SwLinePortion
*pNextFirst
= NULL
;
1873 SwLinePortion
*pNextSecond
= NULL
;
1876 GETGRID( pFrm
->FindPageFrm() )
1877 const sal_Bool bHasGrid
= pGrid
&& GRID_LINES_CHARS
== pGrid
->GetGridType();
1879 USHORT nGridWidth
= 0;
1880 USHORT nRubyHeight
= 0;
1881 sal_Bool bRubyTop
= sal_False
;
1885 nGridWidth
= pGrid
->GetBaseHeight();
1886 nRubyHeight
= pGrid
->GetRubyHeight();
1887 bRubyTop
= ! pGrid
->GetRubyTextBelow();
1892 pCurr
= &rMulti
.GetRoot();
1895 FormatReset( aInf
);
1897 aInf
.Width( KSHORT(nActWidth
) );
1898 aInf
.RealWidth( KSHORT(nActWidth
) );
1899 aInf
.SetFirstMulti( bFirstMulti
);
1900 aInf
.SetNumDone( rInf
.IsNumDone() );
1901 aInf
.SetFtnDone( rInf
.IsFtnDone() );
1905 ASSERT( pFirstRest
->InFldGrp(), "BuildMulti: Fieldrest expected");
1906 SwFldPortion
*pFld
=
1907 ((SwFldPortion
*)pFirstRest
)->Clone(
1908 ((SwFldPortion
*)pFirstRest
)->GetExp() );
1909 pFld
->SetFollow( sal_True
);
1910 aInf
.SetRest( pFld
);
1912 aInf
.SetRuby( rMulti
.IsRuby() && rMulti
.OnTop() );
1914 // in grid mode we temporarily have to disable the grid for the ruby line
1915 const sal_Bool bOldGridModeAllowed
= GetInfo().SnapToGrid();
1916 if ( bHasGrid
&& aInf
.IsRuby() && bRubyTop
)
1917 aInf
.SetSnapToGrid( sal_False
);
1919 // If there's no more rubytext, then buildportion is forbidden
1920 if( pFirstRest
|| !aInf
.IsRuby() )
1921 BuildPortions( aInf
);
1923 aInf
.SetSnapToGrid( bOldGridModeAllowed
);
1925 rMulti
.CalcSize( *this, aInf
);
1926 pCurr
->SetRealHeight( pCurr
->Height() );
1928 if( rMulti
.IsBidi() )
1930 pNextFirst
= aInf
.GetRest();
1934 if( rMulti
.HasRotation() && !rMulti
.IsDouble() )
1936 // second line has to be formatted
1937 else if( pCurr
->GetLen()<nMultiLen
|| rMulti
.IsRuby() || aInf
.GetRest())
1939 xub_StrLen nFirstLen
= pCurr
->GetLen();
1940 delete pCurr
->GetNext();
1941 pCurr
->SetNext( new SwLineLayout() );
1942 pCurr
= pCurr
->GetNext();
1943 nStart
= aInf
.GetIdx();
1945 SwTxtFormatInfo
aTmp( aInf
, *pCurr
, nActWidth
);
1946 if( rMulti
.IsRuby() )
1948 aTmp
.SetRuby( !rMulti
.OnTop() );
1949 pNextFirst
= aInf
.GetRest();
1952 ASSERT( pSecondRest
->InFldGrp(), "Fieldrest expected");
1953 SwFldPortion
*pFld
= ((SwFldPortion
*)pSecondRest
)->Clone(
1954 ((SwFldPortion
*)pSecondRest
)->GetExp() );
1955 pFld
->SetFollow( sal_True
);
1956 aTmp
.SetRest( pFld
);
1958 if( !rMulti
.OnTop() && nFirstLen
< nMultiLen
)
1962 aTmp
.SetRest( aInf
.GetRest() );
1963 aInf
.SetRest( NULL
);
1965 // in grid mode we temporarily have to disable the grid for the ruby line
1966 if ( bHasGrid
&& aTmp
.IsRuby() && ! bRubyTop
)
1967 aTmp
.SetSnapToGrid( sal_False
);
1969 BuildPortions( aTmp
);
1971 aTmp
.SetSnapToGrid( bOldGridModeAllowed
);
1973 rMulti
.CalcSize( *this, aInf
);
1974 rMulti
.GetRoot().SetRealHeight( rMulti
.GetRoot().Height() );
1975 pCurr
->SetRealHeight( pCurr
->Height() );
1976 if( rMulti
.IsRuby() )
1978 pNextSecond
= aTmp
.GetRest();
1983 pNextFirst
= aTmp
.GetRest();
1984 if( ( !aTmp
.IsRuby() && nFirstLen
+ pCurr
->GetLen() < nMultiLen
)
1986 // our guess for width of multiportion was too small,
1987 // text did not fit into multiportion
1990 if( rMulti
.IsRuby() )
1994 // our guess for multiportion width was too small,
1995 // we set min to act
1996 nMinWidth
= nActWidth
;
1997 nActWidth
= ( 3 * nMaxWidth
+ nMinWidth
+ 3 ) / 4;
1998 if ( nActWidth
== nMaxWidth
&& rInf
.GetLineStart() == rInf
.GetIdx() )
1999 // we have too less space, we must allow break cuts
2000 // ( the first multi flag is considered during TxtPortion::_Format() )
2001 bFirstMulti
= sal_False
;
2002 if( nActWidth
<= nMinWidth
)
2007 // For Solaris, this optimisation can causes trouble:
2008 // Setting this to the portion width ( = rMulti.Width() )
2009 // can make GetTextBreak inside SwTxtGuess::Guess return to small
2010 // values. Therefore we add some extra twips.
2011 if( nActWidth
> nTmpX
+ rMulti
.Width() + 6 )
2012 nActWidth
= nTmpX
+ rMulti
.Width() + 6;
2013 nMaxWidth
= nActWidth
;
2014 nActWidth
= ( 3 * nMaxWidth
+ nMinWidth
+ 3 ) / 4;
2015 if( nActWidth
>= nMaxWidth
)
2017 // we do not allow break cuts during formatting
2018 bFirstMulti
= sal_True
;
2030 rMulti
.SetLen( rMulti
.GetRoot().GetLen() + ( rMulti
.GetRoot().GetNext() ?
2031 rMulti
.GetRoot().GetNext()->GetLen() : 0 ) );
2033 if( rMulti
.IsDouble() )
2035 ((SwDoubleLinePortion
&)rMulti
).CalcBlanks( rInf
);
2036 if( ((SwDoubleLinePortion
&)rMulti
).GetLineDiff() )
2038 SwLineLayout
* pLine
= &rMulti
.GetRoot();
2039 if( ((SwDoubleLinePortion
&)rMulti
).GetLineDiff() > 0 )
2041 rInf
.SetIdx( nStartIdx
+ pLine
->GetLen() );
2042 pLine
= pLine
->GetNext();
2046 GetInfo().SetMulti( sal_True
);
2047 CalcNewBlock( pLine
, NULL
, rMulti
.Width() );
2048 GetInfo().SetMulti( sal_False
);
2050 rInf
.SetIdx( nStartIdx
);
2052 if( ((SwDoubleLinePortion
&)rMulti
).GetBrackets() )
2054 rMulti
.Width( rMulti
.Width() +
2055 ((SwDoubleLinePortion
&)rMulti
).BracketWidth() );
2056 GetInfo().X( nOldX
);
2061 rMulti
.ActualizeTabulator();
2062 if( rMulti
.IsRuby() )
2064 ((SwRubyPortion
&)rMulti
).Adjust( rInf
);
2065 ((SwRubyPortion
&)rMulti
).CalcRubyOffset();
2068 if( rMulti
.HasRotation() )
2070 SwTwips nH
= rMulti
.Width();
2071 SwTwips nAsc
= rMulti
.GetAscent() + ( nH
- rMulti
.Height() )/2;
2076 rMulti
.Width( rMulti
.Height() );
2077 rMulti
.Height( KSHORT(nH
) );
2078 rMulti
.SetAscent( KSHORT(nAsc
) );
2079 bRet
= ( rInf
.GetPos().X() + rMulti
.Width() > rInf
.Width() ) &&
2080 nStartIdx
!= rInf
.GetLineStart();
2082 else if ( rMulti
.IsBidi() )
2084 bRet
= rMulti
.GetLen() < nMultiLen
|| pNextFirst
;
2087 // line break has to be performed!
2090 ASSERT( !pNextFirst
|| pNextFirst
->InFldGrp(),
2091 "BuildMultiPortion: Surprising restportion, field expected" );
2092 SwMultiPortion
*pTmp
;
2093 if( rMulti
.IsDouble() )
2094 pTmp
= new SwDoubleLinePortion( ((SwDoubleLinePortion
&)rMulti
),
2095 nMultiLen
+ rInf
.GetIdx() );
2096 else if( rMulti
.IsRuby() )
2098 ASSERT( !pNextSecond
|| pNextSecond
->InFldGrp(),
2099 "BuildMultiPortion: Surprising restportion, field expected" );
2101 if ( rInf
.GetIdx() == rInf
.GetLineStart() )
2103 // the ruby portion has to be split in two portions
2104 pTmp
= new SwRubyPortion( ((SwRubyPortion
&)rMulti
),
2105 nMultiLen
+ rInf
.GetIdx() );
2109 pTmp
->GetRoot().SetNext( new SwLineLayout() );
2110 pTmp
->GetRoot().GetNext()->SetPortion( pNextSecond
);
2112 pTmp
->SetFollowFld();
2116 // we try to keep our ruby portion together
2117 lcl_TruncateMultiPortion( rMulti
, rInf
, nStartIdx
);
2121 else if( rMulti
.HasRotation() )
2123 // we try to keep our rotated portion together
2124 lcl_TruncateMultiPortion( rMulti
, rInf
, nStartIdx
);
2125 pTmp
= new SwRotatedPortion( nMultiLen
+ rInf
.GetIdx(),
2126 rMulti
.GetDirection() );
2128 // during a recursion of BuildMultiPortions we may not build
2129 // a new SwBidiPortion, this would cause a memory leak
2130 else if( rMulti
.IsBidi() && ! pMulti
)
2132 if ( ! rMulti
.GetLen() )
2133 lcl_TruncateMultiPortion( rMulti
, rInf
, nStartIdx
);
2135 // If there is a HolePortion at the end of the bidi portion,
2136 // it has to be moved behind the bidi portion. Otherwise
2137 // the visual cursor travelling gets into trouble.
2138 SwLineLayout
& aRoot
= rMulti
.GetRoot();
2139 SwLinePortion
* pPor
= aRoot
.GetFirstPortion();
2142 if ( pPor
->GetPortion() && pPor
->GetPortion()->IsHolePortion() )
2144 SwLinePortion
* pHolePor
= pPor
->GetPortion();
2145 pPor
->SetPortion( NULL
);
2146 aRoot
.SetLen( aRoot
.GetLen() - pHolePor
->GetLen() );
2147 rMulti
.SetLen( rMulti
.GetLen() - pHolePor
->GetLen() );
2148 rMulti
.SetPortion( pHolePor
);
2151 pPor
= pPor
->GetPortion();
2154 pTmp
= new SwBidiPortion( nMultiLen
+ rInf
.GetIdx(),
2155 ((SwBidiPortion
&)rMulti
).GetLevel() );
2160 if ( ! rMulti
.GetLen() && rInf
.GetLast() )
2162 SeekAndChgBefore( rInf
);
2163 rInf
.GetLast()->FormatEOL( rInf
);
2166 if( pNextFirst
&& pTmp
)
2168 pTmp
->SetFollowFld();
2169 pTmp
->GetRoot().SetPortion( pNextFirst
);
2172 // A follow field portion is still waiting. If nobody wants it,
2176 rInf
.SetRest( pTmp
);
2179 rInf
.SetTxt( *pOldTxt
);
2180 rInf
.SetPaintOfst( nOldPaintOfst
);
2181 rInf
.SetStop( aInf
.IsStop() );
2182 rInf
.SetNumDone( sal_True
);
2183 rInf
.SetFtnDone( sal_True
);
2191 /*-----------------08.11.00 09:29-------------------
2192 * SwTxtFormatter::MakeRestPortion(..)
2193 * When a fieldportion at the end of line breaks and needs a following
2194 * fieldportion in the next line, then the "restportion" of the formatinfo
2195 * has to be set. Normally this happens during the formatting of the first
2196 * part of the fieldportion.
2197 * But sometimes the formatting starts at the line with the following part,
2198 * exspecally when the following part is on the next page.
2199 * In this case the MakeRestPortion-function has to create the following part.
2200 * The first parameter is the line that contains possibly a first part
2201 * of a field. When the function finds such field part, it creates the right
2202 * restportion. This may be a multiportion, e.g. if the field is surrounded by
2203 * a doubleline- or ruby-portion.
2204 * The second parameter is the start index of the line.
2205 * --------------------------------------------------*/
2207 SwLinePortion
* SwTxtFormatter::MakeRestPortion( const SwLineLayout
* pLine
,
2208 xub_StrLen nPosition
)
2212 xub_StrLen nMultiPos
= nPosition
- pLine
->GetLen();
2213 const SwMultiPortion
*pTmpMulti
= NULL
;
2214 const SwMultiPortion
*pHelpMulti
= NULL
;
2215 const SwLinePortion
* pPor
= pLine
->GetFirstPortion();
2216 SwFldPortion
*pFld
= NULL
;
2219 if( pPor
->GetLen() )
2223 nMultiPos
= nMultiPos
+ pPor
->GetLen();
2227 if( pPor
->InFldGrp() )
2231 pFld
= (SwFldPortion
*)pPor
;
2233 else if( pPor
->IsMultiPortion() )
2235 ASSERT( !pHelpMulti
|| pHelpMulti
->IsBidi(),
2236 "Nested multiportions are forbidden." );
2239 pTmpMulti
= (SwMultiPortion
*)pPor
;
2241 pPor
= pPor
->GetPortion();
2242 // If the last portion is a multi-portion, we enter it
2243 // and look for a field portion inside.
2244 // If we are already in a multiportion, we could change to the
2246 if( !pPor
&& pTmpMulti
)
2249 { // We're already inside the multiportion, let's take the second
2250 // line, if we are in a double line portion
2251 if( !pHelpMulti
->IsRuby() )
2252 pPor
= pHelpMulti
->GetRoot().GetNext();
2256 { // Now we enter a multiportion, in a ruby portion we take the
2257 // main line, not the phonetic line, in a doublelineportion we
2258 // starts with the first line.
2259 pHelpMulti
= pTmpMulti
;
2260 nMultiPos
= nMultiPos
- pHelpMulti
->GetLen();
2261 if( pHelpMulti
->IsRuby() && pHelpMulti
->OnTop() )
2262 pPor
= pHelpMulti
->GetRoot().GetNext();
2264 pPor
= pHelpMulti
->GetRoot().GetFirstPortion();
2268 if( pFld
&& !pFld
->HasFollow() )
2271 SwLinePortion
*pRest
= NULL
;
2274 const SwTxtAttr
*pHint
= GetAttr( nPosition
- 1 );
2275 if( pHint
&& pHint
->Which() == RES_TXTATR_FIELD
)
2277 pRest
= NewFldPortion( GetInfo(), pHint
);
2278 if( pRest
->InFldGrp() )
2279 ((SwFldPortion
*)pRest
)->TakeNextOffset( pFld
);
2290 nPosition
= nMultiPos
+ pHelpMulti
->GetLen();
2291 SwMultiCreator
* pCreate
= GetInfo().GetMultiCreator( nMultiPos
, 0 );
2295 ASSERT( !pHelpMulti
->GetLen(), "Multiportion without attribut?" );
2298 pCreate
= GetInfo().GetMultiCreator( --nMultiPos
, 0 );
2301 if( pRest
|| nMultiPos
> nPosition
|| ( pHelpMulti
->IsRuby() &&
2302 ((SwRubyPortion
*)pHelpMulti
)->GetRubyOffset() < STRING_LEN
) )
2304 SwMultiPortion
* pTmp
;
2305 if( pHelpMulti
->IsDouble() )
2306 pTmp
= new SwDoubleLinePortion( *pCreate
, nMultiPos
);
2307 else if( pHelpMulti
->IsBidi() )
2308 pTmp
= new SwBidiPortion( nMultiPos
, pCreate
->nLevel
);
2309 else if( pHelpMulti
->IsRuby() )
2312 sal_Bool
* pRubyPos
= 0;
2314 if ( GetInfo().SnapToGrid() )
2316 GETGRID( pFrm
->FindPageFrm() )
2319 bRubyTop
= ! pGrid
->GetRubyTextBelow();
2320 pRubyPos
= &bRubyTop
;
2324 pTmp
= new SwRubyPortion( *pCreate
, *GetInfo().GetFont(),
2325 *pFrm
->GetTxtNode()->getIDocumentSettingAccess(),
2326 nMultiPos
, ((SwRubyPortion
*)pHelpMulti
)->GetRubyOffset(),
2329 else if( pHelpMulti
->HasRotation() )
2330 pTmp
= new SwRotatedPortion( nMultiPos
, pHelpMulti
->GetDirection() );
2337 pTmp
->SetFollowFld();
2340 SwLineLayout
*pLay
= &pTmp
->GetRoot();
2341 if( pTmp
->IsRuby() && pTmp
->OnTop() )
2343 pLay
->SetNext( new SwLineLayout() );
2344 pLay
= pLay
->GetNext();
2346 pLay
->SetPortion( pRest
);
2355 /*-----------------23.10.00 10:47-------------------
2356 * SwTxtCursorSave notes the start and current line of a SwTxtCursor,
2357 * sets them to the values for GetCrsrOfst inside a multiportion
2358 * and restores them in the destructor.
2359 * --------------------------------------------------*/
2361 SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor
* pTxtCursor
,
2362 SwMultiPortion
* pMulti
,
2365 xub_StrLen nCurrStart
,
2368 pTxtCrsr
= pTxtCursor
;
2369 nStart
= pTxtCursor
->nStart
;
2370 pTxtCursor
->nStart
= nCurrStart
;
2371 pCurr
= pTxtCursor
->pCurr
;
2372 pTxtCursor
->pCurr
= &pMulti
->GetRoot();
2373 while( pTxtCursor
->Y() + pTxtCursor
->GetLineHeight() < nY
&&
2374 pTxtCursor
->Next() )
2376 nWidth
= pTxtCursor
->pCurr
->Width();
2377 nOldProp
= pTxtCursor
->GetPropFont();
2379 if ( pMulti
->IsDouble() || pMulti
->IsBidi() )
2381 bSpaceChg
= pMulti
->ChgSpaceAdd( pTxtCursor
->pCurr
, nSpaceAdd
);
2384 if ( pMulti
->IsDouble() )
2386 pTxtCursor
->SetPropFont( 50 );
2387 nSpaceCnt
= ((SwDoubleLinePortion
*)pMulti
)->GetSpaceCnt();
2391 const xub_StrLen nOldIdx
= pTxtCursor
->GetInfo().GetIdx();
2392 pTxtCursor
->GetInfo().SetIdx ( nCurrStart
);
2393 nSpaceCnt
= ((SwBidiPortion
*)pMulti
)->GetSpaceCnt(pTxtCursor
->GetInfo());
2394 pTxtCursor
->GetInfo().SetIdx ( nOldIdx
);
2397 if( nSpaceAdd
> 0 && !pMulti
->HasTabulator() )
2398 pTxtCursor
->pCurr
->Width( static_cast<USHORT
>(nWidth
+ nSpaceAdd
* nSpaceCnt
/ SPACING_PRECISION_FACTOR
) );
2400 // For a BidiPortion we have to calculate the offset from the
2401 // end of the portion
2402 if ( nX
&& pMulti
->IsBidi() )
2403 nX
= pTxtCursor
->pCurr
->Width() - nX
;
2406 bSpaceChg
= sal_False
;
2409 SwTxtCursorSave::~SwTxtCursorSave()
2412 SwDoubleLinePortion::ResetSpaceAdd( pTxtCrsr
->pCurr
);
2413 pTxtCrsr
->pCurr
->Width( KSHORT(nWidth
) );
2414 pTxtCrsr
->pCurr
= pCurr
;
2415 pTxtCrsr
->nStart
= nStart
;
2416 pTxtCrsr
->SetPropFont( nOldProp
);