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/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 <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 43078 : sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
69 : {
70 44623 : return UNDERLINE_NONE == rFnt.GetUnderline() ||
71 4635 : rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
72 4252 : rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
73 2324 : rPor.IsHolePortion() ||
74 2324 : ( rPor.IsMultiPortion() && ! ((SwMultiPortion&)rPor).IsBidi() ) ||
75 45602 : rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
76 43520 : SVX_CASEMAP_KAPITAELCHEN == rFnt.GetCaseMap();
77 : }
78 :
79 : /*************************************************************************
80 : * SwTxtPainter::CtorInitTxtPainter()
81 : *************************************************************************/
82 14294 : void SwTxtPainter::CtorInitTxtPainter( SwTxtFrm *pNewFrm, SwTxtPaintInfo *pNewInf )
83 : {
84 14294 : CtorInitTxtCursor( pNewFrm, pNewInf );
85 14294 : pInf = pNewInf;
86 14294 : SwFont *pMyFnt = GetFnt();
87 14294 : 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 14294 : bPaintDrop = sal_False;
97 14294 : }
98 :
99 :
100 : /*************************************************************************
101 : * SwTxtPainter::CalcPaintOfst()
102 : *************************************************************************/
103 12829 : SwLinePortion *SwTxtPainter::CalcPaintOfst( const SwRect &rPaint )
104 : {
105 12829 : SwLinePortion *pPor = pCurr->GetFirstPortion();
106 12829 : GetInfo().SetPaintOfst( 0 );
107 12829 : 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 12829 : if( nPaintOfst && pCurr->Width() )
114 : {
115 12047 : SwLinePortion *pLast = 0;
116 : // 7529 und 4757: nicht <= nPaintOfst
117 24105 : while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
118 : < nPaintOfst )
119 : {
120 11 : 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 11 : pPor->Move( GetInfo() );
131 11 : pLast = pPor;
132 11 : pPor = pPor->GetPortion();
133 : }
134 :
135 : // 7529: bei PostIts auch pLast returnen.
136 12047 : if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
137 : {
138 0 : pPor = pLast;
139 0 : GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
140 : }
141 : }
142 12829 : 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 12829 : 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 12829 : GetAdjusted();
166 12829 : GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
167 12829 : GetInfo().ResetSpaceIdx();
168 12829 : GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
169 12829 : GetInfo().ResetKanaIdx();
170 : // Die Groesse des Frames
171 12829 : GetInfo().SetIdx( GetStart() );
172 12829 : GetInfo().SetPos( GetTopLeft() );
173 :
174 12829 : const bool bDrawInWindow = GetInfo().OnWin();
175 :
176 : // 6882: Leerzeilen duerfen nicht wegoptimiert werden bei Paragraphzeichen.
177 12829 : const sal_Bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetTxt().isEmpty();
178 :
179 12829 : SwLinePortion *pPor = bEndPor ? pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
180 :
181 : // Optimierung!
182 12829 : const SwTwips nMaxRight = std::min( rPaint.Right(), Right() );
183 12829 : const SwTwips nTmpLeft = GetInfo().X();
184 12829 : if( !bEndPor && nTmpLeft >= nMaxRight )
185 208 : return;
186 :
187 : // DropCaps!
188 : // 7538: natuerlich auch auf dem Drucker
189 12727 : if( !bPaintDrop )
190 : {
191 : // 8084: Optimierung, weniger Painten.
192 : // AMA: Durch 8084 wurde 7538 wiederbelebt!
193 : // bDrawInWindow entfernt, damit DropCaps auch gedruckt werden
194 12727 : bPaintDrop = pPor == pCurr->GetFirstPortion()
195 12727 : && GetDropLines() >= GetLineNr();
196 : }
197 :
198 : KSHORT nTmpHeight, nTmpAscent;
199 12727 : CalcAscentAndHeight( nTmpAscent, nTmpHeight );
200 :
201 : // bClip entscheidet darueber, ob geclippt werden muss.
202 : // Das Ganze muss vor der Retusche stehen
203 :
204 12727 : bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg();
205 12727 : 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 27140 : if( GetInfo().GetPos().X() < rPaint.Left() ||
212 15457 : GetInfo().GetPos().Y() < rPaint.Top() ||
213 6265 : GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
214 : {
215 3532 : bClip = false;
216 3532 : 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 12727 : OutputDevice* pOut = GetInfo().GetOut();
229 12727 : Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
230 12727 : if ( aPnt1.X() < rPaint.Left() )
231 727 : aPnt1.X() = rPaint.Left();
232 12727 : if ( aPnt1.Y() < rPaint.Top() )
233 2788 : aPnt1.Y() = rPaint.Top();
234 12727 : Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
235 25454 : GetInfo().GetPos().Y() + nTmpHeight );
236 12727 : if ( aPnt2.X() > rPaint.Right() )
237 0 : aPnt2.X() = rPaint.Right();
238 12727 : if ( aPnt2.Y() > rPaint.Bottom() )
239 6361 : aPnt2.Y() = rPaint.Bottom();
240 :
241 12727 : const SwRect aLineRect( aPnt1, aPnt2 );
242 :
243 12727 : if( pCurr->IsClipping() )
244 : {
245 3 : rClip.ChgClip( aLineRect, pFrm );
246 3 : bClip = false;
247 : }
248 :
249 12727 : if( !pPor && !bEndPor )
250 4 : 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 12723 : GETGRID( GetTxtFrm()->FindPageFrm() )
256 : const bool bAdjustBaseLine =
257 12723 : GetLineInfo().HasSpecialAlign( GetTxtFrm()->IsVertical() ) ||
258 12723 : ( 0 != pGrid );
259 12723 : const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
260 12723 : if ( ! bAdjustBaseLine )
261 12723 : GetInfo().Y( nLineBaseLine );
262 :
263 : // 7529: PostIts prepainten
264 12723 : if( GetInfo().OnWin() && pPor && !pPor->Width() )
265 : {
266 743 : SeekAndChg( GetInfo() );
267 :
268 743 : 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 743 : pPor->PrePaint( GetInfo(), pPor );
282 : }
283 :
284 : // 7923: EndPortions geben auch Zeichen aus, deswegen den Fnt wechseln!
285 12723 : if( bEndPor )
286 0 : SeekStartAndChg( GetInfo() );
287 :
288 12723 : sal_Bool bRest = pCurr->IsRest();
289 12723 : sal_Bool bFirst = sal_True;
290 :
291 12723 : SwArrowPortion *pArrow = NULL;
292 : // Reference portion for the paragraph end portion
293 12723 : SwLinePortion* pEndTempl = pCurr->GetFirstPortion();
294 :
295 42185 : while( pPor )
296 : {
297 16739 : sal_Bool bSeeked = sal_True;
298 16739 : GetInfo().SetLen( pPor->GetLen() );
299 :
300 16739 : const SwTwips nOldY = GetInfo().Y();
301 :
302 16739 : 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 16739 : if( ( bRest && pPor->InFldGrp() && !pPor->GetLen() ) )
319 8 : SeekAndChgBefore( GetInfo() );
320 16731 : 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 16731 : else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
328 11584 : SeekAndChg( GetInfo() );
329 5147 : 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 5147 : 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 24400 : if( bClip &&
347 7661 : GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
348 : {
349 779 : bClip = false;
350 779 : rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
351 : }
352 :
353 : // Portions, die "unter" dem Text liegen wie PostIts
354 16739 : SwLinePortion *pNext = pPor->GetPortion();
355 16739 : 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 1001 : if ( !bSeeked )
361 485 : SeekAndChg( GetInfo() );
362 1001 : pNext->PrePaint( GetInfo(), pPor );
363 : }
364 :
365 : // We calculate a separate font for underlining.
366 16739 : CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
367 16739 : SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
368 16739 : if ( pUnderLineFnt )
369 : {
370 41 : const Point aTmpPoint( GetInfo().X(),
371 : bAdjustBaseLine ?
372 0 : pUnderLineFnt->GetPos().Y() :
373 82 : nLineBaseLine );
374 41 : pUnderLineFnt->SetPos( aTmpPoint );
375 : }
376 :
377 :
378 : // in extended input mode we do not want a common underline font.
379 16739 : SwUnderlineFont* pOldUnderLineFnt = 0;
380 16739 : if ( GetRedln() && GetRedln()->ExtOn() )
381 : {
382 0 : pOldUnderLineFnt = GetInfo().GetUnderFnt();
383 0 : GetInfo().SetUnderFnt( 0 );
384 : }
385 :
386 : {
387 : // #i16816# tagged pdf support
388 16739 : Por_Info aPorInfo( *pPor, *this );
389 16739 : SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, &aPorInfo, *pOut );
390 :
391 16739 : if( pPor->IsMultiPortion() )
392 183 : PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor );
393 : else
394 16556 : pPor->Paint( GetInfo() );
395 : }
396 :
397 : // reset underline font
398 16739 : if ( pOldUnderLineFnt )
399 0 : GetInfo().SetUnderFnt( pOldUnderLineFnt );
400 :
401 : // reset (for special vertical alignment)
402 16739 : GetInfo().Y( nOldY );
403 :
404 16739 : if( GetFnt()->IsURL() && pPor->InTxtGrp() )
405 0 : GetInfo().NotifyURL( *pPor );
406 :
407 16739 : bFirst &= !pPor->GetLen();
408 16739 : if( pNext || !pPor->IsMarginPortion() )
409 16225 : pPor->Move( GetInfo() );
410 16739 : if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
411 0 : pArrow = (SwArrowPortion*)pPor;
412 :
413 160 : 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 33478 : 0;
420 : }
421 :
422 : // delete underline font
423 12723 : delete GetInfo().GetUnderFnt();
424 12723 : GetInfo().SetUnderFnt( 0 );
425 :
426 : // paint remaining stuff
427 12723 : 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 12618 : const SwTwips nOldY = GetInfo().Y();
433 :
434 31242 : if( !GetNextLine() &&
435 18018 : GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() &&
436 18624 : GetInfo().GetOpt().IsParagraph() && !GetTxtFrm()->GetFollow() &&
437 0 : GetInfo().GetIdx() >= GetInfo().GetTxt().getLength() )
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 12618 : if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() )
450 : {
451 : const sal_Bool bNextUndersized =
452 15353 : ( GetTxtFrm()->GetNext() &&
453 2739 : 0 == GetTxtFrm()->GetNext()->Prt().Height() &&
454 12626 : GetTxtFrm()->GetNext()->IsTxtFrm() &&
455 12622 : ((SwTxtFrm*)GetTxtFrm()->GetNext())->IsUndersized() ) ;
456 :
457 12618 : if( bUnderSz || bNextUndersized )
458 : {
459 270 : if ( bAdjustBaseLine )
460 0 : GetInfo().Y( GetInfo().GetPos().Y() + pCurr->GetAscent() );
461 :
462 270 : if( pArrow )
463 0 : GetInfo().DrawRedArrow( *pArrow );
464 :
465 : // GetInfo().Y() must be current baseline.
466 270 : SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTxtFrm()->Frm().Bottom();
467 283 : if( ( nDiff > 0 &&
468 21 : ( GetEnd() < GetInfo().GetTxt().getLength() ||
469 291 : ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
470 8 : (nDiff >= 0 && bNextUndersized) )
471 :
472 : {
473 9 : SwArrowPortion aArrow( GetInfo() );
474 9 : GetInfo().DrawRedArrow( aArrow );
475 : }
476 :
477 270 : GetInfo().Y( nOldY );
478 : }
479 : }
480 : }
481 :
482 12723 : if( pCurr->IsClipping() )
483 3 : rClip.ChgClip( rPaint, pFrm );
484 : }
485 :
486 17273 : void SwTxtPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
487 : long nAdjustBaseLine )
488 : {
489 : // Check if common underline should not be continued.
490 17273 : if ( IsUnderlineBreak( *pPor, *pFnt ) )
491 : {
492 : // delete underline font
493 17067 : delete GetInfo().GetUnderFnt();
494 17067 : GetInfo().SetUnderFnt( 0 );
495 17067 : return;
496 : }
497 :
498 : // If current underline matches the common underline font, we continue
499 : // to use the common underline font.
500 : //Bug 120769:Color of underline display wrongly
501 206 : Color aAutoCo(COL_AUTO);
502 455 : if ( GetInfo().GetUnderFnt() &&
503 86 : GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
504 292 : GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != aAutoCo )
505 0 : return;
506 : //Bug 120769(End)
507 : // calculate the new common underline font
508 206 : SwFont* pUnderlineFnt = 0;
509 206 : Point aCommonBaseLine;
510 :
511 206 : Range aRange( 0, GetInfo().GetTxt().getLength() );
512 206 : MultiSelection aUnderMulti( aRange );
513 :
514 : OSL_ENSURE( GetFnt() && UNDERLINE_NONE != GetFnt()->GetUnderline(),
515 : "CheckSpecialUnderline without underlined font" );
516 206 : const SwFont* pParaFnt = GetAttrHandler().GetFont();
517 206 : if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
518 74 : aUnderMulti.SelectAll();
519 :
520 : SwTxtAttr* pTxtAttr;
521 206 : if( HasHints() )
522 : {
523 137 : sal_Bool bUnder = sal_False;
524 137 : MSHORT nTmp = 0;
525 :
526 951 : while( nTmp < pHints->GetStartCount() )
527 : {
528 677 : pTxtAttr = pHints->GetStart( nTmp++ );
529 677 : sal_Bool bUnderSelect = sal_False;
530 :
531 : const SvxUnderlineItem* pItem =
532 677 : static_cast<const SvxUnderlineItem*>(CharFmt::GetItem( *pTxtAttr, RES_CHRATR_UNDERLINE ));
533 :
534 677 : if ( pItem )
535 : {
536 397 : bUnder = sal_True;
537 397 : bUnderSelect = pFnt->GetUnderline() == pItem->GetLineStyle();
538 : }
539 :
540 677 : if( bUnder )
541 : {
542 397 : xub_StrLen nSt = *pTxtAttr->GetStart();
543 397 : xub_StrLen nEnd = *pTxtAttr->GetEnd();
544 397 : if( nEnd > nSt )
545 : {
546 392 : Range aTmp( nSt, nEnd - 1 );
547 392 : if( bUnder )
548 392 : aUnderMulti.Select( aTmp, bUnderSelect );
549 : }
550 397 : bUnder = sal_False;
551 : }
552 : }
553 : }
554 :
555 : MSHORT i;
556 206 : xub_StrLen nIndx = GetInfo().GetIdx();
557 206 : long nUnderStart = 0;
558 206 : long nUnderEnd = 0;
559 206 : MSHORT nCnt = (MSHORT)aUnderMulti.GetRangeCount();
560 :
561 : // find the underline range the current portion is contained in
562 445 : for( i = 0; i < nCnt; ++i )
563 : {
564 265 : const Range& rRange = aUnderMulti.GetRange( i );
565 265 : if( nUnderEnd == rRange.Min() )
566 130 : nUnderEnd = rRange.Max();
567 135 : else if( nIndx >= rRange.Min() )
568 : {
569 109 : nUnderStart = rRange.Min();
570 109 : nUnderEnd = rRange.Max();
571 : }
572 : else
573 26 : break;
574 : }
575 :
576 : // restrict start and end to current line
577 206 : if ( GetStart() > nUnderStart )
578 1 : nUnderStart = GetStart();
579 :
580 206 : if ( GetEnd() && GetEnd() <= nUnderEnd )
581 33 : nUnderEnd = GetEnd() - 1;
582 :
583 :
584 : // check, if underlining is not isolated
585 206 : if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 )
586 : {
587 : //
588 : // here starts the algorithm for calculating the underline font
589 : //
590 121 : SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
591 121 : SwAttrIter aIter( *(SwTxtNode*)GetInfo().GetTxtFrm()->GetTxtNode(),
592 121 : rScriptInfo );
593 :
594 121 : xub_StrLen nTmpIdx = nIndx;
595 121 : sal_uLong nSumWidth = 0;
596 121 : sal_uLong nSumHeight = 0;
597 121 : sal_uLong nBold = 0;
598 121 : sal_uInt16 nMaxBaseLineOfst = 0;
599 121 : sal_uInt16 nNumberOfPortions = 0;
600 :
601 444 : while( nTmpIdx <= nUnderEnd && pPor )
602 : {
603 1028 : if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
604 725 : pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
605 734 : pPor->IsHolePortion() ||
606 220 : ( pPor->IsMultiPortion() && ! ((SwMultiPortion*)pPor)->IsBidi() ) )
607 55 : break;
608 :
609 202 : aIter.Seek( nTmpIdx );
610 :
611 404 : if ( aIter.GetFnt()->GetEscapement() < 0 || pFnt->IsWordLineMode() ||
612 202 : SVX_CASEMAP_KAPITAELCHEN == pFnt->GetCaseMap() )
613 0 : break;
614 :
615 202 : if ( !aIter.GetFnt()->GetEscapement() )
616 : {
617 156 : nSumWidth += pPor->Width();
618 156 : const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
619 :
620 : // If we do not have a common baseline we take the baseline
621 : // and the font of the lowest portion.
622 156 : if ( nAdjustBaseLine )
623 : {
624 0 : sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *pCurr, pPor );
625 0 : if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
626 : {
627 0 : nMaxBaseLineOfst = nTmpBaseLineOfst;
628 0 : nSumHeight = nFontHeight;
629 : }
630 : }
631 : // in horizontal layout we build a weighted sum of the heights
632 : else
633 156 : nSumHeight += pPor->Width() * nFontHeight;
634 :
635 156 : if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
636 6 : nBold += pPor->Width();
637 : }
638 :
639 202 : ++nNumberOfPortions;
640 :
641 202 : nTmpIdx = nTmpIdx + pPor->GetLen();
642 202 : pPor = pPor->GetPortion();
643 : }
644 :
645 : // resulting height
646 121 : if ( nNumberOfPortions > 1 && nSumWidth )
647 : {
648 : const sal_uLong nNewFontHeight = nAdjustBaseLine ?
649 : nSumHeight :
650 43 : nSumHeight / nSumWidth;
651 :
652 43 : pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
653 :
654 : // font height
655 43 : const sal_uInt8 nActual = pUnderlineFnt->GetActual();
656 43 : pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
657 86 : nNewFontHeight ), nActual );
658 :
659 : // font weight
660 43 : if ( 2 * nBold > nSumWidth )
661 3 : pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
662 : else
663 40 : pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
664 :
665 : // common base line
666 43 : aCommonBaseLine.Y() = nAdjustBaseLine + nMaxBaseLineOfst;
667 121 : }
668 : }
669 :
670 : // an escaped redlined portion should also have a special underlining
671 206 : if( ! pUnderlineFnt && pFnt->GetEscapement() > 0 && GetRedln() &&
672 0 : GetRedln()->ChkSpecialUnderline() )
673 0 : pUnderlineFnt = new SwFont( *pFnt );
674 :
675 206 : delete GetInfo().GetUnderFnt();
676 :
677 206 : if ( pUnderlineFnt )
678 : {
679 43 : pUnderlineFnt->SetProportion( 100 );
680 43 : pUnderlineFnt->SetEscapement( 0 );
681 43 : pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
682 43 : pUnderlineFnt->SetOverline( UNDERLINE_NONE );
683 43 : const Color aFillColor( COL_TRANSPARENT );
684 43 : pUnderlineFnt->SetFillColor( aFillColor );
685 :
686 43 : GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt,
687 86 : aCommonBaseLine ) );
688 : }
689 : else
690 : // I'm sorry, we do not have a special underlining font for you.
691 163 : GetInfo().SetUnderFnt( 0 );
692 99 : }
693 :
694 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|