Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / text / txtdrop.cxx
blobd296780b32d7d1587abec08b8aca9d67c2da3023
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
24 #include <paratr.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 /*************************************************************************
45 * lcl_IsDropFlyInter
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();
66 return sal_False;
69 /*************************************************************************
70 * class SwDropSave
71 *************************************************************************/
73 class SwDropSave
75 SwTxtPaintInfo* pInf;
76 xub_StrLen nIdx;
77 xub_StrLen nLen;
78 long nX;
79 long nY;
81 public:
82 SwDropSave( const SwTxtPaintInfo &rInf );
83 ~SwDropSave();
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()
94 pInf->SetIdx( nIdx );
95 pInf->SetLen( nLen );
96 pInf->X( nX );
97 pInf->Y( nY );
100 /*************************************************************************
101 * SwDropPortionPart DTor
102 *************************************************************************/
104 SwDropPortionPart::~SwDropPortionPart()
106 delete pFollow;
107 delete pFnt;
110 /*************************************************************************
111 * SwDropPortion CTor, DTor
112 *************************************************************************/
114 SwDropPortion::SwDropPortion( const MSHORT nLineCnt,
115 const KSHORT nDrpHeight,
116 const KSHORT nDrpDescent,
117 const KSHORT nDist )
118 : pPart( 0 ),
119 nLines( nLineCnt ),
120 nDropHeight(nDrpHeight),
121 nDropDescent(nDrpDescent),
122 nDistance(nDist),
123 nFix(0),
124 nX(0)
126 SetWhichPor( POR_DROP );
129 SwDropPortion::~SwDropPortion()
131 delete pPart;
132 if( pBlink )
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 )
151 nEnd = nWishLen;
153 if ( ! nWishLen && pBreakIt->GetBreakIter().is() )
155 // find first word
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();
165 break;
166 case i18n::ScriptType::COMPLEX :
167 eLanguage = rAttrSet.GetCTLLanguage().GetLanguage();
168 break;
169 default :
170 eLanguage = rAttrSet.GetLanguage().GetLanguage();
171 break;
174 Boundary aBound =
175 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), 0,
176 pBreakIt->GetLocale( eLanguage ), WordType::DICTIONARY_WORD, sal_True );
178 nEnd = (xub_StrLen)aBound.endPos;
181 xub_StrLen i = 0;
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 ) ) )
188 break;
190 return 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
198 * and drop descent.
199 *************************************************************************/
200 bool SwTxtNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const
202 rFontHeight = 0;
203 rDropHeight = 0;
204 rDropDescent =0;
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() ) )
213 return false;
216 // get text frame
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" );
232 if ( pPara )
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();
242 else
244 const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get(RES_CHRATR_FONTSIZE);
245 rFontHeight = rItem.GetHeight();
250 break;
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;
262 return false;
265 return true;
268 /*************************************************************************
269 * SwDropPortion::PaintTxt()
270 *************************************************************************/
272 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
274 void SwDropPortion::PaintTxt( const SwTxtPaintInfo &rInf ) const
276 if ( rInf.OnWin() &&
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();
292 while ( pCurrPart )
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 )
317 return;
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.
330 // Set baseline
331 ((SwTxtPaintInfo&)rInf).Y( aOutPos.Y() + nDropHeight );
333 // for background
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.
342 SwRect aClipRect;
343 if ( rInf.OnWin() )
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 ...
351 PaintTxt( rInf );
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 )
369 if ( rInf.OnWin() &&
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 );
387 delete pTmpFont;
391 /*************************************************************************
392 * virtual Format()
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 );
401 if( bFull )
403 // sieht zwar Scheisse aus, aber was soll man schon machen?
404 rInf.SetUnderFlow( 0 );
405 Truncate();
406 SetLen( nOldLen );
407 rInf.SetLen( nOldInfLen );
409 return bFull;
412 /*************************************************************************
413 * virtual GetTxtSize()
414 *************************************************************************/
417 SwPosSize SwDropPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
419 sal_uInt16 nMyX = 0;
420 xub_StrLen nIdx = 0;
422 const SwDropPortionPart* pCurrPart = GetPart();
424 // skip parts
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 );
438 // robust
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 );
446 return aPosSize;
449 /*************************************************************************
450 * virtual GetCrsrOfst()
451 *************************************************************************/
453 xub_StrLen SwDropPortion::GetCrsrOfst( const KSHORT ) const
455 return 0;
458 /*************************************************************************
459 * SwTxtFormatter::CalcDropHeight()
460 *************************************************************************/
462 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines )
464 const SwLinePortion *const pOldCurr = GetCurr();
465 KSHORT nDropHght = 0;
466 KSHORT nAscent = 0;
467 KSHORT nHeight = 0;
468 KSHORT nDropLns = 0;
469 sal_Bool bRegisterOld = IsRegisterOn();
470 bRegisterOn = sal_False;
472 Top();
474 while( GetCurr()->IsDummy() )
476 if ( !Next() )
477 break;
480 // Wenn wir nur eine Zeile haben returnen wir 0
481 if( GetNext() || GetDropLines() == 1 )
483 for( ; nDropLns < nLines; nDropLns++ )
485 if ( GetCurr()->IsDummy() )
486 break;
487 else
489 CalcAscentAndHeight( nAscent, nHeight );
490 nDropHght = nDropHght + nHeight;
491 bRegisterOn = bRegisterOld;
493 if ( !Next() )
495 nDropLns++; // Fix: 11356
496 break;
500 // In der letzten Zeile plumpsen wir auf den Zeilenascent!
501 nDropHght = nDropHght - nHeight;
502 nDropHght = nDropHght + nAscent;
503 Top();
505 bRegisterOn = bRegisterOld;
506 SetDropDescent( nHeight - nAscent );
507 SetDropHeight( nDropHght );
508 SetDropLines( nDropLns );
509 // Alte Stelle wiederfinden!
510 while( pOldCurr != GetCurr() )
512 if( !Next() )
514 OSL_ENSURE( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
515 break;
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!" );
533 KSHORT nAscent = 0;
534 KSHORT nHeight = 0;
535 SetDropLines( nLines );
536 if ( GetDropLines() > 1 )
538 CalcRealHeight();
539 CalcAscentAndHeight( nAscent, nHeight );
541 SetDropDescent( nHeight - nAscent );
542 SetDropHeight( nHeight * nLines - GetDropDescent() );
545 /*************************************************************************
546 * SwTxtFormatter::NewDropPortion
547 *************************************************************************/
549 SwDropPortion *SwTxtFormatter::NewDropPortion( SwTxtFormatInfo &rInf )
551 if( !pDropFmt )
552 return 0;
554 xub_StrLen nPorLen = pDropFmt->GetWholeWord() ? 0 : pDropFmt->GetChars();
555 nPorLen = pFrm->GetTxtNode()->GetDropLen( nPorLen );
556 if( !nPorLen )
558 ((SwTxtFormatter*)this)->ClearDropFmt();
559 return 0;
562 SwDropPortion *pDropPor = 0;
564 // erste oder zweite Runde?
565 if ( !( GetDropHeight() || IsOnceMore() ) )
567 if ( GetNext() )
568 CalcDropHeight( pDropFmt->GetLines() );
569 else
570 GuessDropHeight( pDropFmt->GetLines() );
573 // the DropPortion
574 if( GetDropHeight() )
575 pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(),
576 GetDropDescent(), pDropFmt->GetDistance() );
577 else
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
585 // font is used.
586 if ( GetDropLines() < 2 )
588 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
589 return pDropPor;
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:
601 Seek( nNextChg );
603 // the font is deleted in the destructor of the drop portion part
604 SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
605 if ( pFmt )
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 )
621 nNextChg = nPorLen;
623 SwDropPortionPart* pPart =
624 new SwDropPortionPart( *pTmpFnt, nNextChg - nTmpIdx );
626 if ( ! pCurrPart )
627 pDropPor->SetPart( pPart );
628 else
629 pCurrPart->SetFollow( pPart );
631 pCurrPart = pPart;
634 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
635 return pDropPor;
638 /*************************************************************************
639 * SwTxtPainter::PaintDropPortion()
640 *************************************************************************/
644 void SwTxtPainter::PaintDropPortion()
646 const SwDropPortion *pDrop = GetInfo().GetParaPortion()->FindDropPortion();
647 OSL_ENSURE( pDrop, "DrapCop-Portion not available." );
648 if( !pDrop )
649 return;
651 const SwTwips nOldY = GetInfo().Y();
653 Top();
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();
666 KSHORT nX = 0;
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
696 class SwDropCapCache
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 ];
703 MSHORT nIndex;
704 public:
705 SwDropCapCache();
706 ~SwDropCapCache(){}
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;
732 MSHORT nTmpIdx = 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() );
741 long nAscent = 0;
742 long nDescent = 0;
743 long nFactor = -1;
745 if ( bUseCache )
747 SwFont& rFnt = pCurrPart->GetFont();
748 rFnt.ChkMagic( rInf.GetVsh(), rFnt.GetActual() );
749 rFnt.GetMagic( pFntNo, nTmpIdx, rFnt.GetActual() );
751 nTmpIdx = 0;
753 while( nTmpIdx < DROP_CACHE_SIZE &&
754 ( aTxt[ nTmpIdx ] != aStr || aMagicNo[ nTmpIdx ] != long(pFntNo) ||
755 aWishedHeight[ nTmpIdx ] != pDrop->GetDropHeight() ) )
756 ++nTmpIdx;
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 )
765 ++nIndex;
766 nIndex %= DROP_CACHE_SIZE;
767 nTmpIdx = nIndex;
769 long nWishedHeight = pDrop->GetDropHeight();
771 // find out biggest font size for initial scaling factor
772 long nMaxFontHeight = 0;
773 while ( pCurrPart )
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;
785 if ( bUseCache )
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
801 long nGrow = 0;
802 #endif
804 sal_Bool bWinUsed = sal_False;
805 Font aOldFnt;
806 MapMode aOldMap( MAP_TWIP );
807 OutputDevice* pOut = rInf.GetOut();
808 OutputDevice* pWin;
809 if( rInf.GetVsh() && rInf.GetVsh()->GetWin() )
810 pWin = rInf.GetVsh()->GetWin();
811 else
812 pWin = GetpApp()->GetDefaultDevice();
814 while( bGrow )
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;
822 while ( pCurrPart )
824 // current font
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() ) &&
845 ! aRect.IsEmpty();
847 if ( ! bHaveGlyphRect )
849 // getting glyph boundaries failed for some reason,
850 // we take the window for calculating sizes
851 if ( pWin )
853 if ( ! bWinUsed )
855 bWinUsed = sal_True;
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() ) &&
864 ! aRect.IsEmpty();
866 if ( bHaveGlyphRect )
868 FontMetric aWinMet( pWin->GetFontMetric() );
869 nAscent = (KSHORT) aWinMet.GetAscent();
871 else
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
879 // font
881 // reset font size and proportion
882 rFnt.SetSize( aOldSize, rFnt.GetActual() );
883 rFnt.SetProportion( nOldProp );
885 if ( bFirstGlyphRect )
887 aCommonRect = aRect;
888 bFirstGlyphRect = sal_False;
890 else
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();
906 if ( nDescent < 0 )
907 nDescent = -nDescent;
909 else
911 nDescent = aCommonRect.Bottom();
912 nAscent = aCommonRect.Top();
914 if ( nAscent < 0 )
915 nAscent = -nAscent;
917 const long nHght = nAscent + nDescent;
918 if ( nHght )
920 if ( nHght > nWishedHeight )
921 nMax = nFactor;
922 else
924 if ( bUseCache )
925 aFactor[ nTmpIdx ] = (sal_uInt16)nFactor;
926 nMin = nFactor;
929 nFactor = ( nFactor * nWishedHeight ) / nHght;
930 bGrow = ( nFactor > nMin ) && ( nFactor < nMax );
931 #if OSL_DEBUG_LEVEL > 1
932 if ( bGrow )
933 nGrow++;
934 #endif
935 nIdx = rInf.GetIdx();
937 else
938 bGrow = sal_False;
941 if ( bWinUsed )
943 // reset window if it has been used
944 pWin->SetMapMode( aOldMap );
945 pWin->SetFont( aOldFnt );
948 if ( bUseCache )
949 aDescent[ nTmpIdx ] = -short( nDescent );
952 pCurrPart = pDrop->GetPart();
954 // did made any new calculations or did we use the cache?
955 if ( -1 == nFactor )
957 nFactor = aFactor[ nTmpIdx ];
958 nDescent = aDescent[ nTmpIdx ];
960 else
961 nDescent = -nDescent;
963 while ( pCurrPart )
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 /*************************************************************************
980 * virtual Format()
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 )
993 if( !pDropCapCache )
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;
1004 while ( pCurrPart )
1006 rInf.SetLen( pCurrPart->GetLen() );
1007 SwFont& rFnt = pCurrPart->GetFont();
1009 SwFontSave aFontSave( rInf, &rFnt );
1010 bFull = FormatTxt( rInf );
1012 if ( bFull )
1013 break;
1016 const SwTwips nTmpWidth =
1017 ( InSpaceGrp() && rInf.GetSpaceAdd() ) ?
1018 Width() + CalcSpacing( rInf.GetSpaceAdd(), rInf ) :
1019 Width();
1021 // set values
1022 pCurrPart->SetWidth( (sal_uInt16)nTmpWidth );
1024 // Move
1025 rInf.SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
1026 rInf.X( rInf.X() + nTmpWidth );
1027 pCurrPart = pCurrPart->GetFollow();
1030 Width( (sal_uInt16)(rInf.X() - nOldX) );
1033 // reset my length
1034 SetLen( rInf.GetLen() );
1036 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1037 if( ! bFull )
1038 bFull = lcl_IsDropFlyInter( rInf, Width(), nDropHeight );
1040 if( bFull )
1042 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1043 if ( !Height() )
1044 Height( rInf.GetTxtHeight() );
1046 // Jetzt noch einmal der ganze Spass
1047 nDropHeight = nLines = 0;
1048 delete pPart;
1049 pPart = NULL;
1051 // meanwhile use normal formatting
1052 bFull = SwTxtPortion::Format( rInf );
1054 else
1055 rInf.SetDropInit( sal_True );
1057 Height( rInf.GetTxtHeight() );
1058 SetAscent( rInf.GetAscent() );
1060 else
1061 bFull = SwTxtPortion::Format( rInf );
1063 if( bFull )
1064 nDistance = 0;
1065 else
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 ) )
1071 nDistance = 0;
1073 Width( Width() + nDistance );
1075 return bFull;
1078 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */