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