xref: /aoo41x/main/sw/source/core/text/txtdrop.cxx (revision efeef26f)
1*efeef26fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*efeef26fSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*efeef26fSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*efeef26fSAndrew Rist  * distributed with this work for additional information
6*efeef26fSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*efeef26fSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*efeef26fSAndrew Rist  * "License"); you may not use this file except in compliance
9*efeef26fSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*efeef26fSAndrew Rist  *
11*efeef26fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*efeef26fSAndrew Rist  *
13*efeef26fSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*efeef26fSAndrew Rist  * software distributed under the License is distributed on an
15*efeef26fSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*efeef26fSAndrew Rist  * KIND, either express or implied.  See the License for the
17*efeef26fSAndrew Rist  * specific language governing permissions and limitations
18*efeef26fSAndrew Rist  * under the License.
19*efeef26fSAndrew Rist  *
20*efeef26fSAndrew Rist  *************************************************************/
21*efeef26fSAndrew Rist 
22*efeef26fSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sw.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir 
28cdf0e10cSrcweir #include <hintids.hxx>
29cdf0e10cSrcweir #include <vcl/metric.hxx>
30cdf0e10cSrcweir #include <vcl/window.hxx>
31cdf0e10cSrcweir #include <vcl/svapp.hxx>
32cdf0e10cSrcweir #include <paratr.hxx>
33cdf0e10cSrcweir #include <txtfrm.hxx>   // Format()
34cdf0e10cSrcweir #include <charfmt.hxx>
35cdf0e10cSrcweir #include <viewopt.hxx>  // SwViewOption
36cdf0e10cSrcweir #include <viewsh.hxx>	// ViewShell
37cdf0e10cSrcweir #include <pordrop.hxx>
38cdf0e10cSrcweir #include <itrform2.hxx>
39cdf0e10cSrcweir #include <txtpaint.hxx> // SwSaveClip
40cdf0e10cSrcweir #include <blink.hxx>	// pBlink
41cdf0e10cSrcweir #include <breakit.hxx>
42cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptType.hdl>
43cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hpp>
44cdf0e10cSrcweir #include <editeng/langitem.hxx>
45cdf0e10cSrcweir #include <charatr.hxx>
46cdf0e10cSrcweir #include <editeng/fhgtitem.hxx>
47cdf0e10cSrcweir #include <switerator.hxx>
48cdf0e10cSrcweir 
49cdf0e10cSrcweir using namespace ::com::sun::star::i18n;
50cdf0e10cSrcweir using namespace ::com::sun::star;
51cdf0e10cSrcweir 
52cdf0e10cSrcweir /*************************************************************************
53cdf0e10cSrcweir  *                lcl_IsDropFlyInter
54cdf0e10cSrcweir  *
55cdf0e10cSrcweir  *  Calculates if a drop caps portion intersects with a fly
56cdf0e10cSrcweir  *  The width and height of the drop caps portion are passed as arguments,
57cdf0e10cSrcweir  *  the position is calculated from the values in rInf
58cdf0e10cSrcweir  *************************************************************************/
59cdf0e10cSrcweir 
lcl_IsDropFlyInter(const SwTxtFormatInfo & rInf,sal_uInt16 nWidth,sal_uInt16 nHeight)60cdf0e10cSrcweir sal_Bool lcl_IsDropFlyInter( const SwTxtFormatInfo &rInf,
61cdf0e10cSrcweir                              sal_uInt16 nWidth, sal_uInt16 nHeight )
62cdf0e10cSrcweir {
63cdf0e10cSrcweir     const SwTxtFly *pTxtFly = rInf.GetTxtFly();
64cdf0e10cSrcweir     if( pTxtFly && pTxtFly->IsOn() )
65cdf0e10cSrcweir     {
66cdf0e10cSrcweir         SwRect aRect( rInf.GetTxtFrm()->Frm().Pos(), Size( nWidth, nHeight) );
67cdf0e10cSrcweir         aRect.Pos() += rInf.GetTxtFrm()->Prt().Pos();
68cdf0e10cSrcweir         aRect.Pos().X() += rInf.X();
69cdf0e10cSrcweir         aRect.Pos().Y() = rInf.Y();
70cdf0e10cSrcweir         aRect = pTxtFly->GetFrm( aRect );
71cdf0e10cSrcweir         return aRect.HasArea();
72cdf0e10cSrcweir     }
73cdf0e10cSrcweir 
74cdf0e10cSrcweir     return sal_False;
75cdf0e10cSrcweir }
76cdf0e10cSrcweir 
77cdf0e10cSrcweir /*************************************************************************
78cdf0e10cSrcweir  *                class SwDropSave
79cdf0e10cSrcweir  *************************************************************************/
80cdf0e10cSrcweir 
81cdf0e10cSrcweir class SwDropSave
82cdf0e10cSrcweir {
83cdf0e10cSrcweir     SwTxtPaintInfo* pInf;
84cdf0e10cSrcweir     xub_StrLen nIdx;
85cdf0e10cSrcweir     xub_StrLen nLen;
86cdf0e10cSrcweir     long nX;
87cdf0e10cSrcweir     long nY;
88cdf0e10cSrcweir 
89cdf0e10cSrcweir public:
90cdf0e10cSrcweir     SwDropSave( const SwTxtPaintInfo &rInf );
91cdf0e10cSrcweir     ~SwDropSave();
92cdf0e10cSrcweir };
93cdf0e10cSrcweir 
SwDropSave(const SwTxtPaintInfo & rInf)94cdf0e10cSrcweir SwDropSave::SwDropSave( const SwTxtPaintInfo &rInf ) :
95cdf0e10cSrcweir         pInf( ((SwTxtPaintInfo*)&rInf) ), nIdx( rInf.GetIdx() ),
96cdf0e10cSrcweir         nLen( rInf.GetLen() ), nX( rInf.X() ), nY( rInf.Y() )
97cdf0e10cSrcweir {
98cdf0e10cSrcweir }
99cdf0e10cSrcweir 
~SwDropSave()100cdf0e10cSrcweir SwDropSave::~SwDropSave()
101cdf0e10cSrcweir {
102cdf0e10cSrcweir     pInf->SetIdx( nIdx );
103cdf0e10cSrcweir     pInf->SetLen( nLen );
104cdf0e10cSrcweir     pInf->X( nX );
105cdf0e10cSrcweir     pInf->Y( nY );
106cdf0e10cSrcweir }
107cdf0e10cSrcweir 
108cdf0e10cSrcweir /*************************************************************************
109cdf0e10cSrcweir  *                SwDropPortionPart DTor
110cdf0e10cSrcweir  *************************************************************************/
111cdf0e10cSrcweir 
~SwDropPortionPart()112cdf0e10cSrcweir SwDropPortionPart::~SwDropPortionPart()
113cdf0e10cSrcweir {
114cdf0e10cSrcweir     if ( pFollow )
115cdf0e10cSrcweir         delete pFollow;
116cdf0e10cSrcweir     delete pFnt;
117cdf0e10cSrcweir }
118cdf0e10cSrcweir 
119cdf0e10cSrcweir /*************************************************************************
120cdf0e10cSrcweir  *                SwDropPortion CTor, DTor
121cdf0e10cSrcweir  *************************************************************************/
122cdf0e10cSrcweir 
SwDropPortion(const MSHORT nLineCnt,const KSHORT nDrpHeight,const KSHORT nDrpDescent,const KSHORT nDist)123cdf0e10cSrcweir SwDropPortion::SwDropPortion( const MSHORT nLineCnt,
124cdf0e10cSrcweir                               const KSHORT nDrpHeight,
125cdf0e10cSrcweir                               const KSHORT nDrpDescent,
126cdf0e10cSrcweir                               const KSHORT nDist )
127cdf0e10cSrcweir   : pPart( 0 ),
128cdf0e10cSrcweir     nLines( nLineCnt ),
129cdf0e10cSrcweir     nDropHeight(nDrpHeight),
130cdf0e10cSrcweir     nDropDescent(nDrpDescent),
131cdf0e10cSrcweir     nDistance(nDist),
132cdf0e10cSrcweir     nFix(0),
133cdf0e10cSrcweir     nX(0)
134cdf0e10cSrcweir {
135cdf0e10cSrcweir     SetWhichPor( POR_DROP );
136cdf0e10cSrcweir }
137cdf0e10cSrcweir 
~SwDropPortion()138cdf0e10cSrcweir SwDropPortion::~SwDropPortion()
139cdf0e10cSrcweir {
140cdf0e10cSrcweir     delete pPart;
141cdf0e10cSrcweir 	if( pBlink )
142cdf0e10cSrcweir 		pBlink->Delete( this );
143cdf0e10cSrcweir }
144cdf0e10cSrcweir 
_HasHint(const SwTxtNode * pTxtNode,xub_StrLen nPos)145cdf0e10cSrcweir sal_Bool SwTxtSizeInfo::_HasHint( const SwTxtNode* pTxtNode, xub_StrLen nPos )
146cdf0e10cSrcweir {
147cdf0e10cSrcweir     return 0 != pTxtNode->GetTxtAttrForCharAt(nPos);
148cdf0e10cSrcweir }
149cdf0e10cSrcweir 
150cdf0e10cSrcweir /*************************************************************************
151cdf0e10cSrcweir  *					  SwTxtNode::GetDropLen()
152cdf0e10cSrcweir  *
153cdf0e10cSrcweir  * nWishLen = 0 indicates that we want a whole word
154cdf0e10cSrcweir  *************************************************************************/
155cdf0e10cSrcweir 
GetDropLen(MSHORT nWishLen) const156cdf0e10cSrcweir MSHORT SwTxtNode::GetDropLen( MSHORT nWishLen ) const
157cdf0e10cSrcweir {
158cdf0e10cSrcweir     xub_StrLen nEnd = GetTxt().Len();
159cdf0e10cSrcweir     if( nWishLen && nWishLen < nEnd )
160cdf0e10cSrcweir         nEnd = nWishLen;
161cdf0e10cSrcweir 
162cdf0e10cSrcweir     if ( ! nWishLen && pBreakIt->GetBreakIter().is() )
163cdf0e10cSrcweir     {
164cdf0e10cSrcweir         // find first word
165cdf0e10cSrcweir         const SwAttrSet& rAttrSet = GetSwAttrSet();
166cdf0e10cSrcweir         const sal_uInt16 nTxtScript = pBreakIt->GetRealScriptOfText( GetTxt(), 0 );
167cdf0e10cSrcweir 
168cdf0e10cSrcweir         LanguageType eLanguage;
169cdf0e10cSrcweir 
170cdf0e10cSrcweir         switch ( nTxtScript )
171cdf0e10cSrcweir         {
172cdf0e10cSrcweir         case i18n::ScriptType::ASIAN :
173cdf0e10cSrcweir             eLanguage = rAttrSet.GetCJKLanguage().GetLanguage();
174cdf0e10cSrcweir             break;
175cdf0e10cSrcweir         case i18n::ScriptType::COMPLEX :
176cdf0e10cSrcweir             eLanguage = rAttrSet.GetCTLLanguage().GetLanguage();
177cdf0e10cSrcweir             break;
178cdf0e10cSrcweir         default :
179cdf0e10cSrcweir             eLanguage = rAttrSet.GetLanguage().GetLanguage();
180cdf0e10cSrcweir             break;
181cdf0e10cSrcweir         }
182cdf0e10cSrcweir 
183cdf0e10cSrcweir         Boundary aBound =
184cdf0e10cSrcweir             pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), 0,
185cdf0e10cSrcweir             pBreakIt->GetLocale( eLanguage ), WordType::DICTIONARY_WORD, sal_True );
186cdf0e10cSrcweir 
187cdf0e10cSrcweir         nEnd = (xub_StrLen)aBound.endPos;
188cdf0e10cSrcweir     }
189cdf0e10cSrcweir 
190cdf0e10cSrcweir     xub_StrLen i = 0;
191cdf0e10cSrcweir     for( ; i < nEnd; ++i )
192cdf0e10cSrcweir     {
193cdf0e10cSrcweir         xub_Unicode cChar = GetTxt().GetChar( i );
194cdf0e10cSrcweir         if( CH_TAB == cChar || CH_BREAK == cChar ||
195cdf0e10cSrcweir             (( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar )
196cdf0e10cSrcweir                 && SwTxtSizeInfo::_HasHint( this, i ) ) )
197cdf0e10cSrcweir             break;
198cdf0e10cSrcweir     }
199cdf0e10cSrcweir     return i;
200cdf0e10cSrcweir }
201cdf0e10cSrcweir 
202cdf0e10cSrcweir /*************************************************************************
203cdf0e10cSrcweir  *                    SwTxtNode::GetDropSize()
204cdf0e10cSrcweir  *
205cdf0e10cSrcweir  *  If a dropcap is found the return value is true otherwise false. The
206cdf0e10cSrcweir  *  drop cap sizes passed back by reference are font height, drop height
207cdf0e10cSrcweir  *  and drop descent.
208cdf0e10cSrcweir  *************************************************************************/
GetDropSize(int & rFontHeight,int & rDropHeight,int & rDropDescent) const209cdf0e10cSrcweir bool SwTxtNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const
210cdf0e10cSrcweir {
211cdf0e10cSrcweir     rFontHeight = 0;
212cdf0e10cSrcweir     rDropHeight = 0;
213cdf0e10cSrcweir     rDropDescent =0;
214cdf0e10cSrcweir 
215cdf0e10cSrcweir     const SwAttrSet& rSet = GetSwAttrSet();
216cdf0e10cSrcweir     const SwFmtDrop& rDrop = rSet.GetDrop();
217cdf0e10cSrcweir 
218cdf0e10cSrcweir     // Return (0,0) if there is no drop cap at this paragraph
219cdf0e10cSrcweir     if( 1 >= rDrop.GetLines() ||
220cdf0e10cSrcweir         ( !rDrop.GetChars() && !rDrop.GetWholeWord() ) )
221cdf0e10cSrcweir     {
222cdf0e10cSrcweir         return false;
223cdf0e10cSrcweir     }
224cdf0e10cSrcweir 
225cdf0e10cSrcweir     // get text frame
226cdf0e10cSrcweir     SwIterator<SwTxtFrm,SwTxtNode> aIter( *this );
227cdf0e10cSrcweir     for( SwTxtFrm* pLastFrm = aIter.First(); pLastFrm; pLastFrm = aIter.Next() )
228cdf0e10cSrcweir     {
229cdf0e10cSrcweir         // Only (master-) text frames can have a drop cap.
230cdf0e10cSrcweir         if ( !pLastFrm->IsFollow() )
231cdf0e10cSrcweir         {
232cdf0e10cSrcweir 
233cdf0e10cSrcweir             if( !pLastFrm->HasPara() )
234cdf0e10cSrcweir                 pLastFrm->GetFormatted();
235cdf0e10cSrcweir 
236cdf0e10cSrcweir             if ( !pLastFrm->IsEmpty() )
237cdf0e10cSrcweir             {
238cdf0e10cSrcweir                 const SwParaPortion* pPara = pLastFrm->GetPara();
239cdf0e10cSrcweir                 ASSERT( pPara, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" )
240cdf0e10cSrcweir 
241cdf0e10cSrcweir                 if ( pPara )
242cdf0e10cSrcweir                 {
243cdf0e10cSrcweir                     const SwLinePortion* pFirstPor = pPara->GetFirstPortion();
244cdf0e10cSrcweir                     if (pFirstPor && pFirstPor->IsDropPortion())
245cdf0e10cSrcweir                     {
246cdf0e10cSrcweir                         const SwDropPortion* pDrop = (const SwDropPortion*)pFirstPor;
247cdf0e10cSrcweir                         rDropHeight = pDrop->GetDropHeight();
248cdf0e10cSrcweir                         rDropDescent = pDrop->GetDropDescent();
249cdf0e10cSrcweir                         if (const SwFont *pFont = pDrop->GetFnt())
250cdf0e10cSrcweir                             rFontHeight = pFont->GetSize(pFont->GetActual()).Height();
251cdf0e10cSrcweir                         else
252cdf0e10cSrcweir                         {
253cdf0e10cSrcweir                             const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get(RES_CHRATR_FONTSIZE);
254cdf0e10cSrcweir                             rFontHeight = rItem.GetHeight();
255cdf0e10cSrcweir                         }
256cdf0e10cSrcweir                     }
257cdf0e10cSrcweir                 }
258cdf0e10cSrcweir             }
259cdf0e10cSrcweir             break;
260cdf0e10cSrcweir         }
261cdf0e10cSrcweir     }
262cdf0e10cSrcweir 
263cdf0e10cSrcweir     if (rFontHeight==0 && rDropHeight==0 && rDropDescent==0)
264cdf0e10cSrcweir     {
265cdf0e10cSrcweir         const sal_uInt16 nLines = rDrop.GetLines();
266cdf0e10cSrcweir 
267cdf0e10cSrcweir         const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get( RES_CHRATR_FONTSIZE );
268cdf0e10cSrcweir         rFontHeight = rItem.GetHeight();
269cdf0e10cSrcweir         rDropHeight = nLines * rFontHeight;
270cdf0e10cSrcweir         rDropDescent = rFontHeight / 5;
271cdf0e10cSrcweir         return false;
272cdf0e10cSrcweir     }
273cdf0e10cSrcweir 
274cdf0e10cSrcweir     return true;
275cdf0e10cSrcweir }
276cdf0e10cSrcweir 
277cdf0e10cSrcweir /*************************************************************************
278cdf0e10cSrcweir  *					  SwDropPortion::PaintTxt()
279cdf0e10cSrcweir  *************************************************************************/
280cdf0e10cSrcweir 
281cdf0e10cSrcweir // Die Breite manipulieren, sonst werden die Buchstaben gestretcht
282cdf0e10cSrcweir 
PaintTxt(const SwTxtPaintInfo & rInf) const283cdf0e10cSrcweir void SwDropPortion::PaintTxt( const SwTxtPaintInfo &rInf ) const
284cdf0e10cSrcweir {
285cdf0e10cSrcweir     if ( rInf.OnWin() &&
286cdf0e10cSrcweir         !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings()    )
287cdf0e10cSrcweir         rInf.DrawBackground( *this );
288cdf0e10cSrcweir 
289cdf0e10cSrcweir     ASSERT( nDropHeight && pPart && nLines != 1, "Drop Portion painted twice" );
290cdf0e10cSrcweir 
291cdf0e10cSrcweir     const SwDropPortionPart* pCurrPart = GetPart();
292cdf0e10cSrcweir     const xub_StrLen nOldLen = GetLen();
293cdf0e10cSrcweir 
294cdf0e10cSrcweir     const SwTwips nBasePosY  = rInf.Y();
295cdf0e10cSrcweir     ((SwTxtPaintInfo&)rInf).Y( nBasePosY + nY );
296cdf0e10cSrcweir     SwDropSave aSave( rInf );
297cdf0e10cSrcweir     // for text inside drop portions we let vcl handle the text directions
298cdf0e10cSrcweir     SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
299cdf0e10cSrcweir     aLayoutModeModifier.SetAuto();
300cdf0e10cSrcweir 
301cdf0e10cSrcweir     while ( pCurrPart )
302cdf0e10cSrcweir     {
303cdf0e10cSrcweir         ((SwDropPortion*)this)->SetLen( pCurrPart->GetLen() );
304cdf0e10cSrcweir         ((SwTxtPaintInfo&)rInf).SetLen( pCurrPart->GetLen() );
305cdf0e10cSrcweir         SwFontSave aFontSave( rInf, &pCurrPart->GetFont() );
306cdf0e10cSrcweir 
307cdf0e10cSrcweir         SwTxtPortion::Paint( rInf );
308cdf0e10cSrcweir 
309cdf0e10cSrcweir         ((SwTxtPaintInfo&)rInf).SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
310cdf0e10cSrcweir         ((SwTxtPaintInfo&)rInf).X( rInf.X() + pCurrPart->GetWidth() );
311cdf0e10cSrcweir         pCurrPart = pCurrPart->GetFollow();
312cdf0e10cSrcweir     }
313cdf0e10cSrcweir 
314cdf0e10cSrcweir     ((SwTxtPaintInfo&)rInf).Y( nBasePosY );
315cdf0e10cSrcweir     ((SwDropPortion*)this)->SetLen( nOldLen );
316cdf0e10cSrcweir }
317cdf0e10cSrcweir 
318cdf0e10cSrcweir /*************************************************************************
319cdf0e10cSrcweir  *					 SwDropPortion::Paint()
320cdf0e10cSrcweir  *************************************************************************/
321cdf0e10cSrcweir 
PaintDrop(const SwTxtPaintInfo & rInf) const322cdf0e10cSrcweir void SwDropPortion::PaintDrop( const SwTxtPaintInfo &rInf ) const
323cdf0e10cSrcweir {
324cdf0e10cSrcweir     // ganz normale Ausgabe wird w?hrend des normalen Paints erledigt
325cdf0e10cSrcweir     if( ! nDropHeight || ! pPart || nLines == 1 )
326cdf0e10cSrcweir 		return;
327cdf0e10cSrcweir 
328cdf0e10cSrcweir 	// Luegenwerte einstellen!
329cdf0e10cSrcweir     const KSHORT nOldHeight = Height();
330cdf0e10cSrcweir     const KSHORT nOldWidth  = Width();
331cdf0e10cSrcweir     const KSHORT nOldAscent = GetAscent();
332cdf0e10cSrcweir     const SwTwips nOldPosY  = rInf.Y();
333cdf0e10cSrcweir     const KSHORT nOldPosX   = (KSHORT)rInf.X();
334cdf0e10cSrcweir 	const SwParaPortion *pPara = rInf.GetParaPortion();
335cdf0e10cSrcweir 	const Point aOutPos( nOldPosX + nX, nOldPosY - pPara->GetAscent()
336cdf0e10cSrcweir 						 - pPara->GetRealHeight() + pPara->Height() );
337cdf0e10cSrcweir 	// Retusche nachholen.
338cdf0e10cSrcweir 
339cdf0e10cSrcweir     // Set baseline
340cdf0e10cSrcweir     ((SwTxtPaintInfo&)rInf).Y( aOutPos.Y() + nDropHeight );
341cdf0e10cSrcweir 
342cdf0e10cSrcweir     // for background
343cdf0e10cSrcweir     ((SwDropPortion*)this)->Height( nDropHeight + nDropDescent );
344cdf0e10cSrcweir     ((SwDropPortion*)this)->Width( Width() - nX );
345cdf0e10cSrcweir     ((SwDropPortion*)this)->SetAscent( nDropHeight );
346cdf0e10cSrcweir 
347cdf0e10cSrcweir 	// Clipregion auf uns einstellen!
348cdf0e10cSrcweir 	// Und zwar immer, und nie mit dem bestehenden ClipRect
349cdf0e10cSrcweir 	// verrechnen, weil dies auf die Zeile eingestellt sein koennte.
350cdf0e10cSrcweir 
351cdf0e10cSrcweir 	SwRect aClipRect;
352cdf0e10cSrcweir 	if ( rInf.OnWin() )
353cdf0e10cSrcweir 	{
354cdf0e10cSrcweir 		aClipRect = SwRect( aOutPos, SvLSize() );
355cdf0e10cSrcweir 		aClipRect.Intersection( rInf.GetPaintRect() );
356cdf0e10cSrcweir 	}
357cdf0e10cSrcweir 	SwSaveClip aClip( (OutputDevice*)rInf.GetOut() );
358cdf0e10cSrcweir     aClip.ChgClip( aClipRect, rInf.GetTxtFrm() );
359cdf0e10cSrcweir     // Das machen, was man sonst nur macht ...
360cdf0e10cSrcweir     PaintTxt( rInf );
361cdf0e10cSrcweir 
362cdf0e10cSrcweir     // Alte Werte sichern
363cdf0e10cSrcweir     ((SwDropPortion*)this)->Height( nOldHeight );
364cdf0e10cSrcweir     ((SwDropPortion*)this)->Width( nOldWidth );
365cdf0e10cSrcweir     ((SwDropPortion*)this)->SetAscent( nOldAscent );
366cdf0e10cSrcweir     ((SwTxtPaintInfo&)rInf).Y( nOldPosY );
367cdf0e10cSrcweir }
368cdf0e10cSrcweir 
369cdf0e10cSrcweir /*************************************************************************
370cdf0e10cSrcweir  *				virtual SwDropPortion::Paint()
371cdf0e10cSrcweir  *************************************************************************/
372cdf0e10cSrcweir 
Paint(const SwTxtPaintInfo & rInf) const373cdf0e10cSrcweir void SwDropPortion::Paint( const SwTxtPaintInfo &rInf ) const
374cdf0e10cSrcweir {
375cdf0e10cSrcweir 	// ganz normale Ausgabe wird hier erledigt.
376cdf0e10cSrcweir     if( ! nDropHeight || ! pPart || 1 == nLines )
377cdf0e10cSrcweir     {
378cdf0e10cSrcweir         if ( rInf.OnWin() &&
379cdf0e10cSrcweir             !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings()       )
380cdf0e10cSrcweir             rInf.DrawBackground( *this );
381cdf0e10cSrcweir 
382cdf0e10cSrcweir 		// make sure that font is not rotated
383cdf0e10cSrcweir 		SwFont* pTmpFont = 0;
384cdf0e10cSrcweir         if ( rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() ) )
385cdf0e10cSrcweir 		{
386cdf0e10cSrcweir 			pTmpFont = new SwFont( *rInf.GetFont() );
387cdf0e10cSrcweir 			pTmpFont->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() );
388cdf0e10cSrcweir 		}
389cdf0e10cSrcweir 
390cdf0e10cSrcweir         SwFontSave aFontSave( rInf, pTmpFont );
391cdf0e10cSrcweir         // for text inside drop portions we let vcl handle the text directions
392cdf0e10cSrcweir         SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
393cdf0e10cSrcweir         aLayoutModeModifier.SetAuto();
394cdf0e10cSrcweir 
395cdf0e10cSrcweir 		SwTxtPortion::Paint( rInf );
396cdf0e10cSrcweir         delete pTmpFont;
397cdf0e10cSrcweir     }
398cdf0e10cSrcweir }
399cdf0e10cSrcweir 
400cdf0e10cSrcweir /*************************************************************************
401cdf0e10cSrcweir  *                virtual Format()
402cdf0e10cSrcweir  *************************************************************************/
403cdf0e10cSrcweir 
404cdf0e10cSrcweir 
FormatTxt(SwTxtFormatInfo & rInf)405cdf0e10cSrcweir sal_Bool SwDropPortion::FormatTxt( SwTxtFormatInfo &rInf )
406cdf0e10cSrcweir {
407cdf0e10cSrcweir 	const xub_StrLen nOldLen = GetLen();
408cdf0e10cSrcweir 	const xub_StrLen nOldInfLen = rInf.GetLen();
409cdf0e10cSrcweir 	const sal_Bool bFull = SwTxtPortion::Format( rInf );
410cdf0e10cSrcweir 	if( bFull )
411cdf0e10cSrcweir 	{
412cdf0e10cSrcweir 		// sieht zwar Scheisse aus, aber was soll man schon machen?
413cdf0e10cSrcweir 		rInf.SetUnderFlow( 0 );
414cdf0e10cSrcweir 		Truncate();
415cdf0e10cSrcweir 		SetLen( nOldLen );
416cdf0e10cSrcweir 		rInf.SetLen( nOldInfLen );
417cdf0e10cSrcweir 	}
418cdf0e10cSrcweir 	return bFull;
419cdf0e10cSrcweir }
420cdf0e10cSrcweir 
421cdf0e10cSrcweir /*************************************************************************
422cdf0e10cSrcweir  *                virtual GetTxtSize()
423cdf0e10cSrcweir  *************************************************************************/
424cdf0e10cSrcweir 
425cdf0e10cSrcweir 
GetTxtSize(const SwTxtSizeInfo & rInf) const426cdf0e10cSrcweir SwPosSize SwDropPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
427cdf0e10cSrcweir {
428cdf0e10cSrcweir     sal_uInt16 nMyX = 0;
429cdf0e10cSrcweir     xub_StrLen nIdx = 0;
430cdf0e10cSrcweir 
431cdf0e10cSrcweir     const SwDropPortionPart* pCurrPart = GetPart();
432cdf0e10cSrcweir 
433cdf0e10cSrcweir     // skip parts
434cdf0e10cSrcweir     while ( pCurrPart && nIdx + pCurrPart->GetLen() < rInf.GetLen() )
435cdf0e10cSrcweir     {
436cdf0e10cSrcweir         nMyX = nMyX + pCurrPart->GetWidth();
437cdf0e10cSrcweir         nIdx = nIdx + pCurrPart->GetLen();
438cdf0e10cSrcweir         pCurrPart = pCurrPart->GetFollow();
439cdf0e10cSrcweir     }
440cdf0e10cSrcweir 
441cdf0e10cSrcweir     xub_StrLen nOldIdx = rInf.GetIdx();
442cdf0e10cSrcweir     xub_StrLen nOldLen = rInf.GetLen();
443cdf0e10cSrcweir 
444cdf0e10cSrcweir     ((SwTxtSizeInfo&)rInf).SetIdx( nIdx );
445cdf0e10cSrcweir     ((SwTxtSizeInfo&)rInf).SetLen( rInf.GetLen() - nIdx );
446cdf0e10cSrcweir 
447cdf0e10cSrcweir     // robust
448cdf0e10cSrcweir     SwFontSave aFontSave( rInf, pCurrPart ? &pCurrPart->GetFont() : 0 );
449cdf0e10cSrcweir     SwPosSize aPosSize( SwTxtPortion::GetTxtSize( rInf ) );
450cdf0e10cSrcweir     aPosSize.Width( aPosSize.Width() + nMyX );
451cdf0e10cSrcweir 
452cdf0e10cSrcweir     ((SwTxtSizeInfo&)rInf).SetIdx( nOldIdx );
453cdf0e10cSrcweir     ((SwTxtSizeInfo&)rInf).SetLen( nOldLen );
454cdf0e10cSrcweir 
455cdf0e10cSrcweir     return aPosSize;
456cdf0e10cSrcweir }
457cdf0e10cSrcweir 
458cdf0e10cSrcweir /*************************************************************************
459cdf0e10cSrcweir  *                virtual GetCrsrOfst()
460cdf0e10cSrcweir  *************************************************************************/
461cdf0e10cSrcweir 
GetCrsrOfst(const KSHORT) const462cdf0e10cSrcweir xub_StrLen SwDropPortion::GetCrsrOfst( const KSHORT ) const
463cdf0e10cSrcweir {
464cdf0e10cSrcweir 	return 0;
465cdf0e10cSrcweir }
466cdf0e10cSrcweir 
467cdf0e10cSrcweir /*************************************************************************
468cdf0e10cSrcweir  *                SwTxtFormatter::CalcDropHeight()
469cdf0e10cSrcweir  *************************************************************************/
470cdf0e10cSrcweir 
CalcDropHeight(const MSHORT nLines)471cdf0e10cSrcweir void SwTxtFormatter::CalcDropHeight( const MSHORT nLines )
472cdf0e10cSrcweir {
473cdf0e10cSrcweir 	const SwLinePortion *const pOldCurr = GetCurr();
474cdf0e10cSrcweir 	KSHORT nDropHght = 0;
475cdf0e10cSrcweir 	KSHORT nAscent = 0;
476cdf0e10cSrcweir 	KSHORT nHeight = 0;
477cdf0e10cSrcweir 	KSHORT nDropLns = 0;
478cdf0e10cSrcweir 	sal_Bool bRegisterOld = IsRegisterOn();
479cdf0e10cSrcweir 	bRegisterOn = sal_False;
480cdf0e10cSrcweir 
481cdf0e10cSrcweir 	Top();
482cdf0e10cSrcweir 
483cdf0e10cSrcweir 	while( GetCurr()->IsDummy() )
484cdf0e10cSrcweir 	{
485cdf0e10cSrcweir 		if ( !Next() )
486cdf0e10cSrcweir 			break;
487cdf0e10cSrcweir 	}
488cdf0e10cSrcweir 
489cdf0e10cSrcweir 	// Wenn wir nur eine Zeile haben returnen wir 0
490cdf0e10cSrcweir 	if( GetNext() || GetDropLines() == 1 )
491cdf0e10cSrcweir 	{
492cdf0e10cSrcweir 		for( ; nDropLns < nLines; nDropLns++ )
493cdf0e10cSrcweir 		{
494cdf0e10cSrcweir 			if ( GetCurr()->IsDummy() )
495cdf0e10cSrcweir 				break;
496cdf0e10cSrcweir 			else
497cdf0e10cSrcweir 			{
498cdf0e10cSrcweir 				CalcAscentAndHeight( nAscent, nHeight );
499cdf0e10cSrcweir 				nDropHght = nDropHght + nHeight;
500cdf0e10cSrcweir 				bRegisterOn = bRegisterOld;
501cdf0e10cSrcweir 			}
502cdf0e10cSrcweir 			if ( !Next() )
503cdf0e10cSrcweir 			{
504cdf0e10cSrcweir 				nDropLns++; // Fix: 11356
505cdf0e10cSrcweir 				break;
506cdf0e10cSrcweir 			}
507cdf0e10cSrcweir 		}
508cdf0e10cSrcweir 
509cdf0e10cSrcweir 		// In der letzten Zeile plumpsen wir auf den Zeilenascent!
510cdf0e10cSrcweir 		nDropHght = nDropHght - nHeight;
511cdf0e10cSrcweir 		nDropHght = nDropHght + nAscent;
512cdf0e10cSrcweir 		Top();
513cdf0e10cSrcweir 	}
514cdf0e10cSrcweir 	bRegisterOn = bRegisterOld;
515cdf0e10cSrcweir 	SetDropDescent( nHeight - nAscent );
516cdf0e10cSrcweir 	SetDropHeight( nDropHght );
517cdf0e10cSrcweir 	SetDropLines( nDropLns );
518cdf0e10cSrcweir 	// Alte Stelle wiederfinden!
519cdf0e10cSrcweir 	while( pOldCurr != GetCurr() )
520cdf0e10cSrcweir 	{
521cdf0e10cSrcweir 		if( !Next() )
522cdf0e10cSrcweir 		{
523cdf0e10cSrcweir 			ASSERT( !this, "SwTxtFormatter::_CalcDropHeight: left Toulouse" );
524cdf0e10cSrcweir 			break;
525cdf0e10cSrcweir 		}
526cdf0e10cSrcweir 	}
527cdf0e10cSrcweir }
528cdf0e10cSrcweir 
529cdf0e10cSrcweir /*************************************************************************
530cdf0e10cSrcweir  *                SwTxtFormatter::GuessDropHeight()
531cdf0e10cSrcweir  *
532cdf0e10cSrcweir  *  Wir schaetzen mal, dass die Fonthoehe sich nicht aendert und dass
533cdf0e10cSrcweir  *  erst mindestens soviele Zeilen gibt, wie die DropCap-Einstellung angibt.
534cdf0e10cSrcweir  *
535cdf0e10cSrcweir  *************************************************************************/
536cdf0e10cSrcweir 
537cdf0e10cSrcweir 
538cdf0e10cSrcweir 
GuessDropHeight(const MSHORT nLines)539cdf0e10cSrcweir void SwTxtFormatter::GuessDropHeight( const MSHORT nLines )
540cdf0e10cSrcweir {
541cdf0e10cSrcweir 	ASSERT( nLines, "GuessDropHeight: Give me more Lines!" );
542cdf0e10cSrcweir 	KSHORT nAscent = 0;
543cdf0e10cSrcweir 	KSHORT nHeight = 0;
544cdf0e10cSrcweir 	SetDropLines( nLines );
545cdf0e10cSrcweir 	if ( GetDropLines() > 1 )
546cdf0e10cSrcweir 	{
547cdf0e10cSrcweir 		CalcRealHeight();
548cdf0e10cSrcweir 		CalcAscentAndHeight( nAscent, nHeight );
549cdf0e10cSrcweir 	}
550cdf0e10cSrcweir 	SetDropDescent( nHeight - nAscent );
551cdf0e10cSrcweir 	SetDropHeight( nHeight * nLines - GetDropDescent() );
552cdf0e10cSrcweir }
553cdf0e10cSrcweir 
554cdf0e10cSrcweir /*************************************************************************
555cdf0e10cSrcweir  *                SwTxtFormatter::NewDropPortion
556cdf0e10cSrcweir  *************************************************************************/
557cdf0e10cSrcweir 
NewDropPortion(SwTxtFormatInfo & rInf)558cdf0e10cSrcweir SwDropPortion *SwTxtFormatter::NewDropPortion( SwTxtFormatInfo &rInf )
559cdf0e10cSrcweir {
560cdf0e10cSrcweir 	if( !pDropFmt )
561cdf0e10cSrcweir 		return 0;
562cdf0e10cSrcweir 
563cdf0e10cSrcweir 	xub_StrLen nPorLen = pDropFmt->GetWholeWord() ? 0 : pDropFmt->GetChars();
564cdf0e10cSrcweir     nPorLen = pFrm->GetTxtNode()->GetDropLen( nPorLen );
565cdf0e10cSrcweir 	if( !nPorLen )
566cdf0e10cSrcweir 	{
567cdf0e10cSrcweir 		((SwTxtFormatter*)this)->ClearDropFmt();
568cdf0e10cSrcweir 		return 0;
569cdf0e10cSrcweir 	}
570cdf0e10cSrcweir 
571cdf0e10cSrcweir 	SwDropPortion *pDropPor = 0;
572cdf0e10cSrcweir 
573cdf0e10cSrcweir 	// erste oder zweite Runde?
574cdf0e10cSrcweir 	if ( !( GetDropHeight() || IsOnceMore() ) )
575cdf0e10cSrcweir 	{
576cdf0e10cSrcweir 		if ( GetNext() )
577cdf0e10cSrcweir             CalcDropHeight( pDropFmt->GetLines() );
578cdf0e10cSrcweir 		else
579cdf0e10cSrcweir             GuessDropHeight( pDropFmt->GetLines() );
580cdf0e10cSrcweir 	}
581cdf0e10cSrcweir 
582cdf0e10cSrcweir     // the DropPortion
583cdf0e10cSrcweir     if( GetDropHeight() )
584cdf0e10cSrcweir         pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(),
585cdf0e10cSrcweir                                       GetDropDescent(), pDropFmt->GetDistance() );
586cdf0e10cSrcweir 	else
587cdf0e10cSrcweir         pDropPor = new SwDropPortion( 0,0,0,pDropFmt->GetDistance() );
588cdf0e10cSrcweir 
589cdf0e10cSrcweir     pDropPor->SetLen( nPorLen );
590cdf0e10cSrcweir 
591cdf0e10cSrcweir     // If it was not possible to create a proper drop cap portion
592cdf0e10cSrcweir     // due to avoiding endless loops. We return a drop cap portion
593cdf0e10cSrcweir     // with an empty SwDropCapPart. For these portions the current
594cdf0e10cSrcweir     // font is used.
595cdf0e10cSrcweir     if ( GetDropLines() < 2 )
596cdf0e10cSrcweir     {
597cdf0e10cSrcweir         ((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
598cdf0e10cSrcweir         return pDropPor;
599cdf0e10cSrcweir     }
600cdf0e10cSrcweir 
601cdf0e10cSrcweir     // build DropPortionParts:
602cdf0e10cSrcweir     ASSERT( ! rInf.GetIdx(), "Drop Portion not at 0 position!" );
603cdf0e10cSrcweir     xub_StrLen nNextChg = 0;
604cdf0e10cSrcweir     const SwCharFmt* pFmt = pDropFmt->GetCharFmt();
605cdf0e10cSrcweir     SwDropPortionPart* pCurrPart = 0;
606cdf0e10cSrcweir 
607cdf0e10cSrcweir     while ( nNextChg  < nPorLen )
608cdf0e10cSrcweir     {
609cdf0e10cSrcweir         // check for attribute changes and if the portion has to split:
610cdf0e10cSrcweir         Seek( nNextChg );
611cdf0e10cSrcweir 
612cdf0e10cSrcweir         // the font is deleted in the destructor of the drop portion part
613cdf0e10cSrcweir         SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
614cdf0e10cSrcweir         if ( pFmt )
615cdf0e10cSrcweir         {
616cdf0e10cSrcweir             const SwAttrSet& rSet = pFmt->GetAttrSet();
617cdf0e10cSrcweir             pTmpFnt->SetDiffFnt( &rSet, pFrm->GetTxtNode()->getIDocumentSettingAccess() );
618cdf0e10cSrcweir         }
619cdf0e10cSrcweir 
620cdf0e10cSrcweir         // we do not allow a vertical font for the drop portion
621cdf0e10cSrcweir         pTmpFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() );
622cdf0e10cSrcweir 
623cdf0e10cSrcweir         // find next attribute change / script change
624cdf0e10cSrcweir         const xub_StrLen nTmpIdx = nNextChg;
625cdf0e10cSrcweir         xub_StrLen nNextAttr = Min( GetNextAttr(), rInf.GetTxt().Len() );
626cdf0e10cSrcweir         nNextChg = pScriptInfo->NextScriptChg( nTmpIdx );
627cdf0e10cSrcweir         if( nNextChg > nNextAttr )
628cdf0e10cSrcweir             nNextChg = nNextAttr;
629cdf0e10cSrcweir         if ( nNextChg > nPorLen )
630cdf0e10cSrcweir             nNextChg = nPorLen;
631cdf0e10cSrcweir 
632cdf0e10cSrcweir         SwDropPortionPart* pPart =
633cdf0e10cSrcweir                 new SwDropPortionPart( *pTmpFnt, nNextChg - nTmpIdx );
634cdf0e10cSrcweir 
635cdf0e10cSrcweir         if ( ! pCurrPart )
636cdf0e10cSrcweir             pDropPor->SetPart( pPart );
637cdf0e10cSrcweir         else
638cdf0e10cSrcweir             pCurrPart->SetFollow( pPart );
639cdf0e10cSrcweir 
640cdf0e10cSrcweir         pCurrPart = pPart;
641cdf0e10cSrcweir     }
642cdf0e10cSrcweir 
643cdf0e10cSrcweir 	((SwTxtFormatter*)this)->SetPaintDrop( sal_True );
644cdf0e10cSrcweir 	return pDropPor;
645cdf0e10cSrcweir }
646cdf0e10cSrcweir 
647cdf0e10cSrcweir /*************************************************************************
648cdf0e10cSrcweir  *                SwTxtPainter::PaintDropPortion()
649cdf0e10cSrcweir  *************************************************************************/
650cdf0e10cSrcweir 
651cdf0e10cSrcweir 
652cdf0e10cSrcweir 
PaintDropPortion()653cdf0e10cSrcweir void SwTxtPainter::PaintDropPortion()
654cdf0e10cSrcweir {
655cdf0e10cSrcweir 	const SwDropPortion *pDrop = GetInfo().GetParaPortion()->FindDropPortion();
656cdf0e10cSrcweir 	ASSERT( pDrop, "DrapCop-Portion not available." );
657cdf0e10cSrcweir 	if( !pDrop )
658cdf0e10cSrcweir 		return;
659cdf0e10cSrcweir 
660cdf0e10cSrcweir 	const SwTwips nOldY = GetInfo().Y();
661cdf0e10cSrcweir 
662cdf0e10cSrcweir 	Top();
663cdf0e10cSrcweir 
664cdf0e10cSrcweir     GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
665cdf0e10cSrcweir 	GetInfo().ResetSpaceIdx();
666cdf0e10cSrcweir     GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
667cdf0e10cSrcweir     GetInfo().ResetKanaIdx();
668cdf0e10cSrcweir 
669cdf0e10cSrcweir 	// 8047: Drops und Dummies
670cdf0e10cSrcweir 	while( !pCurr->GetLen() && Next() )
671cdf0e10cSrcweir 		;
672cdf0e10cSrcweir 
673cdf0e10cSrcweir 	// MarginPortion und Adjustment!
674cdf0e10cSrcweir 	const SwLinePortion *pPor = pCurr->GetFirstPortion();
675cdf0e10cSrcweir 	KSHORT nX = 0;
676cdf0e10cSrcweir 	while( pPor && !pPor->IsDropPortion() )
677cdf0e10cSrcweir 	{
678cdf0e10cSrcweir 		nX = nX + pPor->Width();
679cdf0e10cSrcweir 		pPor = pPor->GetPortion();
680cdf0e10cSrcweir 	}
681cdf0e10cSrcweir 	Point aLineOrigin( GetTopLeft() );
682cdf0e10cSrcweir 
683cdf0e10cSrcweir #ifdef NIE
684cdf0e10cSrcweir 	// Retusche nachholen...
685cdf0e10cSrcweir 	if( nX )
686cdf0e10cSrcweir 	{
687cdf0e10cSrcweir 		const Point aPoint( Left(), Y() );
688cdf0e10cSrcweir 		const Size  aSize( nX - 1, GetDropHeight()+GetDropDescent() );
689cdf0e10cSrcweir 		SwRect aRetouche( aPoint, aSize );
690cdf0e10cSrcweir 		GetInfo().DrawRect( aRetouche );
691cdf0e10cSrcweir 	}
692cdf0e10cSrcweir #endif
693cdf0e10cSrcweir 
694cdf0e10cSrcweir 	aLineOrigin.X() += nX;
695cdf0e10cSrcweir 	KSHORT nTmpAscent, nTmpHeight;
696cdf0e10cSrcweir 	CalcAscentAndHeight( nTmpAscent, nTmpHeight );
697cdf0e10cSrcweir 	aLineOrigin.Y() += nTmpAscent;
698cdf0e10cSrcweir 	GetInfo().SetIdx( GetStart() );
699cdf0e10cSrcweir 	GetInfo().SetPos( aLineOrigin );
700cdf0e10cSrcweir 	GetInfo().SetLen( pDrop->GetLen() );
701cdf0e10cSrcweir 
702cdf0e10cSrcweir 	pDrop->PaintDrop( GetInfo() );
703cdf0e10cSrcweir 
704cdf0e10cSrcweir 	GetInfo().Y( nOldY );
705cdf0e10cSrcweir }
706cdf0e10cSrcweir 
707cdf0e10cSrcweir /*************************************************************************
708cdf0e10cSrcweir  *                      clas SwDropCapCache
709cdf0e10cSrcweir  *
710cdf0e10cSrcweir  * Da die Berechnung der Fontgroesse der Initialen ein teures Geschaeft ist,
711cdf0e10cSrcweir  * wird dies durch einen DropCapCache geschleust.
712cdf0e10cSrcweir  *************************************************************************/
713cdf0e10cSrcweir 
714cdf0e10cSrcweir #define DROP_CACHE_SIZE 10
715cdf0e10cSrcweir 
716cdf0e10cSrcweir class SwDropCapCache
717cdf0e10cSrcweir {
718cdf0e10cSrcweir 	long aMagicNo[ DROP_CACHE_SIZE ];
719cdf0e10cSrcweir 	XubString aTxt[ DROP_CACHE_SIZE ];
720cdf0e10cSrcweir     sal_uInt16 aFactor[ DROP_CACHE_SIZE ];
721cdf0e10cSrcweir 	KSHORT aWishedHeight[ DROP_CACHE_SIZE ];
722cdf0e10cSrcweir 	short aDescent[ DROP_CACHE_SIZE ];
723cdf0e10cSrcweir 	MSHORT nIndex;
724cdf0e10cSrcweir public:
725cdf0e10cSrcweir 	SwDropCapCache();
~SwDropCapCache()726cdf0e10cSrcweir 	~SwDropCapCache(){}
727cdf0e10cSrcweir 	void CalcFontSize( SwDropPortion* pDrop, SwTxtFormatInfo &rInf );
728cdf0e10cSrcweir };
729cdf0e10cSrcweir 
730cdf0e10cSrcweir /*************************************************************************
731cdf0e10cSrcweir  *                  SwDropCapCache Ctor / Dtor
732cdf0e10cSrcweir  *************************************************************************/
733cdf0e10cSrcweir 
SwDropCapCache()734cdf0e10cSrcweir SwDropCapCache::SwDropCapCache() : nIndex( 0 )
735cdf0e10cSrcweir {
736cdf0e10cSrcweir 	memset( &aMagicNo, 0, sizeof(aMagicNo) );
737cdf0e10cSrcweir 	memset( &aWishedHeight, 0, sizeof(aWishedHeight) );
738cdf0e10cSrcweir }
739cdf0e10cSrcweir 
DeleteDropCapCache()740cdf0e10cSrcweir void SwDropPortion::DeleteDropCapCache()
741cdf0e10cSrcweir {
742cdf0e10cSrcweir 	delete pDropCapCache;
743cdf0e10cSrcweir }
744cdf0e10cSrcweir 
745cdf0e10cSrcweir /*************************************************************************
746cdf0e10cSrcweir  *                  SwDropCapCache::CalcFontSize
747cdf0e10cSrcweir  *************************************************************************/
748cdf0e10cSrcweir 
CalcFontSize(SwDropPortion * pDrop,SwTxtFormatInfo & rInf)749cdf0e10cSrcweir void SwDropCapCache::CalcFontSize( SwDropPortion* pDrop, SwTxtFormatInfo &rInf )
750cdf0e10cSrcweir {
751cdf0e10cSrcweir 	const void* pFntNo = 0;
752cdf0e10cSrcweir     MSHORT nTmpIdx = 0;
753cdf0e10cSrcweir 
754cdf0e10cSrcweir     ASSERT( pDrop->GetPart(),"DropPortion without part during font calculation");
755cdf0e10cSrcweir 
756cdf0e10cSrcweir     SwDropPortionPart* pCurrPart = pDrop->GetPart();
757cdf0e10cSrcweir     const sal_Bool bUseCache = ! pCurrPart->GetFollow();
758cdf0e10cSrcweir     xub_StrLen nIdx = rInf.GetIdx();
759cdf0e10cSrcweir     XubString aStr( rInf.GetTxt(), nIdx, pCurrPart->GetLen() );
760cdf0e10cSrcweir 
761cdf0e10cSrcweir     long nAscent = 0;
762cdf0e10cSrcweir     long nDescent = 0;
763cdf0e10cSrcweir     long nFactor = -1;
764cdf0e10cSrcweir 
765cdf0e10cSrcweir     if ( bUseCache )
766cdf0e10cSrcweir     {
767cdf0e10cSrcweir         SwFont& rFnt = pCurrPart->GetFont();
768cdf0e10cSrcweir         rFnt.ChkMagic( rInf.GetVsh(), rFnt.GetActual() );
769cdf0e10cSrcweir         rFnt.GetMagic( pFntNo, nTmpIdx, rFnt.GetActual() );
770cdf0e10cSrcweir 
771cdf0e10cSrcweir         nTmpIdx = 0;
772cdf0e10cSrcweir 
773cdf0e10cSrcweir         while( nTmpIdx < DROP_CACHE_SIZE &&
774cdf0e10cSrcweir             ( aTxt[ nTmpIdx ] != aStr || aMagicNo[ nTmpIdx ] != long(pFntNo) ||
775cdf0e10cSrcweir             aWishedHeight[ nTmpIdx ] != pDrop->GetDropHeight() ) )
776cdf0e10cSrcweir             ++nTmpIdx;
777cdf0e10cSrcweir     }
778cdf0e10cSrcweir 
779cdf0e10cSrcweir     // we have to calculate a new font scaling factor if
780cdf0e10cSrcweir     // 1. we did not find a scaling factor in the cache or
781cdf0e10cSrcweir     // 2. we are not allowed to use the cache because the drop portion
782cdf0e10cSrcweir     //    consists of more than one part
783cdf0e10cSrcweir     if( nTmpIdx >= DROP_CACHE_SIZE || ! bUseCache )
784cdf0e10cSrcweir     {
785cdf0e10cSrcweir         ++nIndex;
786cdf0e10cSrcweir         nIndex %= DROP_CACHE_SIZE;
787cdf0e10cSrcweir         nTmpIdx = nIndex;
788cdf0e10cSrcweir 
789cdf0e10cSrcweir         long nWishedHeight = pDrop->GetDropHeight();
790cdf0e10cSrcweir 
791cdf0e10cSrcweir         // find out biggest font size for initial scaling factor
792cdf0e10cSrcweir         long nMaxFontHeight = 0;
793cdf0e10cSrcweir         while ( pCurrPart )
794cdf0e10cSrcweir         {
795cdf0e10cSrcweir             const SwFont& rFnt = pCurrPart->GetFont();
796cdf0e10cSrcweir             const long nCurrHeight = rFnt.GetHeight( rFnt.GetActual() );
797cdf0e10cSrcweir             if ( nCurrHeight > nMaxFontHeight )
798cdf0e10cSrcweir                 nMaxFontHeight = nCurrHeight;
799cdf0e10cSrcweir 
800cdf0e10cSrcweir             pCurrPart = pCurrPart->GetFollow();
801cdf0e10cSrcweir         }
802cdf0e10cSrcweir 
803cdf0e10cSrcweir         nFactor = ( 1000 * nWishedHeight ) / nMaxFontHeight;
804cdf0e10cSrcweir 
805cdf0e10cSrcweir         if ( bUseCache )
806cdf0e10cSrcweir         {
807cdf0e10cSrcweir             // save keys for cache
808cdf0e10cSrcweir             aMagicNo[ nTmpIdx ] = long(pFntNo);
809cdf0e10cSrcweir             aTxt[ nTmpIdx ] = aStr;
810cdf0e10cSrcweir             aWishedHeight[ nTmpIdx ] = KSHORT(nWishedHeight);
811cdf0e10cSrcweir             // save initial scaling factor
812cdf0e10cSrcweir             aFactor[ nTmpIdx ] = (sal_uInt16)nFactor;
813cdf0e10cSrcweir         }
814cdf0e10cSrcweir 
815cdf0e10cSrcweir         sal_Bool bGrow = ( pDrop->GetLen() != 0 );
816cdf0e10cSrcweir 
817cdf0e10cSrcweir         // for growing controll
818cdf0e10cSrcweir         long nMax = KSHRT_MAX;
819cdf0e10cSrcweir         long nMin = nFactor / 2;
820cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
821cdf0e10cSrcweir         long nGrow = 0;
822cdf0e10cSrcweir #endif
823cdf0e10cSrcweir 
824cdf0e10cSrcweir         sal_Bool bWinUsed = sal_False;
825cdf0e10cSrcweir         Font aOldFnt;
826cdf0e10cSrcweir         MapMode aOldMap( MAP_TWIP );
827cdf0e10cSrcweir         OutputDevice* pOut = rInf.GetOut();
828cdf0e10cSrcweir         OutputDevice* pWin;
829cdf0e10cSrcweir         if( rInf.GetVsh() && rInf.GetVsh()->GetWin() )
830cdf0e10cSrcweir             pWin = rInf.GetVsh()->GetWin();
831cdf0e10cSrcweir         else
832cdf0e10cSrcweir             pWin = GetpApp()->GetDefaultDevice();
833cdf0e10cSrcweir 
834cdf0e10cSrcweir         while( bGrow )
835cdf0e10cSrcweir         {
836cdf0e10cSrcweir             // reset pCurrPart to first part
837cdf0e10cSrcweir             pCurrPart = pDrop->GetPart();
838cdf0e10cSrcweir             sal_Bool bFirstGlyphRect = sal_True;
839cdf0e10cSrcweir             sal_Bool bHaveGlyphRect = sal_False;
840cdf0e10cSrcweir             Rectangle aCommonRect, aRect;
841cdf0e10cSrcweir 
842cdf0e10cSrcweir             while ( pCurrPart )
843cdf0e10cSrcweir             {
844cdf0e10cSrcweir                 // current font
845cdf0e10cSrcweir                 SwFont& rFnt = pCurrPart->GetFont();
846cdf0e10cSrcweir 
847cdf0e10cSrcweir                 // Get height including proportion
848cdf0e10cSrcweir                 const sal_uInt16 nCurrHeight =
849cdf0e10cSrcweir                          (sal_uInt16)rFnt.GetHeight( rFnt.GetActual() );
850cdf0e10cSrcweir 
851cdf0e10cSrcweir                 // Get without proportion
852cdf0e10cSrcweir                 const sal_uInt8 nOldProp = rFnt.GetPropr();
853cdf0e10cSrcweir                 rFnt.SetProportion( 100 );
854cdf0e10cSrcweir                 Size aOldSize = Size( 0, rFnt.GetHeight( rFnt.GetActual() ) );
855cdf0e10cSrcweir 
856cdf0e10cSrcweir                 Size aNewSize( 0, ( nFactor * nCurrHeight ) / 1000 );
857cdf0e10cSrcweir                 rFnt.SetSize( aNewSize, rFnt.GetActual() );
858cdf0e10cSrcweir                 rFnt.ChgPhysFnt( rInf.GetVsh(), *pOut );
859cdf0e10cSrcweir 
860cdf0e10cSrcweir                 nAscent = rFnt.GetAscent( rInf.GetVsh(), *pOut );
861cdf0e10cSrcweir 
862cdf0e10cSrcweir                 // Wir besorgen uns das alle Buchstaben umfassende Rechteck:
863cdf0e10cSrcweir                 bHaveGlyphRect = pOut->GetTextBoundRect( aRect, rInf.GetTxt(), 0,
864cdf0e10cSrcweir                                      nIdx, pCurrPart->GetLen() ) &&
865cdf0e10cSrcweir                                  ! aRect.IsEmpty();
866cdf0e10cSrcweir 
867cdf0e10cSrcweir                 if ( ! bHaveGlyphRect )
868cdf0e10cSrcweir                 {
869cdf0e10cSrcweir                     // getting glyph boundaries failed for some reason,
870cdf0e10cSrcweir                     // we take the window for calculating sizes
871cdf0e10cSrcweir                     if ( pWin )
872cdf0e10cSrcweir                     {
873cdf0e10cSrcweir                         if ( ! bWinUsed )
874cdf0e10cSrcweir                         {
875cdf0e10cSrcweir                             bWinUsed = sal_True;
876cdf0e10cSrcweir                             aOldMap = pWin->GetMapMode( );
877cdf0e10cSrcweir                             pWin->SetMapMode( MapMode( MAP_TWIP ) );
878cdf0e10cSrcweir                             aOldFnt = pWin->GetFont();
879cdf0e10cSrcweir                         }
880cdf0e10cSrcweir                         pWin->SetFont( rFnt.GetActualFont() );
881cdf0e10cSrcweir 
882cdf0e10cSrcweir                         bHaveGlyphRect = pWin->GetTextBoundRect( aRect, rInf.GetTxt(), 0,
883cdf0e10cSrcweir                                             nIdx, pCurrPart->GetLen() ) &&
884cdf0e10cSrcweir                                         ! aRect.IsEmpty();
885cdf0e10cSrcweir                     }
886cdf0e10cSrcweir                     if ( bHaveGlyphRect )
887cdf0e10cSrcweir                     {
888cdf0e10cSrcweir                         FontMetric aWinMet( pWin->GetFontMetric() );
889cdf0e10cSrcweir                         nAscent = (KSHORT) aWinMet.GetAscent();
890cdf0e10cSrcweir                     }
891cdf0e10cSrcweir                     else
892cdf0e10cSrcweir                     // We do not have a window or our window could not
893cdf0e10cSrcweir                     // give us glyph boundaries.
894cdf0e10cSrcweir                         aRect = Rectangle( Point( 0, 0 ), Size( 0, nAscent ) );
895cdf0e10cSrcweir                 }
896cdf0e10cSrcweir 
897cdf0e10cSrcweir                 // Now we (hopefully) have a bounding rectangle for the
898cdf0e10cSrcweir                 // glyphs of the current portion and the ascent of the current
899cdf0e10cSrcweir                 // font
900cdf0e10cSrcweir 
901cdf0e10cSrcweir                 // reset font size and proportion
902cdf0e10cSrcweir                 rFnt.SetSize( aOldSize, rFnt.GetActual() );
903cdf0e10cSrcweir                 rFnt.SetProportion( nOldProp );
904cdf0e10cSrcweir 
905cdf0e10cSrcweir                 if ( bFirstGlyphRect )
906cdf0e10cSrcweir                 {
907cdf0e10cSrcweir                     aCommonRect = aRect;
908cdf0e10cSrcweir                     bFirstGlyphRect = sal_False;
909cdf0e10cSrcweir                 }
910cdf0e10cSrcweir                 else
911cdf0e10cSrcweir                     aCommonRect.Union( aRect );
912cdf0e10cSrcweir 
913cdf0e10cSrcweir                 nIdx = nIdx + pCurrPart->GetLen();
914cdf0e10cSrcweir                 pCurrPart = pCurrPart->GetFollow();
915cdf0e10cSrcweir             }
916cdf0e10cSrcweir 
917cdf0e10cSrcweir             // now we have a union ( aCommonRect ) of all glyphs with
918cdf0e10cSrcweir             // respect to a common baseline : 0
919cdf0e10cSrcweir 
920cdf0e10cSrcweir             // get descent and ascent from union
921cdf0e10cSrcweir             if ( rInf.GetTxtFrm()->IsVertical() )
922cdf0e10cSrcweir             {
923cdf0e10cSrcweir                 nDescent = aCommonRect.Left();
924cdf0e10cSrcweir                 nAscent = aCommonRect.Right();
925cdf0e10cSrcweir 
926cdf0e10cSrcweir                 if ( nDescent < 0 )
927cdf0e10cSrcweir                     nDescent = -nDescent;
928cdf0e10cSrcweir             }
929cdf0e10cSrcweir             else
930cdf0e10cSrcweir             {
931cdf0e10cSrcweir                 nDescent = aCommonRect.Bottom();
932cdf0e10cSrcweir                 nAscent = aCommonRect.Top();
933cdf0e10cSrcweir             }
934cdf0e10cSrcweir             if ( nAscent < 0 )
935cdf0e10cSrcweir                 nAscent = -nAscent;
936cdf0e10cSrcweir 
937cdf0e10cSrcweir             const long nHght = nAscent + nDescent;
938cdf0e10cSrcweir             if ( nHght )
939cdf0e10cSrcweir             {
940cdf0e10cSrcweir                 if ( nHght > nWishedHeight )
941cdf0e10cSrcweir                     nMax = nFactor;
942cdf0e10cSrcweir                 else
943cdf0e10cSrcweir                 {
944cdf0e10cSrcweir                     if ( bUseCache )
945cdf0e10cSrcweir                         aFactor[ nTmpIdx ] = (sal_uInt16)nFactor;
946cdf0e10cSrcweir                     nMin = nFactor;
947cdf0e10cSrcweir                 }
948cdf0e10cSrcweir 
949cdf0e10cSrcweir                 nFactor = ( nFactor * nWishedHeight ) / nHght;
950cdf0e10cSrcweir                 bGrow = ( nFactor > nMin ) && ( nFactor < nMax );
951cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
952cdf0e10cSrcweir                 if ( bGrow )
953cdf0e10cSrcweir                     nGrow++;
954cdf0e10cSrcweir #endif
955cdf0e10cSrcweir                 nIdx = rInf.GetIdx();
956cdf0e10cSrcweir             }
957cdf0e10cSrcweir             else
958cdf0e10cSrcweir                 bGrow = sal_False;
959cdf0e10cSrcweir         }
960cdf0e10cSrcweir 
961cdf0e10cSrcweir         if ( bWinUsed )
962cdf0e10cSrcweir         {
963cdf0e10cSrcweir             // reset window if it has been used
964cdf0e10cSrcweir             pWin->SetMapMode( aOldMap );
965cdf0e10cSrcweir             pWin->SetFont( aOldFnt );
966cdf0e10cSrcweir         }
967cdf0e10cSrcweir 
968cdf0e10cSrcweir         if ( bUseCache )
969cdf0e10cSrcweir             aDescent[ nTmpIdx ] = -short( nDescent );
970cdf0e10cSrcweir     }
971cdf0e10cSrcweir 
972cdf0e10cSrcweir     pCurrPart = pDrop->GetPart();
973cdf0e10cSrcweir 
974cdf0e10cSrcweir     // did made any new calculations or did we use the cache?
975cdf0e10cSrcweir     if ( -1 == nFactor )
976cdf0e10cSrcweir     {
977cdf0e10cSrcweir         nFactor = aFactor[ nTmpIdx ];
978cdf0e10cSrcweir         nDescent = aDescent[ nTmpIdx ];
979cdf0e10cSrcweir     }
980cdf0e10cSrcweir     else
981cdf0e10cSrcweir         nDescent = -nDescent;
982cdf0e10cSrcweir 
983cdf0e10cSrcweir     while ( pCurrPart )
984cdf0e10cSrcweir     {
985cdf0e10cSrcweir         // scale current font
986cdf0e10cSrcweir         SwFont& rFnt = pCurrPart->GetFont();
987cdf0e10cSrcweir         Size aNewSize( 0, ( nFactor * rFnt.GetHeight( rFnt.GetActual() ) ) / 1000 );
988cdf0e10cSrcweir 
989cdf0e10cSrcweir         const sal_uInt8 nOldProp = rFnt.GetPropr();
990cdf0e10cSrcweir         rFnt.SetProportion( 100 );
991cdf0e10cSrcweir         rFnt.SetSize( aNewSize, rFnt.GetActual() );
992cdf0e10cSrcweir         rFnt.SetProportion( nOldProp );
993cdf0e10cSrcweir 
994cdf0e10cSrcweir         pCurrPart = pCurrPart->GetFollow();
995cdf0e10cSrcweir     }
996cdf0e10cSrcweir     pDrop->SetY( (short)nDescent );
997cdf0e10cSrcweir }
998cdf0e10cSrcweir 
999cdf0e10cSrcweir /*************************************************************************
1000cdf0e10cSrcweir  *                virtual Format()
1001cdf0e10cSrcweir  *************************************************************************/
1002cdf0e10cSrcweir 
Format(SwTxtFormatInfo & rInf)1003cdf0e10cSrcweir sal_Bool SwDropPortion::Format( SwTxtFormatInfo &rInf )
1004cdf0e10cSrcweir {
1005cdf0e10cSrcweir 	sal_Bool bFull = sal_False;
1006cdf0e10cSrcweir     Fix( (sal_uInt16)rInf.X() );
1007cdf0e10cSrcweir 
1008cdf0e10cSrcweir     SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
1009cdf0e10cSrcweir     aLayoutModeModifier.SetAuto();
1010cdf0e10cSrcweir 
1011cdf0e10cSrcweir     if( nDropHeight && pPart && nLines!=1 )
1012cdf0e10cSrcweir 	{
1013cdf0e10cSrcweir 		if( !pDropCapCache )
1014cdf0e10cSrcweir 			pDropCapCache = new SwDropCapCache();
1015cdf0e10cSrcweir 
1016cdf0e10cSrcweir         // adjust font sizes to fit into the rectangle
1017cdf0e10cSrcweir         pDropCapCache->CalcFontSize( this, rInf );
1018cdf0e10cSrcweir 
1019cdf0e10cSrcweir         const long nOldX = rInf.X();
1020cdf0e10cSrcweir         {
1021cdf0e10cSrcweir             SwDropSave aSave( rInf );
1022cdf0e10cSrcweir             SwDropPortionPart* pCurrPart = pPart;
1023cdf0e10cSrcweir 
1024cdf0e10cSrcweir             while ( pCurrPart )
1025cdf0e10cSrcweir             {
1026cdf0e10cSrcweir                 rInf.SetLen( pCurrPart->GetLen() );
1027cdf0e10cSrcweir                 SwFont& rFnt = pCurrPart->GetFont();
1028cdf0e10cSrcweir                 {
1029cdf0e10cSrcweir                     SwFontSave aFontSave( rInf, &rFnt );
1030cdf0e10cSrcweir                     bFull = FormatTxt( rInf );
1031cdf0e10cSrcweir 
1032cdf0e10cSrcweir                     if ( bFull )
1033cdf0e10cSrcweir                         break;
1034cdf0e10cSrcweir                 }
1035cdf0e10cSrcweir 
1036cdf0e10cSrcweir                 const SwTwips nTmpWidth =
1037cdf0e10cSrcweir                         ( InSpaceGrp() && rInf.GetSpaceAdd() ) ?
1038cdf0e10cSrcweir                         Width() + CalcSpacing( rInf.GetSpaceAdd(), rInf ) :
1039cdf0e10cSrcweir                         Width();
1040cdf0e10cSrcweir 
1041cdf0e10cSrcweir                 // set values
1042cdf0e10cSrcweir                 pCurrPart->SetWidth( (sal_uInt16)nTmpWidth );
1043cdf0e10cSrcweir 
1044cdf0e10cSrcweir                 // Move
1045cdf0e10cSrcweir                 rInf.SetIdx( rInf.GetIdx() + pCurrPart->GetLen() );
1046cdf0e10cSrcweir                 rInf.X( rInf.X() + nTmpWidth );
1047cdf0e10cSrcweir                 pCurrPart = pCurrPart->GetFollow();
1048cdf0e10cSrcweir             }
1049cdf0e10cSrcweir 
1050cdf0e10cSrcweir             Width( (sal_uInt16)(rInf.X() - nOldX) );
1051cdf0e10cSrcweir         }
1052cdf0e10cSrcweir 
1053cdf0e10cSrcweir         // reset my length
1054cdf0e10cSrcweir         SetLen( rInf.GetLen() );
1055cdf0e10cSrcweir 
1056cdf0e10cSrcweir         // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss.
1057cdf0e10cSrcweir         if( ! bFull )
1058cdf0e10cSrcweir             bFull = lcl_IsDropFlyInter( rInf, Width(), nDropHeight );
1059cdf0e10cSrcweir 
1060cdf0e10cSrcweir         if( bFull )
1061cdf0e10cSrcweir 		{
1062cdf0e10cSrcweir 			// Durch FormatTxt kann nHeight auf 0 gesetzt worden sein
1063cdf0e10cSrcweir 			if ( !Height() )
1064cdf0e10cSrcweir 				Height( rInf.GetTxtHeight() );
1065cdf0e10cSrcweir 
1066cdf0e10cSrcweir             // Jetzt noch einmal der ganze Spass
1067cdf0e10cSrcweir             nDropHeight = nLines = 0;
1068cdf0e10cSrcweir             delete pPart;
1069cdf0e10cSrcweir             pPart = NULL;
1070cdf0e10cSrcweir 
1071cdf0e10cSrcweir             // meanwhile use normal formatting
1072cdf0e10cSrcweir             bFull = SwTxtPortion::Format( rInf );
1073cdf0e10cSrcweir 		}
1074cdf0e10cSrcweir 		else
1075cdf0e10cSrcweir 			rInf.SetDropInit( sal_True );
1076cdf0e10cSrcweir 
1077cdf0e10cSrcweir         Height( rInf.GetTxtHeight() );
1078cdf0e10cSrcweir         SetAscent( rInf.GetAscent() );
1079cdf0e10cSrcweir 	}
1080cdf0e10cSrcweir 	else
1081cdf0e10cSrcweir 		bFull = SwTxtPortion::Format( rInf );
1082cdf0e10cSrcweir 
1083cdf0e10cSrcweir 	if( bFull )
1084cdf0e10cSrcweir 		nDistance = 0;
1085cdf0e10cSrcweir 	else
1086cdf0e10cSrcweir 	{
1087cdf0e10cSrcweir 		const KSHORT nWant = Width() + GetDistance();
1088cdf0e10cSrcweir         const KSHORT nRest = (sal_uInt16)(rInf.Width() - rInf.X());
1089cdf0e10cSrcweir         if( ( nWant > nRest ) ||
1090cdf0e10cSrcweir             lcl_IsDropFlyInter( rInf, Width() + GetDistance(), nDropHeight ) )
1091cdf0e10cSrcweir 			nDistance = 0;
1092cdf0e10cSrcweir 
1093cdf0e10cSrcweir 		Width( Width() + nDistance );
1094cdf0e10cSrcweir 	}
1095cdf0e10cSrcweir 	return bFull;
1096cdf0e10cSrcweir }
1097cdf0e10cSrcweir 
1098