update dev300-m58
[ooovba.git] / sw / source / core / text / txtdrop.cxx
blob184fe64e8d7666d3f66875bbba8ee05327182c69
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: txtdrop.cxx,v $
10 * $Revision: 1.27 $
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>
39 #include <paratr.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>
51 #endif
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 /*************************************************************************
61 * lcl_IsDropFlyInter
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();
82 return sal_False;
85 /*************************************************************************
86 * class SwDropSave
87 *************************************************************************/
89 class SwDropSave
91 SwTxtPaintInfo* pInf;
92 xub_StrLen nIdx;
93 xub_StrLen nLen;
94 long nX;
95 long nY;
97 public:
98 SwDropSave( const SwTxtPaintInfo &rInf );
99 ~SwDropSave();
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 );
112 pInf->X( nX );
113 pInf->Y( nY );
116 /*************************************************************************
117 * SwDropPortionPart DTor
118 *************************************************************************/
120 SwDropPortionPart::~SwDropPortionPart()
122 if ( pFollow )
123 delete pFollow;
124 delete pFnt;
127 /*************************************************************************
128 * SwDropPortion CTor, DTor
129 *************************************************************************/
131 SwDropPortion::SwDropPortion( const MSHORT nLineCnt,
132 const KSHORT nDrpHeight,
133 const KSHORT nDrpDescent,
134 const KSHORT nDist )
135 : pPart( 0 ),
136 nLines( nLineCnt ),
137 nDropHeight(nDrpHeight),
138 nDropDescent(nDrpDescent),
139 nDistance(nDist),
140 nFix(0),
141 nX(0)
143 SetWhichPor( POR_DROP );
146 SwDropPortion::~SwDropPortion()
148 delete pPart;
149 if( pBlink )
150 pBlink->Delete( this );
153 sal_Bool SwTxtSizeInfo::_HasHint( const SwTxtNode* pTxtNode, xub_StrLen nPos )
155 const SwpHints *pHints = pTxtNode->GetpSwpHints();
156 if( !pHints )
157 return sal_False;
158 for ( USHORT i = 0; i < pHints->Count(); ++i )
160 const SwTxtAttr *pPos = (*pHints)[i];
161 xub_StrLen nStart = *pPos->GetStart();
162 if( nPos < nStart )
163 return sal_False;
164 if( nPos == nStart && !pPos->GetEnd() )
165 return sal_True;
167 return sal_False;
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 )
180 nEnd = nWishLen;
182 if ( ! nWishLen && pBreakIt->GetBreakIter().is() )
184 // find first word
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();
194 break;
195 case i18n::ScriptType::COMPLEX :
196 eLanguage = rAttrSet.GetCTLLanguage().GetLanguage();
197 break;
198 default :
199 eLanguage = rAttrSet.GetLanguage().GetLanguage();
200 break;
203 Boundary aBound =
204 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), 0,
205 pBreakIt->GetLocale( eLanguage ), WordType::DICTIONARY_WORD, sal_True );
207 nEnd = (xub_StrLen)aBound.endPos;
210 xub_StrLen i = 0;
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 ) ) )
217 break;
219 return 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
227 * and drop descent.
228 *************************************************************************/
229 bool SwTxtNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const
231 rFontHeight = 0;
232 rDropHeight = 0;
233 rDropDescent =0;
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() ) )
242 return false;
245 // get text frame
246 SwClientIter aClientIter( (SwTxtNode&)*this );
247 SwClient* pLastFrm = aClientIter.GoStart();
249 while( pLastFrm )
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" )
263 if ( pPara )
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();
273 else
275 const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get(RES_CHRATR_FONTSIZE);
276 rFontHeight = rItem.GetHeight();
281 break;
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;
294 return false;
297 return true;
300 /*************************************************************************
301 * SwDropPortion::PaintTxt()
302 *************************************************************************/
304 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
306 void SwDropPortion::PaintTxt( const SwTxtPaintInfo &rInf ) const
308 if ( rInf.OnWin() &&
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();
324 while ( pCurrPart )
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 )
349 return;
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.
362 // Set baseline
363 ((SwTxtPaintInfo&)rInf).Y( aOutPos.Y() + nDropHeight );
365 // for background
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.
374 SwRect aClipRect;
375 if ( rInf.OnWin() )
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 ...
383 PaintTxt( rInf );
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 )
401 if ( rInf.OnWin() &&
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 );
419 delete pTmpFont;
423 /*************************************************************************
424 * virtual Format()
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 );
433 if( bFull )
435 // sieht zwar Scheisse aus, aber was soll man schon machen?
436 rInf.SetUnderFlow( 0 );
437 Truncate();
438 SetLen( nOldLen );
439 rInf.SetLen( nOldInfLen );
441 return bFull;
444 /*************************************************************************
445 * virtual GetTxtSize()
446 *************************************************************************/
449 SwPosSize SwDropPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
451 USHORT nMyX = 0;
452 xub_StrLen nIdx = 0;
454 const SwDropPortionPart* pCurrPart = GetPart();
456 // skip parts
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 );
470 // robust
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 );
478 return aPosSize;
481 /*************************************************************************
482 * virtual GetCrsrOfst()
483 *************************************************************************/
485 xub_StrLen SwDropPortion::GetCrsrOfst( const KSHORT ) const
487 return 0;
490 /*************************************************************************
491 * SwTxtFormatter::CalcDropHeight()
492 *************************************************************************/
494 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines )
496 const SwLinePortion *const pOldCurr = GetCurr();
497 KSHORT nDropHght = 0;
498 KSHORT nAscent = 0;
499 KSHORT nHeight = 0;
500 KSHORT nDropLns = 0;
501 sal_Bool bRegisterOld = IsRegisterOn();
502 bRegisterOn = sal_False;
504 Top();
506 while( GetCurr()->IsDummy() )
508 if ( !Next() )
509 break;
512 // Wenn wir nur eine Zeile haben returnen wir 0
513 if( GetNext() || GetDropLines() == 1 )
515 for( ; nDropLns < nLines; nDropLns++ )
517 if ( GetCurr()->IsDummy() )
518 break;
519 else
521 CalcAscentAndHeight( nAscent, nHeight );
522 nDropHght = nDropHght + nHeight;
523 bRegisterOn = bRegisterOld;
525 if ( !Next() )
527 nDropLns++; // Fix: 11356
528 break;
532 // In der letzten Zeile plumpsen wir auf den Zeilenascent!
533 nDropHght = nDropHght - nHeight;
534 nDropHght = nDropHght + nAscent;
535 Top();
537 bRegisterOn = bRegisterOld;
538 SetDropDescent( nHeight - nAscent );
539 SetDropHeight( nDropHght );
540 SetDropLines( nDropLns );
541 // Alte Stelle wiederfinden!
542 while( pOldCurr != GetCurr() )
544 if( !Next() )
546 ASSERT( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
547 break;
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!" );
565 KSHORT nAscent = 0;
566 KSHORT nHeight = 0;
567 SetDropLines( nLines );
568 if ( GetDropLines() > 1 )
570 CalcRealHeight();
571 CalcAscentAndHeight( nAscent, nHeight );
573 SetDropDescent( nHeight - nAscent );
574 SetDropHeight( nHeight * nLines - GetDropDescent() );
577 /*************************************************************************
578 * SwTxtFormatter::NewDropPortion
579 *************************************************************************/
581 SwDropPortion *SwTxtFormatter::NewDropPortion( SwTxtFormatInfo &rInf )
583 if( !pDropFmt )
584 return 0;
586 xub_StrLen nPorLen = pDropFmt->GetWholeWord() ? 0 : pDropFmt->GetChars();
587 nPorLen = pFrm->GetTxtNode()->GetDropLen( nPorLen );
588 if( !nPorLen )
590 ((SwTxtFormatter*)this)->ClearDropFmt();
591 return 0;
594 SwDropPortion *pDropPor = 0;
596 // erste oder zweite Runde?
597 if ( !( GetDropHeight() || IsOnceMore() ) )
599 if ( GetNext() )
600 CalcDropHeight( pDropFmt->GetLines() );
601 else
602 GuessDropHeight( pDropFmt->GetLines() );
605 // the DropPortion
606 if( GetDropHeight() )
607 pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(),
608 GetDropDescent(), pDropFmt->GetDistance() );
609 else
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
617 // font is used.
618 if ( GetDropLines() < 2 )
620 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
621 return pDropPor;
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:
633 Seek( nNextChg );
635 // the font is deleted in the destructor of the drop portion part
636 SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
637 if ( pFmt )
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 )
653 nNextChg = nPorLen;
655 SwDropPortionPart* pPart =
656 new SwDropPortionPart( *pTmpFnt, nNextChg - nTmpIdx );
658 if ( ! pCurrPart )
659 pDropPor->SetPart( pPart );
660 else
661 pCurrPart->SetFollow( pPart );
663 pCurrPart = pPart;
666 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
667 return pDropPor;
670 /*************************************************************************
671 * SwTxtPainter::PaintDropPortion()
672 *************************************************************************/
676 void SwTxtPainter::PaintDropPortion()
678 const SwDropPortion *pDrop = GetInfo().GetParaPortion()->FindDropPortion();
679 ASSERT( pDrop, "DrapCop-Portion not available." );
680 if( !pDrop )
681 return;
683 const SwTwips nOldY = GetInfo().Y();
685 Top();
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();
698 KSHORT nX = 0;
699 while( pPor && !pPor->IsDropPortion() )
701 nX = nX + pPor->Width();
702 pPor = pPor->GetPortion();
704 Point aLineOrigin( GetTopLeft() );
706 #ifdef NIE
707 // Retusche nachholen...
708 if( nX )
710 const Point aPoint( Left(), Y() );
711 const Size aSize( nX - 1, GetDropHeight()+GetDropDescent() );
712 SwRect aRetouche( aPoint, aSize );
713 GetInfo().DrawRect( aRetouche );
715 #endif
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
739 class SwDropCapCache
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 ];
746 MSHORT nIndex;
747 public:
748 SwDropCapCache();
749 ~SwDropCapCache(){}
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;
775 MSHORT nTmpIdx = 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() );
784 long nAscent = 0;
785 long nDescent = 0;
786 long nFactor = -1;
788 if ( bUseCache )
790 SwFont& rFnt = pCurrPart->GetFont();
791 rFnt.ChkMagic( rInf.GetVsh(), rFnt.GetActual() );
792 rFnt.GetMagic( pFntNo, nTmpIdx, rFnt.GetActual() );
794 nTmpIdx = 0;
796 while( nTmpIdx < DROP_CACHE_SIZE &&
797 ( aTxt[ nTmpIdx ] != aStr || aMagicNo[ nTmpIdx ] != long(pFntNo) ||
798 aWishedHeight[ nTmpIdx ] != pDrop->GetDropHeight() ) )
799 ++nTmpIdx;
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 )
808 ++nIndex;
809 nIndex %= DROP_CACHE_SIZE;
810 nTmpIdx = nIndex;
812 long nWishedHeight = pDrop->GetDropHeight();
814 // find out biggest font size for initial scaling factor
815 long nMaxFontHeight = 0;
816 while ( pCurrPart )
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;
828 if ( bUseCache )
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
844 long nGrow = 0;
845 #endif
847 sal_Bool bWinUsed = sal_False;
848 Font aOldFnt;
849 MapMode aOldMap( MAP_TWIP );
850 OutputDevice* pOut = rInf.GetOut();
851 OutputDevice* pWin;
852 if( rInf.GetVsh() && rInf.GetVsh()->GetWin() )
853 pWin = rInf.GetVsh()->GetWin();
854 else
855 pWin = GetpApp()->GetDefaultDevice();
857 while( bGrow )
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;
865 while ( pCurrPart )
867 // current font
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() ) &&
888 ! aRect.IsEmpty();
890 if ( ! bHaveGlyphRect )
892 // getting glyph boundaries failed for some reason,
893 // we take the window for calculating sizes
894 if ( pWin )
896 if ( ! bWinUsed )
898 bWinUsed = sal_True;
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() ) &&
907 ! aRect.IsEmpty();
909 if ( bHaveGlyphRect )
911 FontMetric aWinMet( pWin->GetFontMetric() );
912 nAscent = (KSHORT) aWinMet.GetAscent();
914 else
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
922 // font
924 // reset font size and proportion
925 rFnt.SetSize( aOldSize, rFnt.GetActual() );
926 rFnt.SetProportion( nOldProp );
928 if ( bFirstGlyphRect )
930 aCommonRect = aRect;
931 bFirstGlyphRect = sal_False;
933 else
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();
949 if ( nDescent < 0 )
950 nDescent = -nDescent;
952 else
954 nDescent = aCommonRect.Bottom();
955 nAscent = aCommonRect.Top();
957 if ( nAscent < 0 )
958 nAscent = -nAscent;
960 const long nHght = nAscent + nDescent;
961 if ( nHght )
963 if ( nHght > nWishedHeight )
964 nMax = nFactor;
965 else
967 if ( bUseCache )
968 aFactor[ nTmpIdx ] = (USHORT)nFactor;
969 nMin = nFactor;
972 nFactor = ( nFactor * nWishedHeight ) / nHght;
973 bGrow = ( nFactor > nMin ) && ( nFactor < nMax );
974 #if OSL_DEBUG_LEVEL > 1
975 if ( bGrow )
976 nGrow++;
977 #endif
978 nIdx = rInf.GetIdx();
980 else
981 bGrow = sal_False;
984 if ( bWinUsed )
986 // reset window if it has been used
987 pWin->SetMapMode( aOldMap );
988 pWin->SetFont( aOldFnt );
991 if ( bUseCache )
992 aDescent[ nTmpIdx ] = -short( nDescent );
995 pCurrPart = pDrop->GetPart();
997 // did made any new calculations or did we use the cache?
998 if ( -1 == nFactor )
1000 nFactor = aFactor[ nTmpIdx ];
1001 nDescent = aDescent[ nTmpIdx ];
1003 else
1004 nDescent = -nDescent;
1006 while ( pCurrPart )
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 /*************************************************************************
1023 * virtual Format()
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;
1047 while ( pCurrPart )
1049 rInf.SetLen( pCurrPart->GetLen() );
1050 SwFont& rFnt = pCurrPart->GetFont();
1052 SwFontSave aFontSave( rInf, &rFnt );
1053 bFull = FormatTxt( rInf );
1055 if ( bFull )
1056 break;
1059 const SwTwips nTmpWidth =
1060 ( InSpaceGrp() && rInf.GetSpaceAdd() ) ?
1061 Width() + CalcSpacing( rInf.GetSpaceAdd(), rInf ) :
1062 Width();
1064 // set values
1065 pCurrPart->SetWidth( (USHORT)nTmpWidth );
1067 // Move
1068 rInf.SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
1069 rInf.X( rInf.X() + nTmpWidth );
1070 pCurrPart = pCurrPart->GetFollow();
1073 Width( (USHORT)(rInf.X() - nOldX) );
1076 // reset my length
1077 SetLen( rInf.GetLen() );
1079 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1080 if( ! bFull )
1081 bFull = lcl_IsDropFlyInter( rInf, Width(), nDropHeight );
1083 if( bFull )
1085 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1086 if ( !Height() )
1087 Height( rInf.GetTxtHeight() );
1089 // Jetzt noch einmal der ganze Spass
1090 nDropHeight = nLines = 0;
1091 delete pPart;
1092 pPart = NULL;
1094 // meanwhile use normal formatting
1095 bFull = SwTxtPortion::Format( rInf );
1097 else
1098 rInf.SetDropInit( sal_True );
1100 Height( rInf.GetTxtHeight() );
1101 SetAscent( rInf.GetAscent() );
1103 else
1104 bFull = SwTxtPortion::Format( rInf );
1106 if( bFull )
1107 nDistance = 0;
1108 else
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 ) )
1114 nDistance = 0;
1116 Width( Width() + nDistance );
1118 return bFull;