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 SwTxtPainter::CheckSpecialUnderline
61 267061 : bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
62 : {
63 282755 : return UNDERLINE_NONE == rFnt.GetUnderline() ||
64 46782 : rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
65 45458 : rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
66 29400 : rPor.IsHolePortion() ||
67 29400 : ( rPor.IsMultiPortion() && ! ((SwMultiPortion&)rPor).IsBidi() ) ||
68 309397 : rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
69 280465 : SVX_CASEMAP_KAPITAELCHEN == rFnt.GetCaseMap();
70 : }
71 :
72 119602 : void SwTxtPainter::CtorInitTxtPainter( SwTxtFrm *pNewFrm, SwTxtPaintInfo *pNewInf )
73 : {
74 119602 : CtorInitTxtCursor( pNewFrm, pNewInf );
75 119602 : pInf = pNewInf;
76 119602 : SwFont *pMyFnt = GetFnt();
77 119602 : GetInfo().SetFont( pMyFnt );
78 : #if OSL_DEBUG_LEVEL > 1
79 : if( ALIGN_BASELINE != pMyFnt->GetAlign() )
80 : {
81 : OSL_ENSURE( ALIGN_BASELINE == pMyFnt->GetAlign(),
82 : "+SwTxtPainter::CTOR: font alignment revolution" );
83 : pMyFnt->SetAlign( ALIGN_BASELINE );
84 : }
85 : #endif
86 119602 : bPaintDrop = false;
87 119602 : }
88 :
89 44922 : SwLinePortion *SwTxtPainter::CalcPaintOfst( const SwRect &rPaint )
90 : {
91 44922 : SwLinePortion *pPor = pCurr->GetFirstPortion();
92 44922 : GetInfo().SetPaintOfst( 0 );
93 44922 : 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 44922 : if( nPaintOfst && pCurr->Width() )
100 : {
101 42483 : SwLinePortion *pLast = 0;
102 : // 7529 und 4757: nicht <= nPaintOfst
103 86860 : while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
104 : < nPaintOfst )
105 : {
106 1894 : 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 1894 : pPor->Move( GetInfo() );
117 1894 : pLast = pPor;
118 1894 : pPor = pPor->GetPortion();
119 : }
120 :
121 : // 7529: bei PostIts auch pLast returnen.
122 42483 : if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
123 : {
124 0 : pPor = pLast;
125 0 : GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
126 : }
127 : }
128 44922 : 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 44922 : void SwTxtPainter::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 44922 : GetAdjusted();
148 44922 : GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
149 44922 : GetInfo().ResetSpaceIdx();
150 44922 : GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
151 44922 : GetInfo().ResetKanaIdx();
152 : // The size of the frame
153 44922 : GetInfo().SetIdx( GetStart() );
154 44922 : GetInfo().SetPos( GetTopLeft() );
155 :
156 44922 : const bool bDrawInWindow = GetInfo().OnWin();
157 :
158 : // 6882: Leerzeilen duerfen nicht wegoptimiert werden bei Paragraphzeichen.
159 44922 : const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetTxt().isEmpty();
160 :
161 44922 : SwLinePortion *pPor = bEndPor ? pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
162 :
163 : // Optimization!
164 44922 : const SwTwips nMaxRight = std::min( rPaint.Right(), Right() );
165 44922 : const SwTwips nTmpLeft = GetInfo().X();
166 44922 : if( !bEndPor && nTmpLeft >= nMaxRight )
167 2204 : return;
168 :
169 : // DropCaps!
170 : // 7538: of course for the printer, too
171 44698 : 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 44698 : bPaintDrop = pPor == pCurr->GetFirstPortion()
177 44698 : && GetDropLines() >= GetLineNr();
178 : }
179 :
180 : sal_uInt16 nTmpHeight, nTmpAscent;
181 44698 : CalcAscentAndHeight( nTmpAscent, nTmpHeight );
182 :
183 : // bClip decides if there's a need to clip
184 : // Das Ganze muss vor der Retusche stehen
185 :
186 44698 : bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg();
187 44698 : 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 54622 : if( GetInfo().GetPos().X() < rPaint.Left() ||
194 32343 : GetInfo().GetPos().Y() < rPaint.Top() ||
195 12445 : GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
196 : {
197 8534 : bClip = false;
198 8534 : 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 44698 : OutputDevice* pOut = GetInfo().GetOut();
211 44698 : Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
212 44698 : if ( aPnt1.X() < rPaint.Left() )
213 21591 : aPnt1.X() = rPaint.Left();
214 44698 : if ( aPnt1.Y() < rPaint.Top() )
215 4589 : aPnt1.Y() = rPaint.Top();
216 44698 : Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
217 89396 : GetInfo().GetPos().Y() + nTmpHeight );
218 44698 : if ( aPnt2.X() > rPaint.Right() )
219 0 : aPnt2.X() = rPaint.Right();
220 44698 : if ( aPnt2.Y() > rPaint.Bottom() )
221 19576 : aPnt2.Y() = rPaint.Bottom();
222 :
223 44698 : const SwRect aLineRect( aPnt1, aPnt2 );
224 :
225 44698 : if( pCurr->IsClipping() )
226 : {
227 216 : rClip.ChgClip( aLineRect, pFrm );
228 216 : bClip = false;
229 : }
230 :
231 44698 : if( !pPor && !bEndPor )
232 1756 : return;
233 :
234 : // Baseline-Ausgabe auch bei nicht-TxtPortions (vgl. TabPor mit Fill)
235 : // if no special vertical alignment is used,
236 : // we calculate Y value for the whole line
237 42942 : SwTextGridItem const*const pGrid(GetGridItem(GetTxtFrm()->FindPageFrm()));
238 : const bool bAdjustBaseLine =
239 42942 : GetLineInfo().HasSpecialAlign( GetTxtFrm()->IsVertical() ) ||
240 42942 : ( 0 != pGrid );
241 42942 : const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
242 42942 : if ( ! bAdjustBaseLine )
243 42876 : GetInfo().Y( nLineBaseLine );
244 :
245 : // 7529: Pre-paint post-its
246 42942 : if( GetInfo().OnWin() && pPor && !pPor->Width() )
247 : {
248 2319 : SeekAndChg( GetInfo() );
249 :
250 2319 : 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 2319 : pPor->PrePaint( GetInfo(), pPor );
264 : }
265 :
266 : // 7923: EndPortions output chars, too, that's why we change the font
267 42942 : if( bEndPor )
268 0 : SeekStartAndChg( GetInfo() );
269 :
270 42942 : const bool bRest = pCurr->IsRest();
271 42942 : bool bFirst = true;
272 :
273 42942 : SwArrowPortion *pArrow = NULL;
274 : // Reference portion for the paragraph end portion
275 42942 : SwLinePortion* pEndTempl = pCurr->GetFirstPortion();
276 :
277 144984 : while( pPor )
278 : {
279 59100 : bool bSeeked = true;
280 59100 : GetInfo().SetLen( pPor->GetLen() );
281 :
282 59100 : const SwTwips nOldY = GetInfo().Y();
283 :
284 59100 : if ( bAdjustBaseLine )
285 : {
286 306 : 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 306 : if ( pPor->Width() && pPor->InTxtGrp() )
293 216 : pEndTempl = pPor;
294 : }
295 :
296 : // Ein Sonderfall sind GluePortions, die Blanks ausgeben.
297 :
298 : // 6168: Der Rest einer FldPortion zog sich die Attribute der naechsten
299 : // Portion an, dies wird durch SeekAndChgBefore vermieden:
300 59100 : if( ( bRest && pPor->InFldGrp() && !pPor->GetLen() ) )
301 144 : SeekAndChgBefore( GetInfo() );
302 58956 : 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 58956 : else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
310 45858 : SeekAndChg( GetInfo() );
311 13098 : 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 13098 : 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 77695 : if( bClip &&
329 18595 : GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
330 : {
331 4001 : bClip = false;
332 4001 : rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
333 : }
334 :
335 : // Portions, which lay "below" the text like post-its
336 59100 : SwLinePortion *pNext = pPor->GetPortion();
337 59100 : 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 5202 : if ( !bSeeked )
343 1984 : SeekAndChg( GetInfo() );
344 5202 : pNext->PrePaint( GetInfo(), pPor );
345 : }
346 :
347 : // We calculate a separate font for underlining.
348 59100 : CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
349 59100 : SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
350 59100 : if ( pUnderLineFnt )
351 : {
352 124 : const Point aTmpPoint( GetInfo().X(),
353 : bAdjustBaseLine ?
354 24 : pUnderLineFnt->GetPos().Y() :
355 272 : nLineBaseLine );
356 124 : pUnderLineFnt->SetPos( aTmpPoint );
357 : }
358 :
359 : // in extended input mode we do not want a common underline font.
360 59100 : SwUnderlineFont* pOldUnderLineFnt = 0;
361 59100 : if ( GetRedln() && GetRedln()->ExtOn() )
362 : {
363 0 : pOldUnderLineFnt = GetInfo().GetUnderFnt();
364 0 : GetInfo().SetUnderFnt( 0 );
365 : }
366 :
367 : {
368 : // #i16816# tagged pdf support
369 59100 : Por_Info aPorInfo( *pPor, *this );
370 59100 : SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, &aPorInfo, *pOut );
371 :
372 59100 : if( pPor->IsMultiPortion() )
373 380 : PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor );
374 : else
375 58720 : pPor->Paint( GetInfo() );
376 : }
377 :
378 : // reset underline font
379 59100 : if ( pOldUnderLineFnt )
380 0 : GetInfo().SetUnderFnt( pOldUnderLineFnt );
381 :
382 : // reset (for special vertical alignment)
383 59100 : GetInfo().Y( nOldY );
384 :
385 59100 : if( GetFnt()->IsURL() && pPor->InTxtGrp() )
386 0 : GetInfo().NotifyURL( *pPor );
387 :
388 59100 : bFirst &= !pPor->GetLen();
389 59100 : if( pNext || !pPor->IsMarginPortion() )
390 56284 : pPor->Move( GetInfo() );
391 59100 : if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
392 0 : pArrow = (SwArrowPortion*)pPor;
393 :
394 562 : pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
395 : // #i16816# tagged pdf support
396 0 : ( GetInfo().GetVsh() &&
397 0 : GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
398 0 : pNext && pNext->IsHolePortion() ) ?
399 : pNext :
400 118200 : 0;
401 : }
402 :
403 : // delete underline font
404 42942 : delete GetInfo().GetUnderFnt();
405 42942 : GetInfo().SetUnderFnt( 0 );
406 :
407 : // paint remaining stuff
408 42942 : 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 42538 : const SwTwips nOldY = GetInfo().Y();
414 :
415 103018 : if( !GetNextLine() &&
416 53826 : GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
417 60480 : GetInfo().GetOpt().IsParagraph() && !GetTxtFrm()->GetFollow() &&
418 0 : GetInfo().GetIdx() >= GetInfo().GetTxt().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 42538 : if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
431 : {
432 : const bool bNextUndersized =
433 57664 : ( GetTxtFrm()->GetNext() &&
434 15138 : 0 == GetTxtFrm()->GetNext()->Prt().Height() &&
435 42562 : GetTxtFrm()->GetNext()->IsTxtFrm() &&
436 42550 : ((SwTxtFrm*)GetTxtFrm()->GetNext())->IsUndersized() ) ;
437 :
438 42538 : if( bUnderSz || bNextUndersized )
439 : {
440 566 : if ( bAdjustBaseLine )
441 0 : GetInfo().Y( GetInfo().GetPos().Y() + pCurr->GetAscent() );
442 :
443 566 : if( pArrow )
444 0 : GetInfo().DrawRedArrow( *pArrow );
445 :
446 : // GetInfo().Y() must be current baseline
447 566 : SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTxtFrm()->Frm().Bottom();
448 690 : if( ( nDiff > 0 &&
449 236 : ( GetEnd() < GetInfo().GetTxt().getLength() ||
450 704 : ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
451 112 : (nDiff >= 0 && bNextUndersized) )
452 :
453 : {
454 24 : SwArrowPortion aArrow( GetInfo() );
455 24 : GetInfo().DrawRedArrow( aArrow );
456 : }
457 :
458 566 : GetInfo().Y( nOldY );
459 : }
460 : }
461 : }
462 :
463 42942 : if( pCurr->IsClipping() )
464 216 : rClip.ChgClip( rPaint, pFrm );
465 : }
466 :
467 60138 : void SwTxtPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
468 : long nAdjustBaseLine )
469 : {
470 : // Check if common underline should not be continued
471 60138 : if ( IsUnderlineBreak( *pPor, *pFnt ) )
472 : {
473 : // delete underline font
474 59006 : delete GetInfo().GetUnderFnt();
475 59006 : GetInfo().SetUnderFnt( 0 );
476 59006 : 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 4528 : if ( GetInfo().GetUnderFnt() &&
483 256 : GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
484 3780 : 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 1132 : MultiSelection aUnderMulti( Range( 0, GetInfo().GetTxt().getLength() ) );
491 1132 : const SwFont* pParaFnt = GetAttrHandler().GetFont();
492 1132 : if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
493 154 : aUnderMulti.SelectAll();
494 :
495 1132 : if( HasHints() )
496 : {
497 4502 : for ( size_t nTmp = 0; nTmp < pHints->GetStartCount(); ++nTmp )
498 : {
499 3602 : SwTxtAttr* const pTxtAttr = pHints->GetStart( nTmp );
500 :
501 : const SvxUnderlineItem* pItem =
502 3602 : static_cast<const SvxUnderlineItem*>(CharFmt::GetItem( *pTxtAttr, RES_CHRATR_UNDERLINE ));
503 :
504 3602 : if ( pItem )
505 : {
506 1630 : const sal_Int32 nSt = pTxtAttr->GetStart();
507 1630 : const sal_Int32 nEnd = *pTxtAttr->GetEnd();
508 1630 : if( nEnd > nSt )
509 : {
510 1566 : const bool bUnderSelect = pFnt->GetUnderline() == pItem->GetLineStyle();
511 1566 : aUnderMulti.Select( Range( nSt, nEnd - 1 ), bUnderSelect );
512 : }
513 : }
514 : }
515 : }
516 :
517 1132 : const sal_Int32 nIndx = GetInfo().GetIdx();
518 1132 : long nUnderStart = 0;
519 1132 : long nUnderEnd = 0;
520 1132 : const size_t nCnt = aUnderMulti.GetRangeCount();
521 :
522 : // find the underline range the current portion is contained in
523 2038 : for( size_t i = 0; i < nCnt; ++i )
524 : {
525 974 : const Range& rRange = aUnderMulti.GetRange( i );
526 974 : if( nUnderEnd == rRange.Min() )
527 518 : nUnderEnd = rRange.Max();
528 456 : else if( nIndx >= rRange.Min() )
529 : {
530 388 : nUnderStart = rRange.Min();
531 388 : nUnderEnd = rRange.Max();
532 : }
533 : else
534 68 : break;
535 : }
536 :
537 : // restrict start and end to current line
538 1132 : if ( GetStart() > nUnderStart )
539 68 : nUnderStart = GetStart();
540 :
541 1132 : if ( GetEnd() && GetEnd() <= nUnderEnd )
542 114 : nUnderEnd = GetEnd() - 1;
543 :
544 : // calculate the new common underline font
545 1132 : SwFont* pUnderlineFnt = 0;
546 1132 : Point aCommonBaseLine;
547 :
548 : // check, if underlining is not isolated
549 1132 : if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 )
550 : {
551 : // here starts the algorithm for calculating the underline font
552 270 : SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
553 270 : SwAttrIter aIter( *(SwTxtNode*)GetInfo().GetTxtFrm()->GetTxtNode(),
554 270 : rScriptInfo );
555 :
556 270 : sal_Int32 nTmpIdx = nIndx;
557 270 : sal_uLong nSumWidth = 0;
558 270 : sal_uLong nSumHeight = 0;
559 270 : sal_uLong nBold = 0;
560 270 : sal_uInt16 nMaxBaseLineOfst = 0;
561 270 : int nNumberOfPortions = 0;
562 :
563 1088 : while( nTmpIdx <= nUnderEnd && pPor )
564 : {
565 2568 : if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
566 1850 : pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
567 1868 : pPor->IsHolePortion() ||
568 584 : ( pPor->IsMultiPortion() && ! ((SwMultiPortion*)pPor)->IsBidi() ) )
569 94 : break;
570 :
571 548 : aIter.Seek( nTmpIdx );
572 :
573 1096 : if ( aIter.GetFnt()->GetEscapement() < 0 || pFnt->IsWordLineMode() ||
574 548 : SVX_CASEMAP_KAPITAELCHEN == pFnt->GetCaseMap() )
575 0 : break;
576 :
577 548 : if ( !aIter.GetFnt()->GetEscapement() )
578 : {
579 474 : nSumWidth += pPor->Width();
580 474 : const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
581 :
582 : // If we do not have a common baseline we take the baseline
583 : // and the font of the lowest portion.
584 474 : if ( nAdjustBaseLine )
585 : {
586 84 : const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *pCurr, pPor );
587 84 : if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
588 : {
589 24 : nMaxBaseLineOfst = nTmpBaseLineOfst;
590 24 : nSumHeight = nFontHeight;
591 : }
592 : }
593 : // in horizontal layout we build a weighted sum of the heights
594 : else
595 390 : nSumHeight += pPor->Width() * nFontHeight;
596 :
597 474 : if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
598 40 : nBold += pPor->Width();
599 : }
600 :
601 548 : ++nNumberOfPortions;
602 :
603 548 : nTmpIdx += pPor->GetLen();
604 548 : pPor = pPor->GetPortion();
605 : }
606 :
607 : // resulting height
608 270 : if ( nNumberOfPortions > 1 && nSumWidth )
609 : {
610 : const sal_uLong nNewFontHeight = nAdjustBaseLine ?
611 : nSumHeight :
612 128 : nSumHeight / nSumWidth;
613 :
614 128 : pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
615 :
616 : // font height
617 128 : const sal_uInt8 nActual = pUnderlineFnt->GetActual();
618 128 : pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
619 256 : nNewFontHeight ), nActual );
620 :
621 : // font weight
622 128 : if ( 2 * nBold > nSumWidth )
623 2 : pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
624 : else
625 126 : pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
626 :
627 : // common base line
628 128 : aCommonBaseLine.Y() = nAdjustBaseLine + nMaxBaseLineOfst;
629 270 : }
630 : }
631 :
632 : // an escaped redlined portion should also have a special underlining
633 1132 : if( ! pUnderlineFnt && pFnt->GetEscapement() > 0 && GetRedln() &&
634 0 : GetRedln()->ChkSpecialUnderline() )
635 0 : pUnderlineFnt = new SwFont( *pFnt );
636 :
637 1132 : delete GetInfo().GetUnderFnt();
638 :
639 1132 : if ( pUnderlineFnt )
640 : {
641 128 : pUnderlineFnt->SetProportion( 100 );
642 128 : pUnderlineFnt->SetEscapement( 0 );
643 128 : pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
644 128 : pUnderlineFnt->SetOverline( UNDERLINE_NONE );
645 128 : const Color aFillColor( COL_TRANSPARENT );
646 128 : pUnderlineFnt->SetFillColor( aFillColor );
647 :
648 128 : GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt,
649 256 : aCommonBaseLine ) );
650 : }
651 : else
652 : // I'm sorry, we do not have a special underlining font for you.
653 1004 : GetInfo().SetUnderFnt( 0 );
654 270 : }
655 :
656 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|