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