Update ooo320-m1
[ooovba.git] / sw / source / core / text / txtdrop.cxx
blob475beaecb3bfe8bb99160ee83987d4748a285f1b
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 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 )
168 nEnd = nWishLen;
170 if ( ! nWishLen && pBreakIt->GetBreakIter().is() )
172 // find first word
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();
182 break;
183 case i18n::ScriptType::COMPLEX :
184 eLanguage = rAttrSet.GetCTLLanguage().GetLanguage();
185 break;
186 default :
187 eLanguage = rAttrSet.GetLanguage().GetLanguage();
188 break;
191 Boundary aBound =
192 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), 0,
193 pBreakIt->GetLocale( eLanguage ), WordType::DICTIONARY_WORD, sal_True );
195 nEnd = (xub_StrLen)aBound.endPos;
198 xub_StrLen i = 0;
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 ) ) )
205 break;
207 return 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
215 * and drop descent.
216 *************************************************************************/
217 bool SwTxtNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const
219 rFontHeight = 0;
220 rDropHeight = 0;
221 rDropDescent =0;
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() ) )
230 return false;
233 // get text frame
234 SwClientIter aClientIter( (SwTxtNode&)*this );
235 SwClient* pLastFrm = aClientIter.GoStart();
237 while( pLastFrm )
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" )
251 if ( pPara )
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();
261 else
263 const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get(RES_CHRATR_FONTSIZE);
264 rFontHeight = rItem.GetHeight();
269 break;
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;
282 return false;
285 return true;
288 /*************************************************************************
289 * SwDropPortion::PaintTxt()
290 *************************************************************************/
292 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
294 void SwDropPortion::PaintTxt( const SwTxtPaintInfo &rInf ) const
296 if ( rInf.OnWin() &&
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();
312 while ( pCurrPart )
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 )
337 return;
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.
350 // Set baseline
351 ((SwTxtPaintInfo&)rInf).Y( aOutPos.Y() + nDropHeight );
353 // for background
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.
362 SwRect aClipRect;
363 if ( rInf.OnWin() )
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 ...
371 PaintTxt( rInf );
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 )
389 if ( rInf.OnWin() &&
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 );
407 delete pTmpFont;
411 /*************************************************************************
412 * virtual Format()
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 );
421 if( bFull )
423 // sieht zwar Scheisse aus, aber was soll man schon machen?
424 rInf.SetUnderFlow( 0 );
425 Truncate();
426 SetLen( nOldLen );
427 rInf.SetLen( nOldInfLen );
429 return bFull;
432 /*************************************************************************
433 * virtual GetTxtSize()
434 *************************************************************************/
437 SwPosSize SwDropPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
439 USHORT nMyX = 0;
440 xub_StrLen nIdx = 0;
442 const SwDropPortionPart* pCurrPart = GetPart();
444 // skip parts
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 );
458 // robust
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 );
466 return aPosSize;
469 /*************************************************************************
470 * virtual GetCrsrOfst()
471 *************************************************************************/
473 xub_StrLen SwDropPortion::GetCrsrOfst( const KSHORT ) const
475 return 0;
478 /*************************************************************************
479 * SwTxtFormatter::CalcDropHeight()
480 *************************************************************************/
482 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines )
484 const SwLinePortion *const pOldCurr = GetCurr();
485 KSHORT nDropHght = 0;
486 KSHORT nAscent = 0;
487 KSHORT nHeight = 0;
488 KSHORT nDropLns = 0;
489 sal_Bool bRegisterOld = IsRegisterOn();
490 bRegisterOn = sal_False;
492 Top();
494 while( GetCurr()->IsDummy() )
496 if ( !Next() )
497 break;
500 // Wenn wir nur eine Zeile haben returnen wir 0
501 if( GetNext() || GetDropLines() == 1 )
503 for( ; nDropLns < nLines; nDropLns++ )
505 if ( GetCurr()->IsDummy() )
506 break;
507 else
509 CalcAscentAndHeight( nAscent, nHeight );
510 nDropHght = nDropHght + nHeight;
511 bRegisterOn = bRegisterOld;
513 if ( !Next() )
515 nDropLns++; // Fix: 11356
516 break;
520 // In der letzten Zeile plumpsen wir auf den Zeilenascent!
521 nDropHght = nDropHght - nHeight;
522 nDropHght = nDropHght + nAscent;
523 Top();
525 bRegisterOn = bRegisterOld;
526 SetDropDescent( nHeight - nAscent );
527 SetDropHeight( nDropHght );
528 SetDropLines( nDropLns );
529 // Alte Stelle wiederfinden!
530 while( pOldCurr != GetCurr() )
532 if( !Next() )
534 ASSERT( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
535 break;
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!" );
553 KSHORT nAscent = 0;
554 KSHORT nHeight = 0;
555 SetDropLines( nLines );
556 if ( GetDropLines() > 1 )
558 CalcRealHeight();
559 CalcAscentAndHeight( nAscent, nHeight );
561 SetDropDescent( nHeight - nAscent );
562 SetDropHeight( nHeight * nLines - GetDropDescent() );
565 /*************************************************************************
566 * SwTxtFormatter::NewDropPortion
567 *************************************************************************/
569 SwDropPortion *SwTxtFormatter::NewDropPortion( SwTxtFormatInfo &rInf )
571 if( !pDropFmt )
572 return 0;
574 xub_StrLen nPorLen = pDropFmt->GetWholeWord() ? 0 : pDropFmt->GetChars();
575 nPorLen = pFrm->GetTxtNode()->GetDropLen( nPorLen );
576 if( !nPorLen )
578 ((SwTxtFormatter*)this)->ClearDropFmt();
579 return 0;
582 SwDropPortion *pDropPor = 0;
584 // erste oder zweite Runde?
585 if ( !( GetDropHeight() || IsOnceMore() ) )
587 if ( GetNext() )
588 CalcDropHeight( pDropFmt->GetLines() );
589 else
590 GuessDropHeight( pDropFmt->GetLines() );
593 // the DropPortion
594 if( GetDropHeight() )
595 pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(),
596 GetDropDescent(), pDropFmt->GetDistance() );
597 else
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
605 // font is used.
606 if ( GetDropLines() < 2 )
608 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
609 return pDropPor;
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:
621 Seek( nNextChg );
623 // the font is deleted in the destructor of the drop portion part
624 SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
625 if ( pFmt )
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 )
641 nNextChg = nPorLen;
643 SwDropPortionPart* pPart =
644 new SwDropPortionPart( *pTmpFnt, nNextChg - nTmpIdx );
646 if ( ! pCurrPart )
647 pDropPor->SetPart( pPart );
648 else
649 pCurrPart->SetFollow( pPart );
651 pCurrPart = pPart;
654 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
655 return pDropPor;
658 /*************************************************************************
659 * SwTxtPainter::PaintDropPortion()
660 *************************************************************************/
664 void SwTxtPainter::PaintDropPortion()
666 const SwDropPortion *pDrop = GetInfo().GetParaPortion()->FindDropPortion();
667 ASSERT( pDrop, "DrapCop-Portion not available." );
668 if( !pDrop )
669 return;
671 const SwTwips nOldY = GetInfo().Y();
673 Top();
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();
686 KSHORT nX = 0;
687 while( pPor && !pPor->IsDropPortion() )
689 nX = nX + pPor->Width();
690 pPor = pPor->GetPortion();
692 Point aLineOrigin( GetTopLeft() );
694 #ifdef NIE
695 // Retusche nachholen...
696 if( nX )
698 const Point aPoint( Left(), Y() );
699 const Size aSize( nX - 1, GetDropHeight()+GetDropDescent() );
700 SwRect aRetouche( aPoint, aSize );
701 GetInfo().DrawRect( aRetouche );
703 #endif
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
727 class SwDropCapCache
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 ];
734 MSHORT nIndex;
735 public:
736 SwDropCapCache();
737 ~SwDropCapCache(){}
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;
763 MSHORT nTmpIdx = 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() );
772 long nAscent = 0;
773 long nDescent = 0;
774 long nFactor = -1;
776 if ( bUseCache )
778 SwFont& rFnt = pCurrPart->GetFont();
779 rFnt.ChkMagic( rInf.GetVsh(), rFnt.GetActual() );
780 rFnt.GetMagic( pFntNo, nTmpIdx, rFnt.GetActual() );
782 nTmpIdx = 0;
784 while( nTmpIdx < DROP_CACHE_SIZE &&
785 ( aTxt[ nTmpIdx ] != aStr || aMagicNo[ nTmpIdx ] != long(pFntNo) ||
786 aWishedHeight[ nTmpIdx ] != pDrop->GetDropHeight() ) )
787 ++nTmpIdx;
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 )
796 ++nIndex;
797 nIndex %= DROP_CACHE_SIZE;
798 nTmpIdx = nIndex;
800 long nWishedHeight = pDrop->GetDropHeight();
802 // find out biggest font size for initial scaling factor
803 long nMaxFontHeight = 0;
804 while ( pCurrPart )
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;
816 if ( bUseCache )
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
832 long nGrow = 0;
833 #endif
835 sal_Bool bWinUsed = sal_False;
836 Font aOldFnt;
837 MapMode aOldMap( MAP_TWIP );
838 OutputDevice* pOut = rInf.GetOut();
839 OutputDevice* pWin;
840 if( rInf.GetVsh() && rInf.GetVsh()->GetWin() )
841 pWin = rInf.GetVsh()->GetWin();
842 else
843 pWin = GetpApp()->GetDefaultDevice();
845 while( bGrow )
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;
853 while ( pCurrPart )
855 // current font
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() ) &&
876 ! aRect.IsEmpty();
878 if ( ! bHaveGlyphRect )
880 // getting glyph boundaries failed for some reason,
881 // we take the window for calculating sizes
882 if ( pWin )
884 if ( ! bWinUsed )
886 bWinUsed = sal_True;
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() ) &&
895 ! aRect.IsEmpty();
897 if ( bHaveGlyphRect )
899 FontMetric aWinMet( pWin->GetFontMetric() );
900 nAscent = (KSHORT) aWinMet.GetAscent();
902 else
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
910 // font
912 // reset font size and proportion
913 rFnt.SetSize( aOldSize, rFnt.GetActual() );
914 rFnt.SetProportion( nOldProp );
916 if ( bFirstGlyphRect )
918 aCommonRect = aRect;
919 bFirstGlyphRect = sal_False;
921 else
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();
937 if ( nDescent < 0 )
938 nDescent = -nDescent;
940 else
942 nDescent = aCommonRect.Bottom();
943 nAscent = aCommonRect.Top();
945 if ( nAscent < 0 )
946 nAscent = -nAscent;
948 const long nHght = nAscent + nDescent;
949 if ( nHght )
951 if ( nHght > nWishedHeight )
952 nMax = nFactor;
953 else
955 if ( bUseCache )
956 aFactor[ nTmpIdx ] = (USHORT)nFactor;
957 nMin = nFactor;
960 nFactor = ( nFactor * nWishedHeight ) / nHght;
961 bGrow = ( nFactor > nMin ) && ( nFactor < nMax );
962 #if OSL_DEBUG_LEVEL > 1
963 if ( bGrow )
964 nGrow++;
965 #endif
966 nIdx = rInf.GetIdx();
968 else
969 bGrow = sal_False;
972 if ( bWinUsed )
974 // reset window if it has been used
975 pWin->SetMapMode( aOldMap );
976 pWin->SetFont( aOldFnt );
979 if ( bUseCache )
980 aDescent[ nTmpIdx ] = -short( nDescent );
983 pCurrPart = pDrop->GetPart();
985 // did made any new calculations or did we use the cache?
986 if ( -1 == nFactor )
988 nFactor = aFactor[ nTmpIdx ];
989 nDescent = aDescent[ nTmpIdx ];
991 else
992 nDescent = -nDescent;
994 while ( pCurrPart )
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 /*************************************************************************
1011 * virtual Format()
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;
1035 while ( pCurrPart )
1037 rInf.SetLen( pCurrPart->GetLen() );
1038 SwFont& rFnt = pCurrPart->GetFont();
1040 SwFontSave aFontSave( rInf, &rFnt );
1041 bFull = FormatTxt( rInf );
1043 if ( bFull )
1044 break;
1047 const SwTwips nTmpWidth =
1048 ( InSpaceGrp() && rInf.GetSpaceAdd() ) ?
1049 Width() + CalcSpacing( rInf.GetSpaceAdd(), rInf ) :
1050 Width();
1052 // set values
1053 pCurrPart->SetWidth( (USHORT)nTmpWidth );
1055 // Move
1056 rInf.SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
1057 rInf.X( rInf.X() + nTmpWidth );
1058 pCurrPart = pCurrPart->GetFollow();
1061 Width( (USHORT)(rInf.X() - nOldX) );
1064 // reset my length
1065 SetLen( rInf.GetLen() );
1067 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1068 if( ! bFull )
1069 bFull = lcl_IsDropFlyInter( rInf, Width(), nDropHeight );
1071 if( bFull )
1073 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1074 if ( !Height() )
1075 Height( rInf.GetTxtHeight() );
1077 // Jetzt noch einmal der ganze Spass
1078 nDropHeight = nLines = 0;
1079 delete pPart;
1080 pPart = NULL;
1082 // meanwhile use normal formatting
1083 bFull = SwTxtPortion::Format( rInf );
1085 else
1086 rInf.SetDropInit( sal_True );
1088 Height( rInf.GetTxtHeight() );
1089 SetAscent( rInf.GetAscent() );
1091 else
1092 bFull = SwTxtPortion::Format( rInf );
1094 if( bFull )
1095 nDistance = 0;
1096 else
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 ) )
1102 nDistance = 0;
1104 Width( Width() + nDistance );
1106 return bFull;