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 return 0 != pTxtNode
->GetTxtAttrForCharAt(nPos
);
158 /*************************************************************************
159 * SwTxtNode::GetDropLen()
161 * nWishLen = 0 indicates that we want a whole word
162 *************************************************************************/
164 MSHORT
SwTxtNode::GetDropLen( MSHORT nWishLen
) const
166 xub_StrLen nEnd
= GetTxt().Len();
167 if( nWishLen
&& nWishLen
< nEnd
)
170 if ( ! nWishLen
&& pBreakIt
->GetBreakIter().is() )
173 const SwAttrSet
& rAttrSet
= GetSwAttrSet();
174 const USHORT nTxtScript
= pBreakIt
->GetRealScriptOfText( GetTxt(), 0 );
176 LanguageType eLanguage
;
178 switch ( nTxtScript
)
180 case i18n::ScriptType::ASIAN
:
181 eLanguage
= rAttrSet
.GetCJKLanguage().GetLanguage();
183 case i18n::ScriptType::COMPLEX
:
184 eLanguage
= rAttrSet
.GetCTLLanguage().GetLanguage();
187 eLanguage
= rAttrSet
.GetLanguage().GetLanguage();
192 pBreakIt
->GetBreakIter()->getWordBoundary( GetTxt(), 0,
193 pBreakIt
->GetLocale( eLanguage
), WordType::DICTIONARY_WORD
, sal_True
);
195 nEnd
= (xub_StrLen
)aBound
.endPos
;
199 for( ; i
< nEnd
; ++i
)
201 xub_Unicode cChar
= GetTxt().GetChar( i
);
202 if( CH_TAB
== cChar
|| CH_BREAK
== cChar
||
203 (( CH_TXTATR_BREAKWORD
== cChar
|| CH_TXTATR_INWORD
== cChar
)
204 && SwTxtSizeInfo::_HasHint( this, i
) ) )
210 /*************************************************************************
211 * SwTxtNode::GetDropSize()
213 * If a dropcap is found the return value is true otherwise false. The
214 * drop cap sizes passed back by reference are font height, drop height
216 *************************************************************************/
217 bool SwTxtNode::GetDropSize(int& rFontHeight
, int& rDropHeight
, int& rDropDescent
) const
223 const SwAttrSet
& rSet
= GetSwAttrSet();
224 const SwFmtDrop
& rDrop
= rSet
.GetDrop();
226 // Return (0,0) if there is no drop cap at this paragraph
227 if( 1 >= rDrop
.GetLines() ||
228 ( !rDrop
.GetChars() && !rDrop
.GetWholeWord() ) )
234 SwClientIter
aClientIter( (SwTxtNode
&)*this );
235 SwClient
* pLastFrm
= aClientIter
.GoStart();
239 // Only (master-) text frames can have a drop cap.
240 if ( pLastFrm
->ISA( SwTxtFrm
) && !((SwTxtFrm
*)pLastFrm
)->IsFollow() )
243 if( !((SwTxtFrm
*)pLastFrm
)->HasPara() )
244 ((SwTxtFrm
*)pLastFrm
)->GetFormatted();
246 if ( !((SwTxtFrm
*)pLastFrm
)->IsEmpty() )
248 const SwParaPortion
* pPara
= ((SwTxtFrm
*)pLastFrm
)->GetPara();
249 ASSERT( pPara
, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" )
253 const SwLinePortion
* pFirstPor
= pPara
->GetFirstPortion();
254 if (pFirstPor
&& pFirstPor
->IsDropPortion())
256 const SwDropPortion
* pDrop
= (const SwDropPortion
*)pFirstPor
;
257 rDropHeight
= pDrop
->GetDropHeight();
258 rDropDescent
= pDrop
->GetDropDescent();
259 if (const SwFont
*pFont
= pDrop
->GetFnt())
260 rFontHeight
= pFont
->GetSize(pFont
->GetActual()).Height();
263 const SvxFontHeightItem
& rItem
= (SvxFontHeightItem
&)rSet
.Get(RES_CHRATR_FONTSIZE
);
264 rFontHeight
= rItem
.GetHeight();
271 pLastFrm
= ++aClientIter
;
274 if (rFontHeight
==0 && rDropHeight
==0 && rDropDescent
==0)
276 const USHORT nLines
= rDrop
.GetLines();
278 const SvxFontHeightItem
& rItem
= (SvxFontHeightItem
&)rSet
.Get( RES_CHRATR_FONTSIZE
);
279 rFontHeight
= rItem
.GetHeight();
280 rDropHeight
= nLines
* rFontHeight
;
281 rDropDescent
= rFontHeight
/ 5;
288 /*************************************************************************
289 * SwDropPortion::PaintTxt()
290 *************************************************************************/
292 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
294 void SwDropPortion::PaintTxt( const SwTxtPaintInfo
&rInf
) const
297 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
298 rInf
.DrawBackground( *this );
300 ASSERT( nDropHeight
&& pPart
&& nLines
!= 1, "Drop Portion painted twice" );
302 const SwDropPortionPart
* pCurrPart
= GetPart();
303 const xub_StrLen nOldLen
= GetLen();
305 const SwTwips nBasePosY
= rInf
.Y();
306 ((SwTxtPaintInfo
&)rInf
).Y( nBasePosY
+ nY
);
307 SwDropSave
aSave( rInf
);
308 // for text inside drop portions we let vcl handle the text directions
309 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
310 aLayoutModeModifier
.SetAuto();
314 ((SwDropPortion
*)this)->SetLen( pCurrPart
->GetLen() );
315 ((SwTxtPaintInfo
&)rInf
).SetLen( pCurrPart
->GetLen() );
316 SwFontSave
aFontSave( rInf
, &pCurrPart
->GetFont() );
318 SwTxtPortion::Paint( rInf
);
320 ((SwTxtPaintInfo
&)rInf
).SetIdx( rInf
.GetIdx() + pCurrPart
->GetLen() );
321 ((SwTxtPaintInfo
&)rInf
).X( rInf
.X() + pCurrPart
->GetWidth() );
322 pCurrPart
= pCurrPart
->GetFollow();
325 ((SwTxtPaintInfo
&)rInf
).Y( nBasePosY
);
326 ((SwDropPortion
*)this)->SetLen( nOldLen
);
329 /*************************************************************************
330 * SwDropPortion::Paint()
331 *************************************************************************/
333 void SwDropPortion::PaintDrop( const SwTxtPaintInfo
&rInf
) const
335 // ganz normale Ausgabe wird w?hrend des normalen Paints erledigt
336 if( ! nDropHeight
|| ! pPart
|| nLines
== 1 )
339 // Luegenwerte einstellen!
340 const KSHORT nOldHeight
= Height();
341 const KSHORT nOldWidth
= Width();
342 const KSHORT nOldAscent
= GetAscent();
343 const SwTwips nOldPosY
= rInf
.Y();
344 const KSHORT nOldPosX
= (KSHORT
)rInf
.X();
345 const SwParaPortion
*pPara
= rInf
.GetParaPortion();
346 const Point
aOutPos( nOldPosX
+ nX
, nOldPosY
- pPara
->GetAscent()
347 - pPara
->GetRealHeight() + pPara
->Height() );
348 // Retusche nachholen.
351 ((SwTxtPaintInfo
&)rInf
).Y( aOutPos
.Y() + nDropHeight
);
354 ((SwDropPortion
*)this)->Height( nDropHeight
+ nDropDescent
);
355 ((SwDropPortion
*)this)->Width( Width() - nX
);
356 ((SwDropPortion
*)this)->SetAscent( nDropHeight
);
358 // Clipregion auf uns einstellen!
359 // Und zwar immer, und nie mit dem bestehenden ClipRect
360 // verrechnen, weil dies auf die Zeile eingestellt sein koennte.
365 aClipRect
= SwRect( aOutPos
, SvLSize() );
366 aClipRect
.Intersection( rInf
.GetPaintRect() );
368 SwSaveClip
aClip( (OutputDevice
*)rInf
.GetOut() );
369 aClip
.ChgClip( aClipRect
, rInf
.GetTxtFrm() );
370 // Das machen, was man sonst nur macht ...
373 // Alte Werte sichern
374 ((SwDropPortion
*)this)->Height( nOldHeight
);
375 ((SwDropPortion
*)this)->Width( nOldWidth
);
376 ((SwDropPortion
*)this)->SetAscent( nOldAscent
);
377 ((SwTxtPaintInfo
&)rInf
).Y( nOldPosY
);
380 /*************************************************************************
381 * virtual SwDropPortion::Paint()
382 *************************************************************************/
384 void SwDropPortion::Paint( const SwTxtPaintInfo
&rInf
) const
386 // ganz normale Ausgabe wird hier erledigt.
387 if( ! nDropHeight
|| ! pPart
|| 1 == nLines
)
390 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
391 rInf
.DrawBackground( *this );
393 // make sure that font is not rotated
394 SwFont
* pTmpFont
= 0;
395 if ( rInf
.GetFont()->GetOrientation( rInf
.GetTxtFrm()->IsVertical() ) )
397 pTmpFont
= new SwFont( *rInf
.GetFont() );
398 pTmpFont
->SetVertical( 0, rInf
.GetTxtFrm()->IsVertical() );
401 SwFontSave
aFontSave( rInf
, pTmpFont
);
402 // for text inside drop portions we let vcl handle the text directions
403 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
404 aLayoutModeModifier
.SetAuto();
406 SwTxtPortion::Paint( rInf
);
411 /*************************************************************************
413 *************************************************************************/
416 sal_Bool
SwDropPortion::FormatTxt( SwTxtFormatInfo
&rInf
)
418 const xub_StrLen nOldLen
= GetLen();
419 const xub_StrLen nOldInfLen
= rInf
.GetLen();
420 const sal_Bool bFull
= SwTxtPortion::Format( rInf
);
423 // sieht zwar Scheisse aus, aber was soll man schon machen?
424 rInf
.SetUnderFlow( 0 );
427 rInf
.SetLen( nOldInfLen
);
432 /*************************************************************************
433 * virtual GetTxtSize()
434 *************************************************************************/
437 SwPosSize
SwDropPortion::GetTxtSize( const SwTxtSizeInfo
&rInf
) const
442 const SwDropPortionPart
* pCurrPart
= GetPart();
445 while ( pCurrPart
&& nIdx
+ pCurrPart
->GetLen() < rInf
.GetLen() )
447 nMyX
= nMyX
+ pCurrPart
->GetWidth();
448 nIdx
= nIdx
+ pCurrPart
->GetLen();
449 pCurrPart
= pCurrPart
->GetFollow();
452 xub_StrLen nOldIdx
= rInf
.GetIdx();
453 xub_StrLen nOldLen
= rInf
.GetLen();
455 ((SwTxtSizeInfo
&)rInf
).SetIdx( nIdx
);
456 ((SwTxtSizeInfo
&)rInf
).SetLen( rInf
.GetLen() - nIdx
);
459 SwFontSave
aFontSave( rInf
, pCurrPart
? &pCurrPart
->GetFont() : 0 );
460 SwPosSize
aPosSize( SwTxtPortion::GetTxtSize( rInf
) );
461 aPosSize
.Width( aPosSize
.Width() + nMyX
);
463 ((SwTxtSizeInfo
&)rInf
).SetIdx( nOldIdx
);
464 ((SwTxtSizeInfo
&)rInf
).SetLen( nOldLen
);
469 /*************************************************************************
470 * virtual GetCrsrOfst()
471 *************************************************************************/
473 xub_StrLen
SwDropPortion::GetCrsrOfst( const KSHORT
) const
478 /*************************************************************************
479 * SwTxtFormatter::CalcDropHeight()
480 *************************************************************************/
482 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines
)
484 const SwLinePortion
*const pOldCurr
= GetCurr();
485 KSHORT nDropHght
= 0;
489 sal_Bool bRegisterOld
= IsRegisterOn();
490 bRegisterOn
= sal_False
;
494 while( GetCurr()->IsDummy() )
500 // Wenn wir nur eine Zeile haben returnen wir 0
501 if( GetNext() || GetDropLines() == 1 )
503 for( ; nDropLns
< nLines
; nDropLns
++ )
505 if ( GetCurr()->IsDummy() )
509 CalcAscentAndHeight( nAscent
, nHeight
);
510 nDropHght
= nDropHght
+ nHeight
;
511 bRegisterOn
= bRegisterOld
;
515 nDropLns
++; // Fix: 11356
520 // In der letzten Zeile plumpsen wir auf den Zeilenascent!
521 nDropHght
= nDropHght
- nHeight
;
522 nDropHght
= nDropHght
+ nAscent
;
525 bRegisterOn
= bRegisterOld
;
526 SetDropDescent( nHeight
- nAscent
);
527 SetDropHeight( nDropHght
);
528 SetDropLines( nDropLns
);
529 // Alte Stelle wiederfinden!
530 while( pOldCurr
!= GetCurr() )
534 ASSERT( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
540 /*************************************************************************
541 * SwTxtFormatter::GuessDropHeight()
543 * Wir schaetzen mal, dass die Fonthoehe sich nicht aendert und dass
544 * erst mindestens soviele Zeilen gibt, wie die DropCap-Einstellung angibt.
546 *************************************************************************/
550 void SwTxtFormatter::GuessDropHeight( const MSHORT nLines
)
552 ASSERT( nLines
, "GuessDropHeight: Give me more Lines!" );
555 SetDropLines( nLines
);
556 if ( GetDropLines() > 1 )
559 CalcAscentAndHeight( nAscent
, nHeight
);
561 SetDropDescent( nHeight
- nAscent
);
562 SetDropHeight( nHeight
* nLines
- GetDropDescent() );
565 /*************************************************************************
566 * SwTxtFormatter::NewDropPortion
567 *************************************************************************/
569 SwDropPortion
*SwTxtFormatter::NewDropPortion( SwTxtFormatInfo
&rInf
)
574 xub_StrLen nPorLen
= pDropFmt
->GetWholeWord() ? 0 : pDropFmt
->GetChars();
575 nPorLen
= pFrm
->GetTxtNode()->GetDropLen( nPorLen
);
578 ((SwTxtFormatter
*)this)->ClearDropFmt();
582 SwDropPortion
*pDropPor
= 0;
584 // erste oder zweite Runde?
585 if ( !( GetDropHeight() || IsOnceMore() ) )
588 CalcDropHeight( pDropFmt
->GetLines() );
590 GuessDropHeight( pDropFmt
->GetLines() );
594 if( GetDropHeight() )
595 pDropPor
= new SwDropPortion( GetDropLines(), GetDropHeight(),
596 GetDropDescent(), pDropFmt
->GetDistance() );
598 pDropPor
= new SwDropPortion( 0,0,0,pDropFmt
->GetDistance() );
600 pDropPor
->SetLen( nPorLen
);
602 // If it was not possible to create a proper drop cap portion
603 // due to avoiding endless loops. We return a drop cap portion
604 // with an empty SwDropCapPart. For these portions the current
606 if ( GetDropLines() < 2 )
608 ((SwTxtFormatter
*)this)->SetPaintDrop( sal_True
);
612 // build DropPortionParts:
613 ASSERT( ! rInf
.GetIdx(), "Drop Portion not at 0 position!" );
614 xub_StrLen nNextChg
= 0;
615 const SwCharFmt
* pFmt
= pDropFmt
->GetCharFmt();
616 SwDropPortionPart
* pCurrPart
= 0;
618 while ( nNextChg
< nPorLen
)
620 // check for attribute changes and if the portion has to split:
623 // the font is deleted in the destructor of the drop portion part
624 SwFont
* pTmpFnt
= new SwFont( *rInf
.GetFont() );
627 const SwAttrSet
& rSet
= pFmt
->GetAttrSet();
628 pTmpFnt
->SetDiffFnt( &rSet
, pFrm
->GetTxtNode()->getIDocumentSettingAccess() );
631 // we do not allow a vertical font for the drop portion
632 pTmpFnt
->SetVertical( 0, rInf
.GetTxtFrm()->IsVertical() );
634 // find next attribute change / script change
635 const xub_StrLen nTmpIdx
= nNextChg
;
636 xub_StrLen nNextAttr
= Min( GetNextAttr(), rInf
.GetTxt().Len() );
637 nNextChg
= pScriptInfo
->NextScriptChg( nTmpIdx
);
638 if( nNextChg
> nNextAttr
)
639 nNextChg
= nNextAttr
;
640 if ( nNextChg
> nPorLen
)
643 SwDropPortionPart
* pPart
=
644 new SwDropPortionPart( *pTmpFnt
, nNextChg
- nTmpIdx
);
647 pDropPor
->SetPart( pPart
);
649 pCurrPart
->SetFollow( pPart
);
654 ((SwTxtFormatter
*)this)->SetPaintDrop( sal_True
);
658 /*************************************************************************
659 * SwTxtPainter::PaintDropPortion()
660 *************************************************************************/
664 void SwTxtPainter::PaintDropPortion()
666 const SwDropPortion
*pDrop
= GetInfo().GetParaPortion()->FindDropPortion();
667 ASSERT( pDrop
, "DrapCop-Portion not available." );
671 const SwTwips nOldY
= GetInfo().Y();
675 GetInfo().SetpSpaceAdd( pCurr
->GetpLLSpaceAdd() );
676 GetInfo().ResetSpaceIdx();
677 GetInfo().SetKanaComp( pCurr
->GetpKanaComp() );
678 GetInfo().ResetKanaIdx();
680 // 8047: Drops und Dummies
681 while( !pCurr
->GetLen() && Next() )
684 // MarginPortion und Adjustment!
685 const SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
687 while( pPor
&& !pPor
->IsDropPortion() )
689 nX
= nX
+ pPor
->Width();
690 pPor
= pPor
->GetPortion();
692 Point
aLineOrigin( GetTopLeft() );
695 // Retusche nachholen...
698 const Point
aPoint( Left(), Y() );
699 const Size
aSize( nX
- 1, GetDropHeight()+GetDropDescent() );
700 SwRect
aRetouche( aPoint
, aSize
);
701 GetInfo().DrawRect( aRetouche
);
705 aLineOrigin
.X() += nX
;
706 KSHORT nTmpAscent
, nTmpHeight
;
707 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
708 aLineOrigin
.Y() += nTmpAscent
;
709 GetInfo().SetIdx( GetStart() );
710 GetInfo().SetPos( aLineOrigin
);
711 GetInfo().SetLen( pDrop
->GetLen() );
713 pDrop
->PaintDrop( GetInfo() );
715 GetInfo().Y( nOldY
);
718 /*************************************************************************
719 * clas SwDropCapCache
721 * Da die Berechnung der Fontgroesse der Initialen ein teures Geschaeft ist,
722 * wird dies durch einen DropCapCache geschleust.
723 *************************************************************************/
725 #define DROP_CACHE_SIZE 10
729 long aMagicNo
[ DROP_CACHE_SIZE
];
730 XubString aTxt
[ DROP_CACHE_SIZE
];
731 USHORT aFactor
[ DROP_CACHE_SIZE
];
732 KSHORT aWishedHeight
[ DROP_CACHE_SIZE
];
733 short aDescent
[ DROP_CACHE_SIZE
];
738 void CalcFontSize( SwDropPortion
* pDrop
, SwTxtFormatInfo
&rInf
);
741 /*************************************************************************
742 * SwDropCapCache Ctor / Dtor
743 *************************************************************************/
745 SwDropCapCache::SwDropCapCache() : nIndex( 0 )
747 memset( &aMagicNo
, 0, sizeof(aMagicNo
) );
748 memset( &aWishedHeight
, 0, sizeof(aWishedHeight
) );
751 void SwDropPortion::DeleteDropCapCache()
753 delete pDropCapCache
;
756 /*************************************************************************
757 * SwDropCapCache::CalcFontSize
758 *************************************************************************/
760 void SwDropCapCache::CalcFontSize( SwDropPortion
* pDrop
, SwTxtFormatInfo
&rInf
)
762 const void* pFntNo
= 0;
765 ASSERT( pDrop
->GetPart(),"DropPortion without part during font calculation");
767 SwDropPortionPart
* pCurrPart
= pDrop
->GetPart();
768 const sal_Bool bUseCache
= ! pCurrPart
->GetFollow();
769 xub_StrLen nIdx
= rInf
.GetIdx();
770 XubString
aStr( rInf
.GetTxt(), nIdx
, pCurrPart
->GetLen() );
778 SwFont
& rFnt
= pCurrPart
->GetFont();
779 rFnt
.ChkMagic( rInf
.GetVsh(), rFnt
.GetActual() );
780 rFnt
.GetMagic( pFntNo
, nTmpIdx
, rFnt
.GetActual() );
784 while( nTmpIdx
< DROP_CACHE_SIZE
&&
785 ( aTxt
[ nTmpIdx
] != aStr
|| aMagicNo
[ nTmpIdx
] != long(pFntNo
) ||
786 aWishedHeight
[ nTmpIdx
] != pDrop
->GetDropHeight() ) )
790 // we have to calculate a new font scaling factor if
791 // 1. we did not find a scaling factor in the cache or
792 // 2. we are not allowed to use the cache because the drop portion
793 // consists of more than one part
794 if( nTmpIdx
>= DROP_CACHE_SIZE
|| ! bUseCache
)
797 nIndex
%= DROP_CACHE_SIZE
;
800 long nWishedHeight
= pDrop
->GetDropHeight();
802 // find out biggest font size for initial scaling factor
803 long nMaxFontHeight
= 0;
806 const SwFont
& rFnt
= pCurrPart
->GetFont();
807 const long nCurrHeight
= rFnt
.GetHeight( rFnt
.GetActual() );
808 if ( nCurrHeight
> nMaxFontHeight
)
809 nMaxFontHeight
= nCurrHeight
;
811 pCurrPart
= pCurrPart
->GetFollow();
814 nFactor
= ( 1000 * nWishedHeight
) / nMaxFontHeight
;
818 // save keys for cache
819 aMagicNo
[ nTmpIdx
] = long(pFntNo
);
820 aTxt
[ nTmpIdx
] = aStr
;
821 aWishedHeight
[ nTmpIdx
] = KSHORT(nWishedHeight
);
822 // save initial scaling factor
823 aFactor
[ nTmpIdx
] = (USHORT
)nFactor
;
826 sal_Bool bGrow
= ( pDrop
->GetLen() != 0 );
828 // for growing controll
829 long nMax
= KSHRT_MAX
;
830 long nMin
= nFactor
/ 2;
831 #if OSL_DEBUG_LEVEL > 1
835 sal_Bool bWinUsed
= sal_False
;
837 MapMode
aOldMap( MAP_TWIP
);
838 OutputDevice
* pOut
= rInf
.GetOut();
840 if( rInf
.GetVsh() && rInf
.GetVsh()->GetWin() )
841 pWin
= rInf
.GetVsh()->GetWin();
843 pWin
= GetpApp()->GetDefaultDevice();
847 // reset pCurrPart to first part
848 pCurrPart
= pDrop
->GetPart();
849 sal_Bool bFirstGlyphRect
= sal_True
;
850 sal_Bool bHaveGlyphRect
= sal_False
;
851 Rectangle aCommonRect
, aRect
;
856 SwFont
& rFnt
= pCurrPart
->GetFont();
858 // Get height including proportion
859 const USHORT nCurrHeight
=
860 (USHORT
)rFnt
.GetHeight( rFnt
.GetActual() );
862 // Get without proportion
863 const BYTE nOldProp
= rFnt
.GetPropr();
864 rFnt
.SetProportion( 100 );
865 Size aOldSize
= Size( 0, rFnt
.GetHeight( rFnt
.GetActual() ) );
867 Size
aNewSize( 0, ( nFactor
* nCurrHeight
) / 1000 );
868 rFnt
.SetSize( aNewSize
, rFnt
.GetActual() );
869 rFnt
.ChgPhysFnt( rInf
.GetVsh(), *pOut
);
871 nAscent
= rFnt
.GetAscent( rInf
.GetVsh(), *pOut
);
873 // Wir besorgen uns das alle Buchstaben umfassende Rechteck:
874 bHaveGlyphRect
= pOut
->GetTextBoundRect( aRect
, rInf
.GetTxt(), 0,
875 nIdx
, pCurrPart
->GetLen() ) &&
878 if ( ! bHaveGlyphRect
)
880 // getting glyph boundaries failed for some reason,
881 // we take the window for calculating sizes
887 aOldMap
= pWin
->GetMapMode( );
888 pWin
->SetMapMode( MapMode( MAP_TWIP
) );
889 aOldFnt
= pWin
->GetFont();
891 pWin
->SetFont( rFnt
.GetActualFont() );
893 bHaveGlyphRect
= pWin
->GetTextBoundRect( aRect
, rInf
.GetTxt(), 0,
894 nIdx
, pCurrPart
->GetLen() ) &&
897 if ( bHaveGlyphRect
)
899 FontMetric
aWinMet( pWin
->GetFontMetric() );
900 nAscent
= (KSHORT
) aWinMet
.GetAscent();
903 // We do not have a window or our window could not
904 // give us glyph boundaries.
905 aRect
= Rectangle( Point( 0, 0 ), Size( 0, nAscent
) );
908 // Now we (hopefully) have a bounding rectangle for the
909 // glyphs of the current portion and the ascent of the current
912 // reset font size and proportion
913 rFnt
.SetSize( aOldSize
, rFnt
.GetActual() );
914 rFnt
.SetProportion( nOldProp
);
916 if ( bFirstGlyphRect
)
919 bFirstGlyphRect
= sal_False
;
922 aCommonRect
.Union( aRect
);
924 nIdx
= nIdx
+ pCurrPart
->GetLen();
925 pCurrPart
= pCurrPart
->GetFollow();
928 // now we have a union ( aCommonRect ) of all glyphs with
929 // respect to a common baseline : 0
931 // get descent and ascent from union
932 if ( rInf
.GetTxtFrm()->IsVertical() )
934 nDescent
= aCommonRect
.Left();
935 nAscent
= aCommonRect
.Right();
938 nDescent
= -nDescent
;
942 nDescent
= aCommonRect
.Bottom();
943 nAscent
= aCommonRect
.Top();
948 const long nHght
= nAscent
+ nDescent
;
951 if ( nHght
> nWishedHeight
)
956 aFactor
[ nTmpIdx
] = (USHORT
)nFactor
;
960 nFactor
= ( nFactor
* nWishedHeight
) / nHght
;
961 bGrow
= ( nFactor
> nMin
) && ( nFactor
< nMax
);
962 #if OSL_DEBUG_LEVEL > 1
966 nIdx
= rInf
.GetIdx();
974 // reset window if it has been used
975 pWin
->SetMapMode( aOldMap
);
976 pWin
->SetFont( aOldFnt
);
980 aDescent
[ nTmpIdx
] = -short( nDescent
);
983 pCurrPart
= pDrop
->GetPart();
985 // did made any new calculations or did we use the cache?
988 nFactor
= aFactor
[ nTmpIdx
];
989 nDescent
= aDescent
[ nTmpIdx
];
992 nDescent
= -nDescent
;
996 // scale current font
997 SwFont
& rFnt
= pCurrPart
->GetFont();
998 Size
aNewSize( 0, ( nFactor
* rFnt
.GetHeight( rFnt
.GetActual() ) ) / 1000 );
1000 const BYTE nOldProp
= rFnt
.GetPropr();
1001 rFnt
.SetProportion( 100 );
1002 rFnt
.SetSize( aNewSize
, rFnt
.GetActual() );
1003 rFnt
.SetProportion( nOldProp
);
1005 pCurrPart
= pCurrPart
->GetFollow();
1007 pDrop
->SetY( (short)nDescent
);
1010 /*************************************************************************
1012 *************************************************************************/
1014 sal_Bool
SwDropPortion::Format( SwTxtFormatInfo
&rInf
)
1016 sal_Bool bFull
= sal_False
;
1017 Fix( (USHORT
)rInf
.X() );
1019 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
1020 aLayoutModeModifier
.SetAuto();
1022 if( nDropHeight
&& pPart
&& nLines
!=1 )
1024 if( !pDropCapCache
)
1025 pDropCapCache
= new SwDropCapCache();
1027 // adjust font sizes to fit into the rectangle
1028 pDropCapCache
->CalcFontSize( this, rInf
);
1030 const long nOldX
= rInf
.X();
1032 SwDropSave
aSave( rInf
);
1033 SwDropPortionPart
* pCurrPart
= pPart
;
1037 rInf
.SetLen( pCurrPart
->GetLen() );
1038 SwFont
& rFnt
= pCurrPart
->GetFont();
1040 SwFontSave
aFontSave( rInf
, &rFnt
);
1041 bFull
= FormatTxt( rInf
);
1047 const SwTwips nTmpWidth
=
1048 ( InSpaceGrp() && rInf
.GetSpaceAdd() ) ?
1049 Width() + CalcSpacing( rInf
.GetSpaceAdd(), rInf
) :
1053 pCurrPart
->SetWidth( (USHORT
)nTmpWidth
);
1056 rInf
.SetIdx( rInf
.GetIdx() + pCurrPart
->GetLen() );
1057 rInf
.X( rInf
.X() + nTmpWidth
);
1058 pCurrPart
= pCurrPart
->GetFollow();
1061 Width( (USHORT
)(rInf
.X() - nOldX
) );
1065 SetLen( rInf
.GetLen() );
1067 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1069 bFull
= lcl_IsDropFlyInter( rInf
, Width(), nDropHeight
);
1073 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1075 Height( rInf
.GetTxtHeight() );
1077 // Jetzt noch einmal der ganze Spass
1078 nDropHeight
= nLines
= 0;
1082 // meanwhile use normal formatting
1083 bFull
= SwTxtPortion::Format( rInf
);
1086 rInf
.SetDropInit( sal_True
);
1088 Height( rInf
.GetTxtHeight() );
1089 SetAscent( rInf
.GetAscent() );
1092 bFull
= SwTxtPortion::Format( rInf
);
1098 const KSHORT nWant
= Width() + GetDistance();
1099 const KSHORT nRest
= (USHORT
)(rInf
.Width() - rInf
.X());
1100 if( ( nWant
> nRest
) ||
1101 lcl_IsDropFlyInter( rInf
, Width() + GetDistance(), nDropHeight
) )
1104 Width( Width() + nDistance
);