1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <vcl/metric.hxx>
22 #include <vcl/window.hxx>
23 #include <vcl/svapp.hxx>
25 #include <txtfrm.hxx> // Format()
26 #include <charfmt.hxx>
27 #include <viewopt.hxx> // SwViewOption
28 #include <viewsh.hxx> // ViewShell
29 #include <pordrop.hxx>
30 #include <itrform2.hxx>
31 #include <txtpaint.hxx> // SwSaveClip
32 #include <blink.hxx> // pBlink
33 #include <breakit.hxx>
34 #include <com/sun/star/i18n/ScriptType.hpp>
35 #include <com/sun/star/i18n/WordType.hpp>
36 #include <editeng/langitem.hxx>
37 #include <charatr.hxx>
38 #include <editeng/fhgtitem.hxx>
39 #include <switerator.hxx>
41 using namespace ::com::sun::star::i18n
;
42 using namespace ::com::sun::star
;
44 /*************************************************************************
47 * Calculates if a drop caps portion intersects with a fly
48 * The width and height of the drop caps portion are passed as arguments,
49 * the position is calculated from the values in rInf
50 *************************************************************************/
52 static sal_Bool
lcl_IsDropFlyInter( const SwTxtFormatInfo
&rInf
,
53 sal_uInt16 nWidth
, sal_uInt16 nHeight
)
55 const SwTxtFly
*pTxtFly
= rInf
.GetTxtFly();
56 if( pTxtFly
&& pTxtFly
->IsOn() )
58 SwRect
aRect( rInf
.GetTxtFrm()->Frm().Pos(), Size( nWidth
, nHeight
) );
59 aRect
.Pos() += rInf
.GetTxtFrm()->Prt().Pos();
60 aRect
.Pos().X() += rInf
.X();
61 aRect
.Pos().Y() = rInf
.Y();
62 aRect
= pTxtFly
->GetFrm( aRect
);
63 return aRect
.HasArea();
69 /*************************************************************************
71 *************************************************************************/
82 SwDropSave( const SwTxtPaintInfo
&rInf
);
86 SwDropSave::SwDropSave( const SwTxtPaintInfo
&rInf
) :
87 pInf( ((SwTxtPaintInfo
*)&rInf
) ), nIdx( rInf
.GetIdx() ),
88 nLen( rInf
.GetLen() ), nX( rInf
.X() ), nY( rInf
.Y() )
92 SwDropSave::~SwDropSave()
100 /*************************************************************************
101 * SwDropPortionPart DTor
102 *************************************************************************/
104 SwDropPortionPart::~SwDropPortionPart()
110 /*************************************************************************
111 * SwDropPortion CTor, DTor
112 *************************************************************************/
114 SwDropPortion::SwDropPortion( const MSHORT nLineCnt
,
115 const KSHORT nDrpHeight
,
116 const KSHORT nDrpDescent
,
120 nDropHeight(nDrpHeight
),
121 nDropDescent(nDrpDescent
),
126 SetWhichPor( POR_DROP
);
129 SwDropPortion::~SwDropPortion()
133 pBlink
->Delete( this );
136 sal_Bool
SwTxtSizeInfo::_HasHint( const SwTxtNode
* pTxtNode
, xub_StrLen nPos
)
138 return 0 != pTxtNode
->GetTxtAttrForCharAt(nPos
);
141 /*************************************************************************
142 * SwTxtNode::GetDropLen()
144 * nWishLen = 0 indicates that we want a whole word
145 *************************************************************************/
147 MSHORT
SwTxtNode::GetDropLen( MSHORT nWishLen
) const
149 xub_StrLen nEnd
= GetTxt().Len();
150 if( nWishLen
&& nWishLen
< nEnd
)
153 if ( ! nWishLen
&& pBreakIt
->GetBreakIter().is() )
156 const SwAttrSet
& rAttrSet
= GetSwAttrSet();
157 const sal_uInt16 nTxtScript
= pBreakIt
->GetRealScriptOfText( GetTxt(), 0 );
159 LanguageType eLanguage
;
161 switch ( nTxtScript
)
163 case i18n::ScriptType::ASIAN
:
164 eLanguage
= rAttrSet
.GetCJKLanguage().GetLanguage();
166 case i18n::ScriptType::COMPLEX
:
167 eLanguage
= rAttrSet
.GetCTLLanguage().GetLanguage();
170 eLanguage
= rAttrSet
.GetLanguage().GetLanguage();
175 pBreakIt
->GetBreakIter()->getWordBoundary( GetTxt(), 0,
176 pBreakIt
->GetLocale( eLanguage
), WordType::DICTIONARY_WORD
, sal_True
);
178 nEnd
= (xub_StrLen
)aBound
.endPos
;
182 for( ; i
< nEnd
; ++i
)
184 sal_Unicode cChar
= GetTxt().GetChar( i
);
185 if( CH_TAB
== cChar
|| CH_BREAK
== cChar
||
186 (( CH_TXTATR_BREAKWORD
== cChar
|| CH_TXTATR_INWORD
== cChar
)
187 && SwTxtSizeInfo::_HasHint( this, i
) ) )
193 /*************************************************************************
194 * SwTxtNode::GetDropSize()
196 * If a dropcap is found the return value is true otherwise false. The
197 * drop cap sizes passed back by reference are font height, drop height
199 *************************************************************************/
200 bool SwTxtNode::GetDropSize(int& rFontHeight
, int& rDropHeight
, int& rDropDescent
) const
206 const SwAttrSet
& rSet
= GetSwAttrSet();
207 const SwFmtDrop
& rDrop
= rSet
.GetDrop();
209 // Return (0,0) if there is no drop cap at this paragraph
210 if( 1 >= rDrop
.GetLines() ||
211 ( !rDrop
.GetChars() && !rDrop
.GetWholeWord() ) )
217 SwIterator
<SwTxtFrm
,SwTxtNode
> aIter( *this );
218 for( SwTxtFrm
* pLastFrm
= aIter
.First(); pLastFrm
; pLastFrm
= aIter
.Next() )
220 // Only (master-) text frames can have a drop cap.
221 if ( !pLastFrm
->IsFollow() )
224 if( !pLastFrm
->HasPara() )
225 pLastFrm
->GetFormatted();
227 if ( !pLastFrm
->IsEmpty() )
229 const SwParaPortion
* pPara
= pLastFrm
->GetPara();
230 OSL_ENSURE( pPara
, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" );
234 const SwLinePortion
* pFirstPor
= pPara
->GetFirstPortion();
235 if (pFirstPor
&& pFirstPor
->IsDropPortion())
237 const SwDropPortion
* pDrop
= (const SwDropPortion
*)pFirstPor
;
238 rDropHeight
= pDrop
->GetDropHeight();
239 rDropDescent
= pDrop
->GetDropDescent();
240 if (const SwFont
*pFont
= pDrop
->GetFnt())
241 rFontHeight
= pFont
->GetSize(pFont
->GetActual()).Height();
244 const SvxFontHeightItem
& rItem
= (SvxFontHeightItem
&)rSet
.Get(RES_CHRATR_FONTSIZE
);
245 rFontHeight
= rItem
.GetHeight();
254 if (rFontHeight
==0 && rDropHeight
==0 && rDropDescent
==0)
256 const sal_uInt16 nLines
= rDrop
.GetLines();
258 const SvxFontHeightItem
& rItem
= (SvxFontHeightItem
&)rSet
.Get( RES_CHRATR_FONTSIZE
);
259 rFontHeight
= rItem
.GetHeight();
260 rDropHeight
= nLines
* rFontHeight
;
261 rDropDescent
= rFontHeight
/ 5;
268 /*************************************************************************
269 * SwDropPortion::PaintTxt()
270 *************************************************************************/
272 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
274 void SwDropPortion::PaintTxt( const SwTxtPaintInfo
&rInf
) const
277 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
278 rInf
.DrawBackground( *this );
280 OSL_ENSURE( nDropHeight
&& pPart
&& nLines
!= 1, "Drop Portion painted twice" );
282 const SwDropPortionPart
* pCurrPart
= GetPart();
283 const xub_StrLen nOldLen
= GetLen();
285 const SwTwips nBasePosY
= rInf
.Y();
286 ((SwTxtPaintInfo
&)rInf
).Y( nBasePosY
+ nY
);
287 SwDropSave
aSave( rInf
);
288 // for text inside drop portions we let vcl handle the text directions
289 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
290 aLayoutModeModifier
.SetAuto();
294 ((SwDropPortion
*)this)->SetLen( pCurrPart
->GetLen() );
295 ((SwTxtPaintInfo
&)rInf
).SetLen( pCurrPart
->GetLen() );
296 SwFontSave
aFontSave( rInf
, &pCurrPart
->GetFont() );
298 SwTxtPortion::Paint( rInf
);
300 ((SwTxtPaintInfo
&)rInf
).SetIdx( rInf
.GetIdx() + pCurrPart
->GetLen() );
301 ((SwTxtPaintInfo
&)rInf
).X( rInf
.X() + pCurrPart
->GetWidth() );
302 pCurrPart
= pCurrPart
->GetFollow();
305 ((SwTxtPaintInfo
&)rInf
).Y( nBasePosY
);
306 ((SwDropPortion
*)this)->SetLen( nOldLen
);
309 /*************************************************************************
310 * SwDropPortion::Paint()
311 *************************************************************************/
313 void SwDropPortion::PaintDrop( const SwTxtPaintInfo
&rInf
) const
315 // ganz normale Ausgabe wird w?hrend des normalen Paints erledigt
316 if( ! nDropHeight
|| ! pPart
|| nLines
== 1 )
319 // Luegenwerte einstellen!
320 const KSHORT nOldHeight
= Height();
321 const KSHORT nOldWidth
= Width();
322 const KSHORT nOldAscent
= GetAscent();
323 const SwTwips nOldPosY
= rInf
.Y();
324 const KSHORT nOldPosX
= (KSHORT
)rInf
.X();
325 const SwParaPortion
*pPara
= rInf
.GetParaPortion();
326 const Point
aOutPos( nOldPosX
+ nX
, nOldPosY
- pPara
->GetAscent()
327 - pPara
->GetRealHeight() + pPara
->Height() );
328 // Retusche nachholen.
331 ((SwTxtPaintInfo
&)rInf
).Y( aOutPos
.Y() + nDropHeight
);
334 ((SwDropPortion
*)this)->Height( nDropHeight
+ nDropDescent
);
335 ((SwDropPortion
*)this)->Width( Width() - nX
);
336 ((SwDropPortion
*)this)->SetAscent( nDropHeight
);
338 // Clipregion auf uns einstellen!
339 // Und zwar immer, und nie mit dem bestehenden ClipRect
340 // verrechnen, weil dies auf die Zeile eingestellt sein koennte.
345 aClipRect
= SwRect( aOutPos
, SvLSize() );
346 aClipRect
.Intersection( rInf
.GetPaintRect() );
348 SwSaveClip
aClip( (OutputDevice
*)rInf
.GetOut() );
349 aClip
.ChgClip( aClipRect
, rInf
.GetTxtFrm() );
350 // Das machen, was man sonst nur macht ...
353 // Alte Werte sichern
354 ((SwDropPortion
*)this)->Height( nOldHeight
);
355 ((SwDropPortion
*)this)->Width( nOldWidth
);
356 ((SwDropPortion
*)this)->SetAscent( nOldAscent
);
357 ((SwTxtPaintInfo
&)rInf
).Y( nOldPosY
);
360 /*************************************************************************
361 * virtual SwDropPortion::Paint()
362 *************************************************************************/
364 void SwDropPortion::Paint( const SwTxtPaintInfo
&rInf
) const
366 // ganz normale Ausgabe wird hier erledigt.
367 if( ! nDropHeight
|| ! pPart
|| 1 == nLines
)
370 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
371 rInf
.DrawBackground( *this );
373 // make sure that font is not rotated
374 SwFont
* pTmpFont
= 0;
375 if ( rInf
.GetFont()->GetOrientation( rInf
.GetTxtFrm()->IsVertical() ) )
377 pTmpFont
= new SwFont( *rInf
.GetFont() );
378 pTmpFont
->SetVertical( 0, rInf
.GetTxtFrm()->IsVertical() );
381 SwFontSave
aFontSave( rInf
, pTmpFont
);
382 // for text inside drop portions we let vcl handle the text directions
383 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
384 aLayoutModeModifier
.SetAuto();
386 SwTxtPortion::Paint( rInf
);
391 /*************************************************************************
393 *************************************************************************/
396 sal_Bool
SwDropPortion::FormatTxt( SwTxtFormatInfo
&rInf
)
398 const xub_StrLen nOldLen
= GetLen();
399 const xub_StrLen nOldInfLen
= rInf
.GetLen();
400 const sal_Bool bFull
= SwTxtPortion::Format( rInf
);
403 // sieht zwar Scheisse aus, aber was soll man schon machen?
404 rInf
.SetUnderFlow( 0 );
407 rInf
.SetLen( nOldInfLen
);
412 /*************************************************************************
413 * virtual GetTxtSize()
414 *************************************************************************/
417 SwPosSize
SwDropPortion::GetTxtSize( const SwTxtSizeInfo
&rInf
) const
422 const SwDropPortionPart
* pCurrPart
= GetPart();
425 while ( pCurrPart
&& nIdx
+ pCurrPart
->GetLen() < rInf
.GetLen() )
427 nMyX
= nMyX
+ pCurrPart
->GetWidth();
428 nIdx
= nIdx
+ pCurrPart
->GetLen();
429 pCurrPart
= pCurrPart
->GetFollow();
432 xub_StrLen nOldIdx
= rInf
.GetIdx();
433 xub_StrLen nOldLen
= rInf
.GetLen();
435 ((SwTxtSizeInfo
&)rInf
).SetIdx( nIdx
);
436 ((SwTxtSizeInfo
&)rInf
).SetLen( rInf
.GetLen() - nIdx
);
439 SwFontSave
aFontSave( rInf
, pCurrPart
? &pCurrPart
->GetFont() : 0 );
440 SwPosSize
aPosSize( SwTxtPortion::GetTxtSize( rInf
) );
441 aPosSize
.Width( aPosSize
.Width() + nMyX
);
443 ((SwTxtSizeInfo
&)rInf
).SetIdx( nOldIdx
);
444 ((SwTxtSizeInfo
&)rInf
).SetLen( nOldLen
);
449 /*************************************************************************
450 * virtual GetCrsrOfst()
451 *************************************************************************/
453 xub_StrLen
SwDropPortion::GetCrsrOfst( const KSHORT
) const
458 /*************************************************************************
459 * SwTxtFormatter::CalcDropHeight()
460 *************************************************************************/
462 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines
)
464 const SwLinePortion
*const pOldCurr
= GetCurr();
465 KSHORT nDropHght
= 0;
469 sal_Bool bRegisterOld
= IsRegisterOn();
470 bRegisterOn
= sal_False
;
474 while( GetCurr()->IsDummy() )
480 // Wenn wir nur eine Zeile haben returnen wir 0
481 if( GetNext() || GetDropLines() == 1 )
483 for( ; nDropLns
< nLines
; nDropLns
++ )
485 if ( GetCurr()->IsDummy() )
489 CalcAscentAndHeight( nAscent
, nHeight
);
490 nDropHght
= nDropHght
+ nHeight
;
491 bRegisterOn
= bRegisterOld
;
495 nDropLns
++; // Fix: 11356
500 // In der letzten Zeile plumpsen wir auf den Zeilenascent!
501 nDropHght
= nDropHght
- nHeight
;
502 nDropHght
= nDropHght
+ nAscent
;
505 bRegisterOn
= bRegisterOld
;
506 SetDropDescent( nHeight
- nAscent
);
507 SetDropHeight( nDropHght
);
508 SetDropLines( nDropLns
);
509 // Alte Stelle wiederfinden!
510 while( pOldCurr
!= GetCurr() )
514 OSL_ENSURE( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
520 /*************************************************************************
521 * SwTxtFormatter::GuessDropHeight()
523 * Wir schaetzen mal, dass die Fonthoehe sich nicht aendert und dass
524 * erst mindestens soviele Zeilen gibt, wie die DropCap-Einstellung angibt.
526 *************************************************************************/
530 void SwTxtFormatter::GuessDropHeight( const MSHORT nLines
)
532 OSL_ENSURE( nLines
, "GuessDropHeight: Give me more Lines!" );
535 SetDropLines( nLines
);
536 if ( GetDropLines() > 1 )
539 CalcAscentAndHeight( nAscent
, nHeight
);
541 SetDropDescent( nHeight
- nAscent
);
542 SetDropHeight( nHeight
* nLines
- GetDropDescent() );
545 /*************************************************************************
546 * SwTxtFormatter::NewDropPortion
547 *************************************************************************/
549 SwDropPortion
*SwTxtFormatter::NewDropPortion( SwTxtFormatInfo
&rInf
)
554 xub_StrLen nPorLen
= pDropFmt
->GetWholeWord() ? 0 : pDropFmt
->GetChars();
555 nPorLen
= pFrm
->GetTxtNode()->GetDropLen( nPorLen
);
558 ((SwTxtFormatter
*)this)->ClearDropFmt();
562 SwDropPortion
*pDropPor
= 0;
564 // erste oder zweite Runde?
565 if ( !( GetDropHeight() || IsOnceMore() ) )
568 CalcDropHeight( pDropFmt
->GetLines() );
570 GuessDropHeight( pDropFmt
->GetLines() );
574 if( GetDropHeight() )
575 pDropPor
= new SwDropPortion( GetDropLines(), GetDropHeight(),
576 GetDropDescent(), pDropFmt
->GetDistance() );
578 pDropPor
= new SwDropPortion( 0,0,0,pDropFmt
->GetDistance() );
580 pDropPor
->SetLen( nPorLen
);
582 // If it was not possible to create a proper drop cap portion
583 // due to avoiding endless loops. We return a drop cap portion
584 // with an empty SwDropCapPart. For these portions the current
586 if ( GetDropLines() < 2 )
588 ((SwTxtFormatter
*)this)->SetPaintDrop( sal_True
);
592 // build DropPortionParts:
593 OSL_ENSURE( ! rInf
.GetIdx(), "Drop Portion not at 0 position!" );
594 xub_StrLen nNextChg
= 0;
595 const SwCharFmt
* pFmt
= pDropFmt
->GetCharFmt();
596 SwDropPortionPart
* pCurrPart
= 0;
598 while ( nNextChg
< nPorLen
)
600 // check for attribute changes and if the portion has to split:
603 // the font is deleted in the destructor of the drop portion part
604 SwFont
* pTmpFnt
= new SwFont( *rInf
.GetFont() );
607 const SwAttrSet
& rSet
= pFmt
->GetAttrSet();
608 pTmpFnt
->SetDiffFnt( &rSet
, pFrm
->GetTxtNode()->getIDocumentSettingAccess() );
611 // we do not allow a vertical font for the drop portion
612 pTmpFnt
->SetVertical( 0, rInf
.GetTxtFrm()->IsVertical() );
614 // find next attribute change / script change
615 const xub_StrLen nTmpIdx
= nNextChg
;
616 xub_StrLen nNextAttr
= Min( GetNextAttr(), rInf
.GetTxt().Len() );
617 nNextChg
= pScriptInfo
->NextScriptChg( nTmpIdx
);
618 if( nNextChg
> nNextAttr
)
619 nNextChg
= nNextAttr
;
620 if ( nNextChg
> nPorLen
)
623 SwDropPortionPart
* pPart
=
624 new SwDropPortionPart( *pTmpFnt
, nNextChg
- nTmpIdx
);
627 pDropPor
->SetPart( pPart
);
629 pCurrPart
->SetFollow( pPart
);
634 ((SwTxtFormatter
*)this)->SetPaintDrop( sal_True
);
638 /*************************************************************************
639 * SwTxtPainter::PaintDropPortion()
640 *************************************************************************/
644 void SwTxtPainter::PaintDropPortion()
646 const SwDropPortion
*pDrop
= GetInfo().GetParaPortion()->FindDropPortion();
647 OSL_ENSURE( pDrop
, "DrapCop-Portion not available." );
651 const SwTwips nOldY
= GetInfo().Y();
655 GetInfo().SetpSpaceAdd( pCurr
->GetpLLSpaceAdd() );
656 GetInfo().ResetSpaceIdx();
657 GetInfo().SetKanaComp( pCurr
->GetpKanaComp() );
658 GetInfo().ResetKanaIdx();
660 // 8047: Drops und Dummies
661 while( !pCurr
->GetLen() && Next() )
664 // MarginPortion und Adjustment!
665 const SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
667 while( pPor
&& !pPor
->IsDropPortion() )
669 nX
= nX
+ pPor
->Width();
670 pPor
= pPor
->GetPortion();
672 Point
aLineOrigin( GetTopLeft() );
674 aLineOrigin
.X() += nX
;
675 KSHORT nTmpAscent
, nTmpHeight
;
676 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
677 aLineOrigin
.Y() += nTmpAscent
;
678 GetInfo().SetIdx( GetStart() );
679 GetInfo().SetPos( aLineOrigin
);
680 GetInfo().SetLen( pDrop
->GetLen() );
682 pDrop
->PaintDrop( GetInfo() );
684 GetInfo().Y( nOldY
);
687 /*************************************************************************
688 * clas SwDropCapCache
690 * Da die Berechnung der Fontgroesse der Initialen ein teures Geschaeft ist,
691 * wird dies durch einen DropCapCache geschleust.
692 *************************************************************************/
694 #define DROP_CACHE_SIZE 10
698 long aMagicNo
[ DROP_CACHE_SIZE
];
699 XubString aTxt
[ DROP_CACHE_SIZE
];
700 sal_uInt16 aFactor
[ DROP_CACHE_SIZE
];
701 KSHORT aWishedHeight
[ DROP_CACHE_SIZE
];
702 short aDescent
[ DROP_CACHE_SIZE
];
707 void CalcFontSize( SwDropPortion
* pDrop
, SwTxtFormatInfo
&rInf
);
710 /*************************************************************************
711 * SwDropCapCache Ctor / Dtor
712 *************************************************************************/
714 SwDropCapCache::SwDropCapCache() : nIndex( 0 )
716 memset( &aMagicNo
, 0, sizeof(aMagicNo
) );
717 memset( &aWishedHeight
, 0, sizeof(aWishedHeight
) );
720 void SwDropPortion::DeleteDropCapCache()
722 delete pDropCapCache
;
725 /*************************************************************************
726 * SwDropCapCache::CalcFontSize
727 *************************************************************************/
729 void SwDropCapCache::CalcFontSize( SwDropPortion
* pDrop
, SwTxtFormatInfo
&rInf
)
731 const void* pFntNo
= 0;
734 OSL_ENSURE( pDrop
->GetPart(),"DropPortion without part during font calculation");
736 SwDropPortionPart
* pCurrPart
= pDrop
->GetPart();
737 const sal_Bool bUseCache
= ! pCurrPart
->GetFollow();
738 xub_StrLen nIdx
= rInf
.GetIdx();
739 XubString
aStr( rInf
.GetTxt(), nIdx
, pCurrPart
->GetLen() );
747 SwFont
& rFnt
= pCurrPart
->GetFont();
748 rFnt
.ChkMagic( rInf
.GetVsh(), rFnt
.GetActual() );
749 rFnt
.GetMagic( pFntNo
, nTmpIdx
, rFnt
.GetActual() );
753 while( nTmpIdx
< DROP_CACHE_SIZE
&&
754 ( aTxt
[ nTmpIdx
] != aStr
|| aMagicNo
[ nTmpIdx
] != long(pFntNo
) ||
755 aWishedHeight
[ nTmpIdx
] != pDrop
->GetDropHeight() ) )
759 // we have to calculate a new font scaling factor if
760 // 1. we did not find a scaling factor in the cache or
761 // 2. we are not allowed to use the cache because the drop portion
762 // consists of more than one part
763 if( nTmpIdx
>= DROP_CACHE_SIZE
|| ! bUseCache
)
766 nIndex
%= DROP_CACHE_SIZE
;
769 long nWishedHeight
= pDrop
->GetDropHeight();
771 // find out biggest font size for initial scaling factor
772 long nMaxFontHeight
= 0;
775 const SwFont
& rFnt
= pCurrPart
->GetFont();
776 const long nCurrHeight
= rFnt
.GetHeight( rFnt
.GetActual() );
777 if ( nCurrHeight
> nMaxFontHeight
)
778 nMaxFontHeight
= nCurrHeight
;
780 pCurrPart
= pCurrPart
->GetFollow();
783 nFactor
= ( 1000 * nWishedHeight
) / nMaxFontHeight
;
787 // save keys for cache
788 aMagicNo
[ nTmpIdx
] = long(pFntNo
);
789 aTxt
[ nTmpIdx
] = aStr
;
790 aWishedHeight
[ nTmpIdx
] = KSHORT(nWishedHeight
);
791 // save initial scaling factor
792 aFactor
[ nTmpIdx
] = (sal_uInt16
)nFactor
;
795 sal_Bool bGrow
= ( pDrop
->GetLen() != 0 );
797 // for growing controll
798 long nMax
= KSHRT_MAX
;
799 long nMin
= nFactor
/ 2;
800 #if OSL_DEBUG_LEVEL > 1
804 sal_Bool bWinUsed
= sal_False
;
806 MapMode
aOldMap( MAP_TWIP
);
807 OutputDevice
* pOut
= rInf
.GetOut();
809 if( rInf
.GetVsh() && rInf
.GetVsh()->GetWin() )
810 pWin
= rInf
.GetVsh()->GetWin();
812 pWin
= GetpApp()->GetDefaultDevice();
816 // reset pCurrPart to first part
817 pCurrPart
= pDrop
->GetPart();
818 sal_Bool bFirstGlyphRect
= sal_True
;
819 sal_Bool bHaveGlyphRect
= sal_False
;
820 Rectangle aCommonRect
, aRect
;
825 SwFont
& rFnt
= pCurrPart
->GetFont();
827 // Get height including proportion
828 const sal_uInt16 nCurrHeight
=
829 (sal_uInt16
)rFnt
.GetHeight( rFnt
.GetActual() );
831 // Get without proportion
832 const sal_uInt8 nOldProp
= rFnt
.GetPropr();
833 rFnt
.SetProportion( 100 );
834 Size aOldSize
= Size( 0, rFnt
.GetHeight( rFnt
.GetActual() ) );
836 Size
aNewSize( 0, ( nFactor
* nCurrHeight
) / 1000 );
837 rFnt
.SetSize( aNewSize
, rFnt
.GetActual() );
838 rFnt
.ChgPhysFnt( rInf
.GetVsh(), *pOut
);
840 nAscent
= rFnt
.GetAscent( rInf
.GetVsh(), *pOut
);
842 // Wir besorgen uns das alle Buchstaben umfassende Rechteck:
843 bHaveGlyphRect
= pOut
->GetTextBoundRect( aRect
, rInf
.GetTxt(), 0,
844 nIdx
, pCurrPart
->GetLen() ) &&
847 if ( ! bHaveGlyphRect
)
849 // getting glyph boundaries failed for some reason,
850 // we take the window for calculating sizes
856 aOldMap
= pWin
->GetMapMode( );
857 pWin
->SetMapMode( MapMode( MAP_TWIP
) );
858 aOldFnt
= pWin
->GetFont();
860 pWin
->SetFont( rFnt
.GetActualFont() );
862 bHaveGlyphRect
= pWin
->GetTextBoundRect( aRect
, rInf
.GetTxt(), 0,
863 nIdx
, pCurrPart
->GetLen() ) &&
866 if ( bHaveGlyphRect
)
868 FontMetric
aWinMet( pWin
->GetFontMetric() );
869 nAscent
= (KSHORT
) aWinMet
.GetAscent();
872 // We do not have a window or our window could not
873 // give us glyph boundaries.
874 aRect
= Rectangle( Point( 0, 0 ), Size( 0, nAscent
) );
877 // Now we (hopefully) have a bounding rectangle for the
878 // glyphs of the current portion and the ascent of the current
881 // reset font size and proportion
882 rFnt
.SetSize( aOldSize
, rFnt
.GetActual() );
883 rFnt
.SetProportion( nOldProp
);
885 if ( bFirstGlyphRect
)
888 bFirstGlyphRect
= sal_False
;
891 aCommonRect
.Union( aRect
);
893 nIdx
= nIdx
+ pCurrPart
->GetLen();
894 pCurrPart
= pCurrPart
->GetFollow();
897 // now we have a union ( aCommonRect ) of all glyphs with
898 // respect to a common baseline : 0
900 // get descent and ascent from union
901 if ( rInf
.GetTxtFrm()->IsVertical() )
903 nDescent
= aCommonRect
.Left();
904 nAscent
= aCommonRect
.Right();
907 nDescent
= -nDescent
;
911 nDescent
= aCommonRect
.Bottom();
912 nAscent
= aCommonRect
.Top();
917 const long nHght
= nAscent
+ nDescent
;
920 if ( nHght
> nWishedHeight
)
925 aFactor
[ nTmpIdx
] = (sal_uInt16
)nFactor
;
929 nFactor
= ( nFactor
* nWishedHeight
) / nHght
;
930 bGrow
= ( nFactor
> nMin
) && ( nFactor
< nMax
);
931 #if OSL_DEBUG_LEVEL > 1
935 nIdx
= rInf
.GetIdx();
943 // reset window if it has been used
944 pWin
->SetMapMode( aOldMap
);
945 pWin
->SetFont( aOldFnt
);
949 aDescent
[ nTmpIdx
] = -short( nDescent
);
952 pCurrPart
= pDrop
->GetPart();
954 // did made any new calculations or did we use the cache?
957 nFactor
= aFactor
[ nTmpIdx
];
958 nDescent
= aDescent
[ nTmpIdx
];
961 nDescent
= -nDescent
;
965 // scale current font
966 SwFont
& rFnt
= pCurrPart
->GetFont();
967 Size
aNewSize( 0, ( nFactor
* rFnt
.GetHeight( rFnt
.GetActual() ) ) / 1000 );
969 const sal_uInt8 nOldProp
= rFnt
.GetPropr();
970 rFnt
.SetProportion( 100 );
971 rFnt
.SetSize( aNewSize
, rFnt
.GetActual() );
972 rFnt
.SetProportion( nOldProp
);
974 pCurrPart
= pCurrPart
->GetFollow();
976 pDrop
->SetY( (short)nDescent
);
979 /*************************************************************************
981 *************************************************************************/
983 sal_Bool
SwDropPortion::Format( SwTxtFormatInfo
&rInf
)
985 sal_Bool bFull
= sal_False
;
986 Fix( (sal_uInt16
)rInf
.X() );
988 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
989 aLayoutModeModifier
.SetAuto();
991 if( nDropHeight
&& pPart
&& nLines
!=1 )
994 pDropCapCache
= new SwDropCapCache();
996 // adjust font sizes to fit into the rectangle
997 pDropCapCache
->CalcFontSize( this, rInf
);
999 const long nOldX
= rInf
.X();
1001 SwDropSave
aSave( rInf
);
1002 SwDropPortionPart
* pCurrPart
= pPart
;
1006 rInf
.SetLen( pCurrPart
->GetLen() );
1007 SwFont
& rFnt
= pCurrPart
->GetFont();
1009 SwFontSave
aFontSave( rInf
, &rFnt
);
1010 bFull
= FormatTxt( rInf
);
1016 const SwTwips nTmpWidth
=
1017 ( InSpaceGrp() && rInf
.GetSpaceAdd() ) ?
1018 Width() + CalcSpacing( rInf
.GetSpaceAdd(), rInf
) :
1022 pCurrPart
->SetWidth( (sal_uInt16
)nTmpWidth
);
1025 rInf
.SetIdx( rInf
.GetIdx() + pCurrPart
->GetLen() );
1026 rInf
.X( rInf
.X() + nTmpWidth
);
1027 pCurrPart
= pCurrPart
->GetFollow();
1030 Width( (sal_uInt16
)(rInf
.X() - nOldX
) );
1034 SetLen( rInf
.GetLen() );
1036 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1038 bFull
= lcl_IsDropFlyInter( rInf
, Width(), nDropHeight
);
1042 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1044 Height( rInf
.GetTxtHeight() );
1046 // Jetzt noch einmal der ganze Spass
1047 nDropHeight
= nLines
= 0;
1051 // meanwhile use normal formatting
1052 bFull
= SwTxtPortion::Format( rInf
);
1055 rInf
.SetDropInit( sal_True
);
1057 Height( rInf
.GetTxtHeight() );
1058 SetAscent( rInf
.GetAscent() );
1061 bFull
= SwTxtPortion::Format( rInf
);
1067 const KSHORT nWant
= Width() + GetDistance();
1068 const KSHORT nRest
= (sal_uInt16
)(rInf
.Width() - rInf
.X());
1069 if( ( nWant
> nRest
) ||
1070 lcl_IsDropFlyInter( rInf
, Width() + GetDistance(), nDropHeight
) )
1073 Width( Width() + nDistance
);
1078 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */