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: txtdrop.cxx,v $
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>
36 #include <vcl/metric.hxx>
37 #include <vcl/window.hxx>
38 #include <vcl/svapp.hxx>
40 #include <txtfrm.hxx> // Format()
41 #include <charfmt.hxx>
42 #include <viewopt.hxx> // SwViewOption
43 #include <viewsh.hxx> // ViewShell
44 #include <pordrop.hxx>
45 #include <itrform2.hxx>
46 #include <txtpaint.hxx> // SwSaveClip
47 #include <blink.hxx> // pBlink
48 #include <breakit.hxx>
49 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
50 #include <com/sun/star/i18n/ScriptType.hdl>
52 #include <com/sun/star/i18n/WordType.hpp>
53 #include <svx/langitem.hxx>
54 #include <charatr.hxx>
55 #include <svx/fhgtitem.hxx>
57 using namespace ::com::sun::star::i18n
;
58 using namespace ::com::sun::star
;
60 /*************************************************************************
63 * Calculates if a drop caps portion intersects with a fly
64 * The width and height of the drop caps portion are passed as arguments,
65 * the position is calculated from the values in rInf
66 *************************************************************************/
68 sal_Bool
lcl_IsDropFlyInter( const SwTxtFormatInfo
&rInf
,
69 USHORT nWidth
, USHORT nHeight
)
71 const SwTxtFly
*pTxtFly
= rInf
.GetTxtFly();
72 if( pTxtFly
&& pTxtFly
->IsOn() )
74 SwRect
aRect( rInf
.GetTxtFrm()->Frm().Pos(), Size( nWidth
, nHeight
) );
75 aRect
.Pos() += rInf
.GetTxtFrm()->Prt().Pos();
76 aRect
.Pos().X() += rInf
.X();
77 aRect
.Pos().Y() = rInf
.Y();
78 aRect
= pTxtFly
->GetFrm( aRect
);
79 return aRect
.HasArea();
85 /*************************************************************************
87 *************************************************************************/
98 SwDropSave( const SwTxtPaintInfo
&rInf
);
102 SwDropSave::SwDropSave( const SwTxtPaintInfo
&rInf
) :
103 pInf( ((SwTxtPaintInfo
*)&rInf
) ), nIdx( rInf
.GetIdx() ),
104 nLen( rInf
.GetLen() ), nX( rInf
.X() ), nY( rInf
.Y() )
108 SwDropSave::~SwDropSave()
110 pInf
->SetIdx( nIdx
);
111 pInf
->SetLen( nLen
);
116 /*************************************************************************
117 * SwDropPortionPart DTor
118 *************************************************************************/
120 SwDropPortionPart::~SwDropPortionPart()
127 /*************************************************************************
128 * SwDropPortion CTor, DTor
129 *************************************************************************/
131 SwDropPortion::SwDropPortion( const MSHORT nLineCnt
,
132 const KSHORT nDrpHeight
,
133 const KSHORT nDrpDescent
,
137 nDropHeight(nDrpHeight
),
138 nDropDescent(nDrpDescent
),
143 SetWhichPor( POR_DROP
);
146 SwDropPortion::~SwDropPortion()
150 pBlink
->Delete( this );
153 sal_Bool
SwTxtSizeInfo::_HasHint( const SwTxtNode
* pTxtNode
, xub_StrLen nPos
)
155 const SwpHints
*pHints
= pTxtNode
->GetpSwpHints();
158 for ( USHORT i
= 0; i
< pHints
->Count(); ++i
)
160 const SwTxtAttr
*pPos
= (*pHints
)[i
];
161 xub_StrLen nStart
= *pPos
->GetStart();
164 if( nPos
== nStart
&& !pPos
->GetEnd() )
170 /*************************************************************************
171 * SwTxtNode::GetDropLen()
173 * nWishLen = 0 indicates that we want a whole word
174 *************************************************************************/
176 MSHORT
SwTxtNode::GetDropLen( MSHORT nWishLen
) const
178 xub_StrLen nEnd
= GetTxt().Len();
179 if( nWishLen
&& nWishLen
< nEnd
)
182 if ( ! nWishLen
&& pBreakIt
->GetBreakIter().is() )
185 const SwAttrSet
& rAttrSet
= GetSwAttrSet();
186 const USHORT nTxtScript
= pBreakIt
->GetRealScriptOfText( GetTxt(), 0 );
188 LanguageType eLanguage
;
190 switch ( nTxtScript
)
192 case i18n::ScriptType::ASIAN
:
193 eLanguage
= rAttrSet
.GetCJKLanguage().GetLanguage();
195 case i18n::ScriptType::COMPLEX
:
196 eLanguage
= rAttrSet
.GetCTLLanguage().GetLanguage();
199 eLanguage
= rAttrSet
.GetLanguage().GetLanguage();
204 pBreakIt
->GetBreakIter()->getWordBoundary( GetTxt(), 0,
205 pBreakIt
->GetLocale( eLanguage
), WordType::DICTIONARY_WORD
, sal_True
);
207 nEnd
= (xub_StrLen
)aBound
.endPos
;
211 for( ; i
< nEnd
; ++i
)
213 xub_Unicode cChar
= GetTxt().GetChar( i
);
214 if( CH_TAB
== cChar
|| CH_BREAK
== cChar
||
215 (( CH_TXTATR_BREAKWORD
== cChar
|| CH_TXTATR_INWORD
== cChar
)
216 && SwTxtSizeInfo::_HasHint( this, i
) ) )
222 /*************************************************************************
223 * SwTxtNode::GetDropSize()
225 * If a dropcap is found the return value is true otherwise false. The
226 * drop cap sizes passed back by reference are font height, drop height
228 *************************************************************************/
229 bool SwTxtNode::GetDropSize(int& rFontHeight
, int& rDropHeight
, int& rDropDescent
) const
235 const SwAttrSet
& rSet
= GetSwAttrSet();
236 const SwFmtDrop
& rDrop
= rSet
.GetDrop();
238 // Return (0,0) if there is no drop cap at this paragraph
239 if( 1 >= rDrop
.GetLines() ||
240 ( !rDrop
.GetChars() && !rDrop
.GetWholeWord() ) )
246 SwClientIter
aClientIter( (SwTxtNode
&)*this );
247 SwClient
* pLastFrm
= aClientIter
.GoStart();
251 // Only (master-) text frames can have a drop cap.
252 if ( pLastFrm
->ISA( SwTxtFrm
) && !((SwTxtFrm
*)pLastFrm
)->IsFollow() )
255 if( !((SwTxtFrm
*)pLastFrm
)->HasPara() )
256 ((SwTxtFrm
*)pLastFrm
)->GetFormatted();
258 if ( !((SwTxtFrm
*)pLastFrm
)->IsEmpty() )
260 const SwParaPortion
* pPara
= ((SwTxtFrm
*)pLastFrm
)->GetPara();
261 ASSERT( pPara
, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" )
265 const SwLinePortion
* pFirstPor
= pPara
->GetFirstPortion();
266 if (pFirstPor
&& pFirstPor
->IsDropPortion())
268 const SwDropPortion
* pDrop
= (const SwDropPortion
*)pFirstPor
;
269 rDropHeight
= pDrop
->GetDropHeight();
270 rDropDescent
= pDrop
->GetDropDescent();
271 if (const SwFont
*pFont
= pDrop
->GetFnt())
272 rFontHeight
= pFont
->GetSize(pFont
->GetActual()).Height();
275 const SvxFontHeightItem
& rItem
= (SvxFontHeightItem
&)rSet
.Get(RES_CHRATR_FONTSIZE
);
276 rFontHeight
= rItem
.GetHeight();
283 pLastFrm
= ++aClientIter
;
286 if (rFontHeight
==0 && rDropHeight
==0 && rDropDescent
==0)
288 const USHORT nLines
= rDrop
.GetLines();
290 const SvxFontHeightItem
& rItem
= (SvxFontHeightItem
&)rSet
.Get( RES_CHRATR_FONTSIZE
);
291 rFontHeight
= rItem
.GetHeight();
292 rDropHeight
= nLines
* rFontHeight
;
293 rDropDescent
= rFontHeight
/ 5;
300 /*************************************************************************
301 * SwDropPortion::PaintTxt()
302 *************************************************************************/
304 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
306 void SwDropPortion::PaintTxt( const SwTxtPaintInfo
&rInf
) const
309 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
310 rInf
.DrawBackground( *this );
312 ASSERT( nDropHeight
&& pPart
&& nLines
!= 1, "Drop Portion painted twice" );
314 const SwDropPortionPart
* pCurrPart
= GetPart();
315 const xub_StrLen nOldLen
= GetLen();
317 const SwTwips nBasePosY
= rInf
.Y();
318 ((SwTxtPaintInfo
&)rInf
).Y( nBasePosY
+ nY
);
319 SwDropSave
aSave( rInf
);
320 // for text inside drop portions we let vcl handle the text directions
321 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
322 aLayoutModeModifier
.SetAuto();
326 ((SwDropPortion
*)this)->SetLen( pCurrPart
->GetLen() );
327 ((SwTxtPaintInfo
&)rInf
).SetLen( pCurrPart
->GetLen() );
328 SwFontSave
aFontSave( rInf
, &pCurrPart
->GetFont() );
330 SwTxtPortion::Paint( rInf
);
332 ((SwTxtPaintInfo
&)rInf
).SetIdx( rInf
.GetIdx() + pCurrPart
->GetLen() );
333 ((SwTxtPaintInfo
&)rInf
).X( rInf
.X() + pCurrPart
->GetWidth() );
334 pCurrPart
= pCurrPart
->GetFollow();
337 ((SwTxtPaintInfo
&)rInf
).Y( nBasePosY
);
338 ((SwDropPortion
*)this)->SetLen( nOldLen
);
341 /*************************************************************************
342 * SwDropPortion::Paint()
343 *************************************************************************/
345 void SwDropPortion::PaintDrop( const SwTxtPaintInfo
&rInf
) const
347 // ganz normale Ausgabe wird w?hrend des normalen Paints erledigt
348 if( ! nDropHeight
|| ! pPart
|| nLines
== 1 )
351 // Luegenwerte einstellen!
352 const KSHORT nOldHeight
= Height();
353 const KSHORT nOldWidth
= Width();
354 const KSHORT nOldAscent
= GetAscent();
355 const SwTwips nOldPosY
= rInf
.Y();
356 const KSHORT nOldPosX
= (KSHORT
)rInf
.X();
357 const SwParaPortion
*pPara
= rInf
.GetParaPortion();
358 const Point
aOutPos( nOldPosX
+ nX
, nOldPosY
- pPara
->GetAscent()
359 - pPara
->GetRealHeight() + pPara
->Height() );
360 // Retusche nachholen.
363 ((SwTxtPaintInfo
&)rInf
).Y( aOutPos
.Y() + nDropHeight
);
366 ((SwDropPortion
*)this)->Height( nDropHeight
+ nDropDescent
);
367 ((SwDropPortion
*)this)->Width( Width() - nX
);
368 ((SwDropPortion
*)this)->SetAscent( nDropHeight
);
370 // Clipregion auf uns einstellen!
371 // Und zwar immer, und nie mit dem bestehenden ClipRect
372 // verrechnen, weil dies auf die Zeile eingestellt sein koennte.
377 aClipRect
= SwRect( aOutPos
, SvLSize() );
378 aClipRect
.Intersection( rInf
.GetPaintRect() );
380 SwSaveClip
aClip( (OutputDevice
*)rInf
.GetOut() );
381 aClip
.ChgClip( aClipRect
, rInf
.GetTxtFrm() );
382 // Das machen, was man sonst nur macht ...
385 // Alte Werte sichern
386 ((SwDropPortion
*)this)->Height( nOldHeight
);
387 ((SwDropPortion
*)this)->Width( nOldWidth
);
388 ((SwDropPortion
*)this)->SetAscent( nOldAscent
);
389 ((SwTxtPaintInfo
&)rInf
).Y( nOldPosY
);
392 /*************************************************************************
393 * virtual SwDropPortion::Paint()
394 *************************************************************************/
396 void SwDropPortion::Paint( const SwTxtPaintInfo
&rInf
) const
398 // ganz normale Ausgabe wird hier erledigt.
399 if( ! nDropHeight
|| ! pPart
|| 1 == nLines
)
402 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
403 rInf
.DrawBackground( *this );
405 // make sure that font is not rotated
406 SwFont
* pTmpFont
= 0;
407 if ( rInf
.GetFont()->GetOrientation( rInf
.GetTxtFrm()->IsVertical() ) )
409 pTmpFont
= new SwFont( *rInf
.GetFont() );
410 pTmpFont
->SetVertical( 0, rInf
.GetTxtFrm()->IsVertical() );
413 SwFontSave
aFontSave( rInf
, pTmpFont
);
414 // for text inside drop portions we let vcl handle the text directions
415 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
416 aLayoutModeModifier
.SetAuto();
418 SwTxtPortion::Paint( rInf
);
423 /*************************************************************************
425 *************************************************************************/
428 sal_Bool
SwDropPortion::FormatTxt( SwTxtFormatInfo
&rInf
)
430 const xub_StrLen nOldLen
= GetLen();
431 const xub_StrLen nOldInfLen
= rInf
.GetLen();
432 const sal_Bool bFull
= SwTxtPortion::Format( rInf
);
435 // sieht zwar Scheisse aus, aber was soll man schon machen?
436 rInf
.SetUnderFlow( 0 );
439 rInf
.SetLen( nOldInfLen
);
444 /*************************************************************************
445 * virtual GetTxtSize()
446 *************************************************************************/
449 SwPosSize
SwDropPortion::GetTxtSize( const SwTxtSizeInfo
&rInf
) const
454 const SwDropPortionPart
* pCurrPart
= GetPart();
457 while ( pCurrPart
&& nIdx
+ pCurrPart
->GetLen() < rInf
.GetLen() )
459 nMyX
= nMyX
+ pCurrPart
->GetWidth();
460 nIdx
= nIdx
+ pCurrPart
->GetLen();
461 pCurrPart
= pCurrPart
->GetFollow();
464 xub_StrLen nOldIdx
= rInf
.GetIdx();
465 xub_StrLen nOldLen
= rInf
.GetLen();
467 ((SwTxtSizeInfo
&)rInf
).SetIdx( nIdx
);
468 ((SwTxtSizeInfo
&)rInf
).SetLen( rInf
.GetLen() - nIdx
);
471 SwFontSave
aFontSave( rInf
, pCurrPart
? &pCurrPart
->GetFont() : 0 );
472 SwPosSize
aPosSize( SwTxtPortion::GetTxtSize( rInf
) );
473 aPosSize
.Width( aPosSize
.Width() + nMyX
);
475 ((SwTxtSizeInfo
&)rInf
).SetIdx( nOldIdx
);
476 ((SwTxtSizeInfo
&)rInf
).SetLen( nOldLen
);
481 /*************************************************************************
482 * virtual GetCrsrOfst()
483 *************************************************************************/
485 xub_StrLen
SwDropPortion::GetCrsrOfst( const KSHORT
) const
490 /*************************************************************************
491 * SwTxtFormatter::CalcDropHeight()
492 *************************************************************************/
494 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines
)
496 const SwLinePortion
*const pOldCurr
= GetCurr();
497 KSHORT nDropHght
= 0;
501 sal_Bool bRegisterOld
= IsRegisterOn();
502 bRegisterOn
= sal_False
;
506 while( GetCurr()->IsDummy() )
512 // Wenn wir nur eine Zeile haben returnen wir 0
513 if( GetNext() || GetDropLines() == 1 )
515 for( ; nDropLns
< nLines
; nDropLns
++ )
517 if ( GetCurr()->IsDummy() )
521 CalcAscentAndHeight( nAscent
, nHeight
);
522 nDropHght
= nDropHght
+ nHeight
;
523 bRegisterOn
= bRegisterOld
;
527 nDropLns
++; // Fix: 11356
532 // In der letzten Zeile plumpsen wir auf den Zeilenascent!
533 nDropHght
= nDropHght
- nHeight
;
534 nDropHght
= nDropHght
+ nAscent
;
537 bRegisterOn
= bRegisterOld
;
538 SetDropDescent( nHeight
- nAscent
);
539 SetDropHeight( nDropHght
);
540 SetDropLines( nDropLns
);
541 // Alte Stelle wiederfinden!
542 while( pOldCurr
!= GetCurr() )
546 ASSERT( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
552 /*************************************************************************
553 * SwTxtFormatter::GuessDropHeight()
555 * Wir schaetzen mal, dass die Fonthoehe sich nicht aendert und dass
556 * erst mindestens soviele Zeilen gibt, wie die DropCap-Einstellung angibt.
558 *************************************************************************/
562 void SwTxtFormatter::GuessDropHeight( const MSHORT nLines
)
564 ASSERT( nLines
, "GuessDropHeight: Give me more Lines!" );
567 SetDropLines( nLines
);
568 if ( GetDropLines() > 1 )
571 CalcAscentAndHeight( nAscent
, nHeight
);
573 SetDropDescent( nHeight
- nAscent
);
574 SetDropHeight( nHeight
* nLines
- GetDropDescent() );
577 /*************************************************************************
578 * SwTxtFormatter::NewDropPortion
579 *************************************************************************/
581 SwDropPortion
*SwTxtFormatter::NewDropPortion( SwTxtFormatInfo
&rInf
)
586 xub_StrLen nPorLen
= pDropFmt
->GetWholeWord() ? 0 : pDropFmt
->GetChars();
587 nPorLen
= pFrm
->GetTxtNode()->GetDropLen( nPorLen
);
590 ((SwTxtFormatter
*)this)->ClearDropFmt();
594 SwDropPortion
*pDropPor
= 0;
596 // erste oder zweite Runde?
597 if ( !( GetDropHeight() || IsOnceMore() ) )
600 CalcDropHeight( pDropFmt
->GetLines() );
602 GuessDropHeight( pDropFmt
->GetLines() );
606 if( GetDropHeight() )
607 pDropPor
= new SwDropPortion( GetDropLines(), GetDropHeight(),
608 GetDropDescent(), pDropFmt
->GetDistance() );
610 pDropPor
= new SwDropPortion( 0,0,0,pDropFmt
->GetDistance() );
612 pDropPor
->SetLen( nPorLen
);
614 // If it was not possible to create a proper drop cap portion
615 // due to avoiding endless loops. We return a drop cap portion
616 // with an empty SwDropCapPart. For these portions the current
618 if ( GetDropLines() < 2 )
620 ((SwTxtFormatter
*)this)->SetPaintDrop( sal_True
);
624 // build DropPortionParts:
625 ASSERT( ! rInf
.GetIdx(), "Drop Portion not at 0 position!" );
626 xub_StrLen nNextChg
= 0;
627 const SwCharFmt
* pFmt
= pDropFmt
->GetCharFmt();
628 SwDropPortionPart
* pCurrPart
= 0;
630 while ( nNextChg
< nPorLen
)
632 // check for attribute changes and if the portion has to split:
635 // the font is deleted in the destructor of the drop portion part
636 SwFont
* pTmpFnt
= new SwFont( *rInf
.GetFont() );
639 const SwAttrSet
& rSet
= pFmt
->GetAttrSet();
640 pTmpFnt
->SetDiffFnt( &rSet
, pFrm
->GetTxtNode()->getIDocumentSettingAccess() );
643 // we do not allow a vertical font for the drop portion
644 pTmpFnt
->SetVertical( 0, rInf
.GetTxtFrm()->IsVertical() );
646 // find next attribute change / script change
647 const xub_StrLen nTmpIdx
= nNextChg
;
648 xub_StrLen nNextAttr
= Min( GetNextAttr(), rInf
.GetTxt().Len() );
649 nNextChg
= pScriptInfo
->NextScriptChg( nTmpIdx
);
650 if( nNextChg
> nNextAttr
)
651 nNextChg
= nNextAttr
;
652 if ( nNextChg
> nPorLen
)
655 SwDropPortionPart
* pPart
=
656 new SwDropPortionPart( *pTmpFnt
, nNextChg
- nTmpIdx
);
659 pDropPor
->SetPart( pPart
);
661 pCurrPart
->SetFollow( pPart
);
666 ((SwTxtFormatter
*)this)->SetPaintDrop( sal_True
);
670 /*************************************************************************
671 * SwTxtPainter::PaintDropPortion()
672 *************************************************************************/
676 void SwTxtPainter::PaintDropPortion()
678 const SwDropPortion
*pDrop
= GetInfo().GetParaPortion()->FindDropPortion();
679 ASSERT( pDrop
, "DrapCop-Portion not available." );
683 const SwTwips nOldY
= GetInfo().Y();
687 GetInfo().SetpSpaceAdd( pCurr
->GetpLLSpaceAdd() );
688 GetInfo().ResetSpaceIdx();
689 GetInfo().SetKanaComp( pCurr
->GetpKanaComp() );
690 GetInfo().ResetKanaIdx();
692 // 8047: Drops und Dummies
693 while( !pCurr
->GetLen() && Next() )
696 // MarginPortion und Adjustment!
697 const SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
699 while( pPor
&& !pPor
->IsDropPortion() )
701 nX
= nX
+ pPor
->Width();
702 pPor
= pPor
->GetPortion();
704 Point
aLineOrigin( GetTopLeft() );
707 // Retusche nachholen...
710 const Point
aPoint( Left(), Y() );
711 const Size
aSize( nX
- 1, GetDropHeight()+GetDropDescent() );
712 SwRect
aRetouche( aPoint
, aSize
);
713 GetInfo().DrawRect( aRetouche
);
717 aLineOrigin
.X() += nX
;
718 KSHORT nTmpAscent
, nTmpHeight
;
719 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
720 aLineOrigin
.Y() += nTmpAscent
;
721 GetInfo().SetIdx( GetStart() );
722 GetInfo().SetPos( aLineOrigin
);
723 GetInfo().SetLen( pDrop
->GetLen() );
725 pDrop
->PaintDrop( GetInfo() );
727 GetInfo().Y( nOldY
);
730 /*************************************************************************
731 * clas SwDropCapCache
733 * Da die Berechnung der Fontgroesse der Initialen ein teures Geschaeft ist,
734 * wird dies durch einen DropCapCache geschleust.
735 *************************************************************************/
737 #define DROP_CACHE_SIZE 10
741 long aMagicNo
[ DROP_CACHE_SIZE
];
742 XubString aTxt
[ DROP_CACHE_SIZE
];
743 USHORT aFactor
[ DROP_CACHE_SIZE
];
744 KSHORT aWishedHeight
[ DROP_CACHE_SIZE
];
745 short aDescent
[ DROP_CACHE_SIZE
];
750 void CalcFontSize( SwDropPortion
* pDrop
, SwTxtFormatInfo
&rInf
);
753 /*************************************************************************
754 * SwDropCapCache Ctor / Dtor
755 *************************************************************************/
757 SwDropCapCache::SwDropCapCache() : nIndex( 0 )
759 memset( &aMagicNo
, 0, sizeof(aMagicNo
) );
760 memset( &aWishedHeight
, 0, sizeof(aWishedHeight
) );
763 void SwDropPortion::DeleteDropCapCache()
765 delete pDropCapCache
;
768 /*************************************************************************
769 * SwDropCapCache::CalcFontSize
770 *************************************************************************/
772 void SwDropCapCache::CalcFontSize( SwDropPortion
* pDrop
, SwTxtFormatInfo
&rInf
)
774 const void* pFntNo
= 0;
777 ASSERT( pDrop
->GetPart(),"DropPortion without part during font calculation");
779 SwDropPortionPart
* pCurrPart
= pDrop
->GetPart();
780 const sal_Bool bUseCache
= ! pCurrPart
->GetFollow();
781 xub_StrLen nIdx
= rInf
.GetIdx();
782 XubString
aStr( rInf
.GetTxt(), nIdx
, pCurrPart
->GetLen() );
790 SwFont
& rFnt
= pCurrPart
->GetFont();
791 rFnt
.ChkMagic( rInf
.GetVsh(), rFnt
.GetActual() );
792 rFnt
.GetMagic( pFntNo
, nTmpIdx
, rFnt
.GetActual() );
796 while( nTmpIdx
< DROP_CACHE_SIZE
&&
797 ( aTxt
[ nTmpIdx
] != aStr
|| aMagicNo
[ nTmpIdx
] != long(pFntNo
) ||
798 aWishedHeight
[ nTmpIdx
] != pDrop
->GetDropHeight() ) )
802 // we have to calculate a new font scaling factor if
803 // 1. we did not find a scaling factor in the cache or
804 // 2. we are not allowed to use the cache because the drop portion
805 // consists of more than one part
806 if( nTmpIdx
>= DROP_CACHE_SIZE
|| ! bUseCache
)
809 nIndex
%= DROP_CACHE_SIZE
;
812 long nWishedHeight
= pDrop
->GetDropHeight();
814 // find out biggest font size for initial scaling factor
815 long nMaxFontHeight
= 0;
818 const SwFont
& rFnt
= pCurrPart
->GetFont();
819 const long nCurrHeight
= rFnt
.GetHeight( rFnt
.GetActual() );
820 if ( nCurrHeight
> nMaxFontHeight
)
821 nMaxFontHeight
= nCurrHeight
;
823 pCurrPart
= pCurrPart
->GetFollow();
826 nFactor
= ( 1000 * nWishedHeight
) / nMaxFontHeight
;
830 // save keys for cache
831 aMagicNo
[ nTmpIdx
] = long(pFntNo
);
832 aTxt
[ nTmpIdx
] = aStr
;
833 aWishedHeight
[ nTmpIdx
] = KSHORT(nWishedHeight
);
834 // save initial scaling factor
835 aFactor
[ nTmpIdx
] = (USHORT
)nFactor
;
838 sal_Bool bGrow
= ( pDrop
->GetLen() != 0 );
840 // for growing controll
841 long nMax
= KSHRT_MAX
;
842 long nMin
= nFactor
/ 2;
843 #if OSL_DEBUG_LEVEL > 1
847 sal_Bool bWinUsed
= sal_False
;
849 MapMode
aOldMap( MAP_TWIP
);
850 OutputDevice
* pOut
= rInf
.GetOut();
852 if( rInf
.GetVsh() && rInf
.GetVsh()->GetWin() )
853 pWin
= rInf
.GetVsh()->GetWin();
855 pWin
= GetpApp()->GetDefaultDevice();
859 // reset pCurrPart to first part
860 pCurrPart
= pDrop
->GetPart();
861 sal_Bool bFirstGlyphRect
= sal_True
;
862 sal_Bool bHaveGlyphRect
= sal_False
;
863 Rectangle aCommonRect
, aRect
;
868 SwFont
& rFnt
= pCurrPart
->GetFont();
870 // Get height including proportion
871 const USHORT nCurrHeight
=
872 (USHORT
)rFnt
.GetHeight( rFnt
.GetActual() );
874 // Get without proportion
875 const BYTE nOldProp
= rFnt
.GetPropr();
876 rFnt
.SetProportion( 100 );
877 Size aOldSize
= Size( 0, rFnt
.GetHeight( rFnt
.GetActual() ) );
879 Size
aNewSize( 0, ( nFactor
* nCurrHeight
) / 1000 );
880 rFnt
.SetSize( aNewSize
, rFnt
.GetActual() );
881 rFnt
.ChgPhysFnt( rInf
.GetVsh(), *pOut
);
883 nAscent
= rFnt
.GetAscent( rInf
.GetVsh(), *pOut
);
885 // Wir besorgen uns das alle Buchstaben umfassende Rechteck:
886 bHaveGlyphRect
= pOut
->GetTextBoundRect( aRect
, rInf
.GetTxt(), 0,
887 nIdx
, pCurrPart
->GetLen() ) &&
890 if ( ! bHaveGlyphRect
)
892 // getting glyph boundaries failed for some reason,
893 // we take the window for calculating sizes
899 aOldMap
= pWin
->GetMapMode( );
900 pWin
->SetMapMode( MapMode( MAP_TWIP
) );
901 aOldFnt
= pWin
->GetFont();
903 pWin
->SetFont( rFnt
.GetActualFont() );
905 bHaveGlyphRect
= pWin
->GetTextBoundRect( aRect
, rInf
.GetTxt(), 0,
906 nIdx
, pCurrPart
->GetLen() ) &&
909 if ( bHaveGlyphRect
)
911 FontMetric
aWinMet( pWin
->GetFontMetric() );
912 nAscent
= (KSHORT
) aWinMet
.GetAscent();
915 // We do not have a window or our window could not
916 // give us glyph boundaries.
917 aRect
= Rectangle( Point( 0, 0 ), Size( 0, nAscent
) );
920 // Now we (hopefully) have a bounding rectangle for the
921 // glyphs of the current portion and the ascent of the current
924 // reset font size and proportion
925 rFnt
.SetSize( aOldSize
, rFnt
.GetActual() );
926 rFnt
.SetProportion( nOldProp
);
928 if ( bFirstGlyphRect
)
931 bFirstGlyphRect
= sal_False
;
934 aCommonRect
.Union( aRect
);
936 nIdx
= nIdx
+ pCurrPart
->GetLen();
937 pCurrPart
= pCurrPart
->GetFollow();
940 // now we have a union ( aCommonRect ) of all glyphs with
941 // respect to a common baseline : 0
943 // get descent and ascent from union
944 if ( rInf
.GetTxtFrm()->IsVertical() )
946 nDescent
= aCommonRect
.Left();
947 nAscent
= aCommonRect
.Right();
950 nDescent
= -nDescent
;
954 nDescent
= aCommonRect
.Bottom();
955 nAscent
= aCommonRect
.Top();
960 const long nHght
= nAscent
+ nDescent
;
963 if ( nHght
> nWishedHeight
)
968 aFactor
[ nTmpIdx
] = (USHORT
)nFactor
;
972 nFactor
= ( nFactor
* nWishedHeight
) / nHght
;
973 bGrow
= ( nFactor
> nMin
) && ( nFactor
< nMax
);
974 #if OSL_DEBUG_LEVEL > 1
978 nIdx
= rInf
.GetIdx();
986 // reset window if it has been used
987 pWin
->SetMapMode( aOldMap
);
988 pWin
->SetFont( aOldFnt
);
992 aDescent
[ nTmpIdx
] = -short( nDescent
);
995 pCurrPart
= pDrop
->GetPart();
997 // did made any new calculations or did we use the cache?
1000 nFactor
= aFactor
[ nTmpIdx
];
1001 nDescent
= aDescent
[ nTmpIdx
];
1004 nDescent
= -nDescent
;
1008 // scale current font
1009 SwFont
& rFnt
= pCurrPart
->GetFont();
1010 Size
aNewSize( 0, ( nFactor
* rFnt
.GetHeight( rFnt
.GetActual() ) ) / 1000 );
1012 const BYTE nOldProp
= rFnt
.GetPropr();
1013 rFnt
.SetProportion( 100 );
1014 rFnt
.SetSize( aNewSize
, rFnt
.GetActual() );
1015 rFnt
.SetProportion( nOldProp
);
1017 pCurrPart
= pCurrPart
->GetFollow();
1019 pDrop
->SetY( (short)nDescent
);
1022 /*************************************************************************
1024 *************************************************************************/
1026 sal_Bool
SwDropPortion::Format( SwTxtFormatInfo
&rInf
)
1028 sal_Bool bFull
= sal_False
;
1029 Fix( (USHORT
)rInf
.X() );
1031 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
1032 aLayoutModeModifier
.SetAuto();
1034 if( nDropHeight
&& pPart
&& nLines
!=1 )
1036 if( !pDropCapCache
)
1037 pDropCapCache
= new SwDropCapCache();
1039 // adjust font sizes to fit into the rectangle
1040 pDropCapCache
->CalcFontSize( this, rInf
);
1042 const long nOldX
= rInf
.X();
1044 SwDropSave
aSave( rInf
);
1045 SwDropPortionPart
* pCurrPart
= pPart
;
1049 rInf
.SetLen( pCurrPart
->GetLen() );
1050 SwFont
& rFnt
= pCurrPart
->GetFont();
1052 SwFontSave
aFontSave( rInf
, &rFnt
);
1053 bFull
= FormatTxt( rInf
);
1059 const SwTwips nTmpWidth
=
1060 ( InSpaceGrp() && rInf
.GetSpaceAdd() ) ?
1061 Width() + CalcSpacing( rInf
.GetSpaceAdd(), rInf
) :
1065 pCurrPart
->SetWidth( (USHORT
)nTmpWidth
);
1068 rInf
.SetIdx( rInf
.GetIdx() + pCurrPart
->GetLen() );
1069 rInf
.X( rInf
.X() + nTmpWidth
);
1070 pCurrPart
= pCurrPart
->GetFollow();
1073 Width( (USHORT
)(rInf
.X() - nOldX
) );
1077 SetLen( rInf
.GetLen() );
1079 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1081 bFull
= lcl_IsDropFlyInter( rInf
, Width(), nDropHeight
);
1085 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1087 Height( rInf
.GetTxtHeight() );
1089 // Jetzt noch einmal der ganze Spass
1090 nDropHeight
= nLines
= 0;
1094 // meanwhile use normal formatting
1095 bFull
= SwTxtPortion::Format( rInf
);
1098 rInf
.SetDropInit( sal_True
);
1100 Height( rInf
.GetTxtHeight() );
1101 SetAscent( rInf
.GetAscent() );
1104 bFull
= SwTxtPortion::Format( rInf
);
1110 const KSHORT nWant
= Width() + GetDistance();
1111 const KSHORT nRest
= (USHORT
)(rInf
.Width() - rInf
.X());
1112 if( ( nWant
> nRest
) ||
1113 lcl_IsDropFlyInter( rInf
, Width() + GetDistance(), nDropHeight
) )
1116 Width( Width() + nDistance
);