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