1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include "hintids.hxx"
29 #include "flyfrm.hxx" // SwFlyInCntFrm
30 #include "viewopt.hxx" // SwViewOptions
31 #include "errhdl.hxx"
32 #include "txtatr.hxx" // SwINetFmt
33 #include <tools/multisel.hxx>
34 #include <editeng/escpitem.hxx>
35 #include <editeng/udlnitem.hxx>
36 #include <editeng/lrspitem.hxx>
37 #include <txtinet.hxx>
38 #include <fchrfmt.hxx>
39 #include <frmatr.hxx>
40 #include <sfx2/printer.hxx>
41 #include <fmtftn.hxx>
42 #include <fmtfld.hxx>
43 #include <fldbas.hxx> // SwField
44 #include <rootfrm.hxx>
45 #include <pagefrm.hxx>
46 #include <pagedesc.hxx> // SwPageDesc
47 #include <tgrditem.hxx>
48
49 // --> FME 2004-06-08 #i12836# enhanced pdf export
50 #include <EnhancedPDFExportHelper.hxx>
51 // <--
52
53
54 #include "flyfrms.hxx"
55 #include "viewsh.hxx"
56 #include "txtcfg.hxx"
57 #include "itrpaint.hxx"
58 #include "txtfrm.hxx" // pFrm
59 #include "txtfly.hxx"
60 #include "swfont.hxx"
61 #include "txtpaint.hxx"
62 #include "portab.hxx" // SwTabPortion::IsFilled
63 #include "porfly.hxx" // SwFlyCntPortion
64 #include "porfld.hxx" // SwGrfNumPortion
65 #include "frmfmt.hxx" // LRSpace
66 #include "txatbase.hxx" // SwTxtAttr
67 #include "charfmt.hxx" // SwFmtCharFmt
68 #include "redlnitr.hxx" // SwRedlineItr
69 #include "porrst.hxx" // SwArrowPortion
70 #include "pormulti.hxx"
71
72 /*************************************************************************
73 * IsUnderlineBreak
74 *
75 * Returns, if we have an underline breaking situation
76 * Adding some more conditions here means you also have to change them
77 * in SwTxtPainter::CheckSpecialUnderline
78 *************************************************************************/
IsUnderlineBreak(const SwLinePortion & rPor,const SwFont & rFnt)79 sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
80 {
81 return UNDERLINE_NONE == rFnt.GetUnderline() ||
82 rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
83 rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
84 rPor.IsHolePortion() ||
85 ( rPor.IsMultiPortion() && ! ((SwMultiPortion&)rPor).IsBidi() ) ||
86 rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
87 SVX_CASEMAP_KAPITAELCHEN == rFnt.GetCaseMap();
88 }
89
90 /*************************************************************************
91 * SwTxtPainter::CtorInitTxtPainter()
92 *************************************************************************/
CtorInitTxtPainter(SwTxtFrm * pNewFrm,SwTxtPaintInfo * pNewInf)93 void SwTxtPainter::CtorInitTxtPainter( SwTxtFrm *pNewFrm, SwTxtPaintInfo *pNewInf )
94 {
95 CtorInitTxtCursor( pNewFrm, pNewInf );
96 pInf = pNewInf;
97 SwFont *pMyFnt = GetFnt();
98 GetInfo().SetFont( pMyFnt );
99 #ifdef DBG_UTIL
100 if( ALIGN_BASELINE != pMyFnt->GetAlign() )
101 {
102 ASSERT( ALIGN_BASELINE == pMyFnt->GetAlign(),
103 "+SwTxtPainter::CTOR: font alignment revolution" );
104 pMyFnt->SetAlign( ALIGN_BASELINE );
105 }
106 #endif
107 bPaintDrop = sal_False;
108 }
109
110
111 /*************************************************************************
112 * SwTxtPainter::CalcPaintOfst()
113 *************************************************************************/
CalcPaintOfst(const SwRect & rPaint)114 SwLinePortion *SwTxtPainter::CalcPaintOfst( const SwRect &rPaint )
115 {
116 SwLinePortion *pPor = pCurr->GetFirstPortion();
117 GetInfo().SetPaintOfst( 0 );
118 SwTwips nPaintOfst = rPaint.Left();
119
120 // nPaintOfst wurde exakt auf das Ende eingestellt, deswegen <=
121 // nPaintOfst ist dokumentglobal, deswegen nLeftMar aufaddieren
122 // const KSHORT nLeftMar = KSHORT(GetLeftMargin());
123 // 8310: painten von LineBreaks in leeren Zeilen.
124 if( nPaintOfst && pCurr->Width() )
125 {
126 SwLinePortion *pLast = 0;
127 // 7529 und 4757: nicht <= nPaintOfst
128 while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
129 < nPaintOfst )
130 {
131 DBG_LOOP;
132 if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
133 {
134 long nTmp = GetInfo().X() +pPor->Width() +
135 pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
136 if( nTmp + (pPor->Height()/2) >= nPaintOfst )
137 break;
138 GetInfo().X( nTmp );
139 GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
140 }
141 else
142 pPor->Move( GetInfo() );
143 pLast = pPor;
144 pPor = pPor->GetPortion();
145 }
146
147 // 7529: bei PostIts auch pLast returnen.
148 if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
149 {
150 pPor = pLast;
151 GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
152 }
153 }
154 return pPor;
155 }
156
157 /*************************************************************************
158 * SwTxtPainter::DrawTextLine()
159 *
160 * Es gibt zwei Moeglichkeiten bei transparenten Font auszugeben:
161 * 1) DrawRect auf die ganze Zeile und die DrawText hinterher
162 * (objektiv schnell, subjektiv langsam).
163 * 2) Fuer jede Portion ein DrawRect mit anschliessendem DrawText
164 * ausgefuehrt (objektiv langsam, subjektiv schnell).
165 * Da der User in der Regel subjektiv urteilt, wird die 2. Methode
166 * als Default eingestellt.
167 *************************************************************************/
DrawTextLine(const SwRect & rPaint,SwSaveClip & rClip,const sal_Bool bUnderSz)168 void SwTxtPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
169 const sal_Bool bUnderSz )
170 {
171 #if OSL_DEBUG_LEVEL > 1
172 // sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
173 // sal_uInt16 nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
174 #endif
175
176 // Adjustierung ggf. nachholen
177 GetAdjusted();
178 GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
179 GetInfo().ResetSpaceIdx();
180 GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
181 GetInfo().ResetKanaIdx();
182 // Die Groesse des Frames
183 GetInfo().SetIdx( GetStart() );
184 GetInfo().SetPos( GetTopLeft() );
185
186 const sal_Bool bDrawInWindow = GetInfo().OnWin();
187
188 // 6882: Leerzeilen duerfen nicht wegoptimiert werden bei Paragraphzeichen.
189 const sal_Bool bEndPor = GetInfo().GetOpt().IsParagraph() && !GetInfo().GetTxt().Len();
190
191 SwLinePortion *pPor = bEndPor ? pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
192
193 // Optimierung!
194 const SwTwips nMaxRight = Min( rPaint.Right(), Right() );
195 const SwTwips nTmpLeft = GetInfo().X();
196 if( !bEndPor && nTmpLeft >= nMaxRight )
197 return;
198
199 // DropCaps!
200 // 7538: natuerlich auch auf dem Drucker
201 if( !bPaintDrop )
202 {
203 // 8084: Optimierung, weniger Painten.
204 // AMA: Durch 8084 wurde 7538 wiederbelebt!
205 // bDrawInWindow entfernt, damit DropCaps auch gedruckt werden
206 bPaintDrop = pPor == pCurr->GetFirstPortion()
207 && GetDropLines() >= GetLineNr();
208 }
209
210 KSHORT nTmpHeight, nTmpAscent;
211 CalcAscentAndHeight( nTmpAscent, nTmpHeight );
212
213 // bClip entscheidet darueber, ob geclippt werden muss.
214 // Das Ganze muss vor der Retusche stehen
215
216 sal_Bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg();
217 if( bClip && pPor )
218 {
219 // Wenn TopLeft oder BottomLeft der Line ausserhalb liegen,
220 // muss geclippt werden. Die Ueberpruefung auf Right() erfolgt
221 // in der folgenden Ausgabeschleife...
222
223 if( GetInfo().GetPos().X() < rPaint.Left() ||
224 GetInfo().GetPos().Y() < rPaint.Top() ||
225 GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
226 {
227 bClip = sal_False;
228 rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
229 }
230 #if OSL_DEBUG_LEVEL > 1
231 static sal_Bool bClipAlways = sal_False;
232 if( bClip && bClipAlways )
233 { bClip = sal_False;
234 rClip.ChgClip( rPaint );
235 }
236 #endif
237 }
238
239 // Alignment:
240 sal_Bool bPlus = sal_False;
241 OutputDevice* pOut = GetInfo().GetOut();
242 Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
243 if ( aPnt1.X() < rPaint.Left() )
244 aPnt1.X() = rPaint.Left();
245 if ( aPnt1.Y() < rPaint.Top() )
246 aPnt1.Y() = rPaint.Top();
247 Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
248 GetInfo().GetPos().Y() + nTmpHeight );
249 if ( aPnt2.X() > rPaint.Right() )
250 aPnt2.X() = rPaint.Right();
251 if ( aPnt2.Y() > rPaint.Bottom() )
252 {
253 aPnt2.Y() = rPaint.Bottom();
254 bPlus = sal_True;
255 }
256
257 const SwRect aLineRect( aPnt1, aPnt2 );
258
259 if( pCurr->IsClipping() )
260 {
261 rClip.ChgClip( aLineRect, pFrm );
262 bClip = sal_False;
263 }
264
265 if( !pPor && !bEndPor )
266 {
267 #ifdef DBGTXT
268 aDbstream << "PAINTER: done nothing" << endl;
269 #endif
270 return;
271 }
272
273 // Baseline-Ausgabe auch bei nicht-TxtPortions (vgl. TabPor mit Fill)
274 // if no special vertical alignment is used,
275 // we calculate Y value for the whole line
276 GETGRID( GetTxtFrm()->FindPageFrm() )
277 const sal_Bool bAdjustBaseLine =
278 GetLineInfo().HasSpecialAlign( GetTxtFrm()->IsVertical() ) ||
279 ( 0 != pGrid );
280 const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
281 if ( ! bAdjustBaseLine )
282 GetInfo().Y( nLineBaseLine );
283
284 // 7529: PostIts prepainten
285 if( GetInfo().OnWin() && pPor && !pPor->Width() )
286 {
287 SeekAndChg( GetInfo() );
288
289 if( bAdjustBaseLine )
290 {
291 const SwTwips nOldY = GetInfo().Y();
292
293 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, 0,
294 GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
295 GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
296 ) );
297
298 pPor->PrePaint( GetInfo(), pPor );
299 GetInfo().Y( nOldY );
300 }
301 else
302 pPor->PrePaint( GetInfo(), pPor );
303 }
304
305 // 7923: EndPortions geben auch Zeichen aus, deswegen den Fnt wechseln!
306 if( bEndPor )
307 SeekStartAndChg( GetInfo() );
308
309 sal_Bool bRest = pCurr->IsRest();
310 sal_Bool bFirst = sal_True;
311
312 SwArrowPortion *pArrow = NULL;
313 // Reference portion for the paragraph end portion
314 SwLinePortion* pEndTempl = pCurr->GetFirstPortion();
315
316 while( pPor )
317 {
318 DBG_LOOP;
319 sal_Bool bSeeked = sal_True;
320 GetInfo().SetLen( pPor->GetLen() );
321
322 const SwTwips nOldY = GetInfo().Y();
323
324 if ( bAdjustBaseLine )
325 {
326 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, pPor ) );
327
328 // we store the last portion, because a possible paragraph
329 // end character has the same font as this portion
330 // (only in special vertical alignment case, otherwise the first
331 // portion of the line is used)
332 if ( pPor->Width() && pPor->InTxtGrp() )
333 pEndTempl = pPor;
334 }
335
336 // Ein Sonderfall sind GluePortions, die Blanks ausgeben.
337
338 // 6168: Der Rest einer FldPortion zog sich die Attribute der naechsten
339 // Portion an, dies wird durch SeekAndChgBefore vermieden:
340 if( ( bRest && pPor->InFldGrp() && !pPor->GetLen() ) )
341 SeekAndChgBefore( GetInfo() );
342 else if ( pPor->IsQuoVadisPortion() )
343 {
344 xub_StrLen nOffset = GetInfo().GetIdx();
345 SeekStartAndChg( GetInfo(), sal_True );
346 if( GetRedln() && pCurr->HasRedline() )
347 GetRedln()->Seek( *pFnt, nOffset, 0 );
348 }
349 else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
350 SeekAndChg( GetInfo() );
351 else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
352 {
353 // Paragraphzeichen sollten den gleichen Font wie das Zeichen vor
354 // haben, es sei denn, es gibt Redlining in dem Absatz.
355 if( GetRedln() )
356 SeekAndChg( GetInfo() );
357 else
358 SeekAndChgBefore( GetInfo() );
359 }
360 else
361 bSeeked = sal_False;
362
363 // bRest = sal_False;
364
365 // Wenn das Ende der Portion hinausragt, wird geclippt.
366 // Es wird ein Sicherheitsabstand von Height-Halbe aufaddiert,
367 // damit die TTF-"f" nicht im Seitenrand haengen...
368 if( bClip &&
369 GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
370 {
371 bClip = sal_False;
372 rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
373 }
374
375 // Portions, die "unter" dem Text liegen wie PostIts
376 SwLinePortion *pNext = pPor->GetPortion();
377 if( GetInfo().OnWin() && pNext && !pNext->Width() )
378 {
379 // Fix 11289: Felder waren hier ausgeklammert wg. Last!=Owner beim
380 // Laden von Brief.sdw. Jetzt sind die Felder wieder zugelassen,
381 // durch bSeeked wird Last!=Owner vermieden.
382 if ( !bSeeked )
383 SeekAndChg( GetInfo() );
384 pNext->PrePaint( GetInfo(), pPor );
385 }
386
387 // We calculate a separate font for underlining.
388 CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
389 SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
390 if ( pUnderLineFnt )
391 {
392 const Point aTmpPoint( GetInfo().X(),
393 bAdjustBaseLine ?
394 pUnderLineFnt->GetPos().Y() :
395 nLineBaseLine );
396 pUnderLineFnt->SetPos( aTmpPoint );
397 }
398
399
400 // in extended input mode we do not want a common underline font.
401 SwUnderlineFont* pOldUnderLineFnt = 0;
402 if ( GetRedln() && GetRedln()->ExtOn() )
403 {
404 pOldUnderLineFnt = GetInfo().GetUnderFnt();
405 GetInfo().SetUnderFnt( 0 );
406 }
407
408 {
409 // --> FME 2004-06-24 #i16816# tagged pdf support
410 Por_Info aPorInfo( *pPor, *this );
411 SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, &aPorInfo, *pOut );
412 // <--
413
414 if( pPor->IsMultiPortion() )
415 PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor );
416 else
417 pPor->Paint( GetInfo() );
418 }
419
420 // reset underline font
421 if ( pOldUnderLineFnt )
422 GetInfo().SetUnderFnt( pOldUnderLineFnt );
423
424 // reset (for special vertical alignment)
425 GetInfo().Y( nOldY );
426
427 if( GetFnt()->IsURL() && pPor->InTxtGrp() )
428 GetInfo().NotifyURL( *pPor );
429
430 bFirst &= !pPor->GetLen();
431 if( pNext || !pPor->IsMarginPortion() )
432 pPor->Move( GetInfo() );
433 if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
434 pArrow = (SwArrowPortion*)pPor;
435
436 pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
437 // --> FME 2004-06-24 #i16816# tagged pdf support
438 ( GetInfo().GetVsh() &&
439 GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
440 pNext && pNext->IsHolePortion() ) ?
441 // <--
442 pNext :
443 0;
444 }
445
446 // delete underline font
447 delete GetInfo().GetUnderFnt();
448 GetInfo().SetUnderFnt( 0 );
449
450 // paint remaining stuff
451 if( bDrawInWindow )
452 {
453 // If special vertical alignment is enabled, GetInfo().Y() is the
454 // top of the current line. Therefore is has to be adjusted for
455 // the painting of the remaining stuff. We first store the old value.
456 const SwTwips nOldY = GetInfo().Y();
457
458 if( !GetNextLine() &&
459 GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() &&
460 GetInfo().GetOpt().IsParagraph() && !GetTxtFrm()->GetFollow() &&
461 GetInfo().GetIdx() >= GetInfo().GetTxt().Len() )
462 {
463 const SwTmpEndPortion aEnd( *pEndTempl );
464 GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
465
466 if ( bAdjustBaseLine )
467 GetInfo().Y( GetInfo().GetPos().Y()
468 + AdjustBaseLine( *pCurr, &aEnd ) );
469
470 aEnd.Paint( GetInfo() );
471 GetInfo().Y( nOldY );
472 }
473 if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() )
474 {
475 const sal_Bool bNextUndersized =
476 ( GetTxtFrm()->GetNext() &&
477 0 == GetTxtFrm()->GetNext()->Prt().Height() &&
478 GetTxtFrm()->GetNext()->IsTxtFrm() &&
479 ((SwTxtFrm*)GetTxtFrm()->GetNext())->IsUndersized() ) ;
480
481 if( bUnderSz || bNextUndersized )
482 {
483 if ( bAdjustBaseLine )
484 GetInfo().Y( GetInfo().GetPos().Y() + pCurr->GetAscent() );
485
486 if( pArrow )
487 GetInfo().DrawRedArrow( *pArrow );
488
489 // GetInfo().Y() must be current baseline.
490 SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTxtFrm()->Frm().Bottom();
491 if( ( nDiff > 0 &&
492 ( GetEnd() < GetInfo().GetTxt().Len() ||
493 ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
494 (nDiff >= 0 && bNextUndersized) )
495
496 {
497 SwArrowPortion aArrow( GetInfo() );
498 GetInfo().DrawRedArrow( aArrow );
499 }
500
501 GetInfo().Y( nOldY );
502 }
503 }
504 }
505
506 if( pCurr->IsClipping() )
507 rClip.ChgClip( rPaint, pFrm );
508 }
509
CheckSpecialUnderline(const SwLinePortion * pPor,long nAdjustBaseLine)510 void SwTxtPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
511 long nAdjustBaseLine )
512 {
513 // Check if common underline should not be continued.
514 if ( IsUnderlineBreak( *pPor, *pFnt ) )
515 {
516 // delete underline font
517 delete GetInfo().GetUnderFnt();
518 GetInfo().SetUnderFnt( 0 );
519 return;
520 }
521
522 // If current underline matches the common underline font, we continue
523 // to use the common underline font.
524 //Bug 120769:Color of underline display wrongly
525 Color aAutoCo(COL_AUTO);
526 if ( GetInfo().GetUnderFnt() &&
527 GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
528 GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != aAutoCo )
529 return;
530 //Bug 120769(End)
531 // calculate the new common underline font
532 SwFont* pUnderlineFnt = 0;
533 Point aCommonBaseLine;
534
535 Range aRange( 0, GetInfo().GetTxt().Len() );
536 MultiSelection aUnderMulti( aRange );
537
538 ASSERT( GetFnt() && UNDERLINE_NONE != GetFnt()->GetUnderline(),
539 "CheckSpecialUnderline without underlined font" )
540 const SwFont* pParaFnt = GetAttrHandler().GetFont();
541 if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
542 aUnderMulti.SelectAll();
543
544 SwTxtAttr* pTxtAttr;
545 if( HasHints() )
546 {
547 sal_Bool bUnder = sal_False;
548 MSHORT nTmp = 0;
549
550 while( nTmp < pHints->GetStartCount() )
551 {
552 pTxtAttr = pHints->GetStart( nTmp++ );
553 sal_Bool bUnderSelect = sal_False;
554
555 const SvxUnderlineItem* pItem =
556 static_cast<const SvxUnderlineItem*>(CharFmt::GetItem( *pTxtAttr, RES_CHRATR_UNDERLINE ));
557
558 if ( pItem )
559 {
560 bUnder = sal_True;
561 bUnderSelect = pFnt->GetUnderline() == pItem->GetLineStyle();
562 }
563
564 if( bUnder )
565 {
566 xub_StrLen nSt = *pTxtAttr->GetStart();
567 xub_StrLen nEnd = *pTxtAttr->GetEnd();
568 if( nEnd > nSt )
569 {
570 Range aTmp( nSt, nEnd - 1 );
571 if( bUnder )
572 aUnderMulti.Select( aTmp, bUnderSelect );
573 }
574 bUnder = sal_False;
575 }
576 }
577 }
578
579 MSHORT i;
580 xub_StrLen nIndx = GetInfo().GetIdx();
581 long nUnderStart = 0;
582 long nUnderEnd = 0;
583 MSHORT nCnt = (MSHORT)aUnderMulti.GetRangeCount();
584
585 // find the underline range the current portion is contained in
586 for( i = 0; i < nCnt; ++i )
587 {
588 const Range& rRange = aUnderMulti.GetRange( i );
589 if( nUnderEnd == rRange.Min() )
590 nUnderEnd = rRange.Max();
591 else if( nIndx >= rRange.Min() )
592 {
593 nUnderStart = rRange.Min();
594 nUnderEnd = rRange.Max();
595 }
596 else
597 break;
598 }
599
600 // restrict start and end to current line
601 if ( GetStart() > nUnderStart )
602 nUnderStart = GetStart();
603
604 if ( GetEnd() && GetEnd() <= nUnderEnd )
605 nUnderEnd = GetEnd() - 1;
606
607
608 // check, if underlining is not isolated
609 if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 )
610 {
611 //
612 // here starts the algorithm for calculating the underline font
613 //
614 SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
615 SwAttrIter aIter( *(SwTxtNode*)GetInfo().GetTxtFrm()->GetTxtNode(),
616 rScriptInfo );
617
618 xub_StrLen nTmpIdx = nIndx;
619 sal_uLong nSumWidth = 0;
620 sal_uLong nSumHeight = 0;
621 sal_uLong nBold = 0;
622 sal_uInt16 nMaxBaseLineOfst = 0;
623 sal_uInt16 nNumberOfPortions = 0;
624
625 while( nTmpIdx <= nUnderEnd && pPor )
626 {
627 if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
628 pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
629 pPor->IsHolePortion() ||
630 ( pPor->IsMultiPortion() && ! ((SwMultiPortion*)pPor)->IsBidi() ) )
631 break;
632
633 aIter.Seek( nTmpIdx );
634
635 if ( aIter.GetFnt()->GetEscapement() < 0 || pFnt->IsWordLineMode() ||
636 SVX_CASEMAP_KAPITAELCHEN == pFnt->GetCaseMap() )
637 break;
638
639 if ( !aIter.GetFnt()->GetEscapement() )
640 {
641 nSumWidth += pPor->Width();
642 const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
643
644 // If we do not have a common baseline we take the baseline
645 // and the font of the lowest portion.
646 if ( nAdjustBaseLine )
647 {
648 sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *pCurr, pPor );
649 if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
650 {
651 nMaxBaseLineOfst = nTmpBaseLineOfst;
652 nSumHeight = nFontHeight;
653 }
654 }
655 // in horizontal layout we build a weighted sum of the heights
656 else
657 nSumHeight += pPor->Width() * nFontHeight;
658
659 if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
660 nBold += pPor->Width();
661 }
662
663 ++nNumberOfPortions;
664
665 nTmpIdx = nTmpIdx + pPor->GetLen();
666 pPor = pPor->GetPortion();
667 }
668
669 // resulting height
670 if ( nNumberOfPortions > 1 && nSumWidth )
671 {
672 const sal_uLong nNewFontHeight = nAdjustBaseLine ?
673 nSumHeight :
674 nSumHeight / nSumWidth;
675
676 pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
677
678 // font height
679 const sal_uInt8 nActual = pUnderlineFnt->GetActual();
680 pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
681 nNewFontHeight ), nActual );
682
683 // font weight
684 if ( 2 * nBold > nSumWidth )
685 pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
686 else
687 pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
688
689 // common base line
690 aCommonBaseLine.Y() = nAdjustBaseLine + nMaxBaseLineOfst;
691 }
692 }
693
694 // an escaped redlined portion should also have a special underlining
695 if( ! pUnderlineFnt && pFnt->GetEscapement() > 0 && GetRedln() &&
696 GetRedln()->ChkSpecialUnderline() )
697 pUnderlineFnt = new SwFont( *pFnt );
698
699 delete GetInfo().GetUnderFnt();
700
701 if ( pUnderlineFnt )
702 {
703 pUnderlineFnt->SetProportion( 100 );
704 pUnderlineFnt->SetEscapement( 0 );
705 pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
706 pUnderlineFnt->SetOverline( UNDERLINE_NONE );
707 const Color aFillColor( COL_TRANSPARENT );
708 pUnderlineFnt->SetFillColor( aFillColor );
709
710 GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt,
711 aCommonBaseLine ) );
712 }
713 else
714 // I'm sorry, we do not have a special underlining font for you.
715 GetInfo().SetUnderFnt( 0 );
716 }
717