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