1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <sal/types.h>
23 #include <vcl/gdimtf.hxx>
24 #include <vcl/metaact.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vcl/settings.hxx>
27 #include <vcl/virdev.hxx>
29 #include <tools/helpers.hxx>
32 #include <impglyphitem.hxx>
34 #include <basegfx/matrix/b2dhommatrixtools.hxx>
35 #include <basegfx/polygon/WaveLine.hxx>
37 #define UNDERLINE_LAST LINESTYLE_BOLDWAVE
38 #define STRIKEOUT_LAST STRIKEOUT_X
40 void OutputDevice::ImplInitTextLineSize()
42 mpFontInstance
->mxFontMetric
->ImplInitTextLineSize( this );
45 void OutputDevice::ImplInitAboveTextLineSize()
47 mpFontInstance
->mxFontMetric
->ImplInitAboveTextLineSize();
50 void OutputDevice::ImplDrawWavePixel( tools::Long nOriginX
, tools::Long nOriginY
,
51 tools::Long nCurX
, tools::Long nCurY
,
52 Degree10 nOrientation
,
53 SalGraphics
* pGraphics
,
54 OutputDevice
const * pOutDev
,
56 tools::Long nPixWidth
, tools::Long nPixHeight
)
60 Point
aPoint( nOriginX
, nOriginY
);
61 aPoint
.RotateAround( nCurX
, nCurY
, nOrientation
);
67 pGraphics
->DrawRect( nCurX
, nCurY
, nPixWidth
, nPixHeight
, pOutDev
);
71 pGraphics
->DrawPixel( nCurX
, nCurY
, pOutDev
);
75 void OutputDevice::ImplDrawWaveLine( tools::Long nBaseX
, tools::Long nBaseY
,
76 tools::Long nDistX
, tools::Long nDistY
,
77 tools::Long nWidth
, tools::Long nHeight
,
78 tools::Long nLineWidth
, Degree10 nOrientation
,
84 tools::Long nStartX
= nBaseX
+ nDistX
;
85 tools::Long nStartY
= nBaseY
+ nDistY
;
87 // If the height is 1 pixel, it's enough output a line
88 if ( (nLineWidth
== 1) && (nHeight
== 1) )
90 mpGraphics
->SetLineColor( rColor
);
91 mbInitLineColor
= true;
93 tools::Long nEndX
= nStartX
+nWidth
;
94 tools::Long nEndY
= nStartY
;
97 Point
aOriginPt( nBaseX
, nBaseY
);
98 aOriginPt
.RotateAround( nStartX
, nStartY
, nOrientation
);
99 aOriginPt
.RotateAround( nEndX
, nEndY
, nOrientation
);
101 mpGraphics
->DrawLine( nStartX
, nStartY
, nEndX
, nEndY
, this );
105 tools::Long nCurX
= nStartX
;
106 tools::Long nCurY
= nStartY
;
107 tools::Long nDiffX
= 2;
108 tools::Long nDiffY
= nHeight
-1;
109 tools::Long nCount
= nWidth
;
110 tools::Long nOffY
= -1;
111 tools::Long nPixWidth
;
112 tools::Long nPixHeight
;
114 // On printers that output pixel via DrawRect()
115 if ( (GetOutDevType() == OUTDEV_PRINTER
) || (nLineWidth
> 1) )
117 if ( mbLineColor
|| mbInitLineColor
)
119 mpGraphics
->SetLineColor();
120 mbInitLineColor
= true;
122 mpGraphics
->SetFillColor( rColor
);
123 mbInitFillColor
= true;
124 bDrawPixAsRect
= true;
125 nPixWidth
= nLineWidth
;
126 nPixHeight
= ((nLineWidth
*mnDPIX
)+(mnDPIY
/2))/mnDPIY
;
130 mpGraphics
->SetLineColor( rColor
);
131 mbInitLineColor
= true;
134 bDrawPixAsRect
= false;
141 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
143 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
151 tools::Long nFreq
= nCount
/ (nDiffX
+nDiffY
);
154 for( tools::Long i
= nDiffY
; i
; --i
)
156 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
158 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
162 for( tools::Long i
= nDiffX
; i
; --i
)
164 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
166 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
171 nFreq
= nCount
% (nDiffX
+nDiffY
);
174 for( tools::Long i
= nDiffY
; i
&& nFreq
; --i
, --nFreq
)
176 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
178 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
183 for( tools::Long i
= nDiffX
; i
&& nFreq
; --i
, --nFreq
)
185 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
187 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
195 void OutputDevice::ImplDrawWaveTextLine( tools::Long nBaseX
, tools::Long nBaseY
,
196 tools::Long nDistX
, tools::Long nDistY
, tools::Long nWidth
,
197 FontLineStyle eTextLine
,
201 LogicalFontInstance
* pFontInstance
= mpFontInstance
.get();
202 tools::Long nLineHeight
;
203 tools::Long nLinePos
;
207 nLineHeight
= pFontInstance
->mxFontMetric
->GetAboveWavelineUnderlineSize();
208 nLinePos
= pFontInstance
->mxFontMetric
->GetAboveWavelineUnderlineOffset();
212 nLineHeight
= pFontInstance
->mxFontMetric
->GetWavelineUnderlineSize();
213 nLinePos
= pFontInstance
->mxFontMetric
->GetWavelineUnderlineOffset();
215 if ( (eTextLine
== LINESTYLE_SMALLWAVE
) && (nLineHeight
> 3) )
218 tools::Long nLineWidth
= mnDPIX
/ 300;
222 if ( eTextLine
== LINESTYLE_BOLDWAVE
)
225 nLinePos
+= nDistY
- (nLineHeight
/ 2);
227 tools::Long nLineWidthHeight
= ((nLineWidth
* mnDPIX
) + (mnDPIY
/ 2)) / mnDPIY
;
228 if ( eTextLine
== LINESTYLE_DOUBLEWAVE
)
230 tools::Long nOrgLineHeight
= nLineHeight
;
232 if ( nLineHeight
< 2 )
234 if ( nOrgLineHeight
> 1 )
240 tools::Long nLineDY
= nOrgLineHeight
-(nLineHeight
*2);
241 if ( nLineDY
< nLineWidthHeight
)
242 nLineDY
= nLineWidthHeight
;
244 tools::Long nLineDY2
= nLineDY
/2;
248 nLinePos
-= nLineWidthHeight
-nLineDY2
;
249 ImplDrawWaveLine( nBaseX
, nBaseY
, nDistX
, nLinePos
, nWidth
, nLineHeight
,
250 nLineWidth
, mpFontInstance
->mnOrientation
, aColor
);
251 nLinePos
+= nLineWidthHeight
+nLineDY
;
252 ImplDrawWaveLine( nBaseX
, nBaseY
, nDistX
, nLinePos
, nWidth
, nLineHeight
,
253 nLineWidth
, mpFontInstance
->mnOrientation
, aColor
);
257 nLinePos
-= nLineWidthHeight
/2;
258 ImplDrawWaveLine( nBaseX
, nBaseY
, nDistX
, nLinePos
, nWidth
, nLineHeight
,
259 nLineWidth
, mpFontInstance
->mnOrientation
, aColor
);
263 void OutputDevice::ImplDrawStraightTextLine( tools::Long nBaseX
, tools::Long nBaseY
,
264 tools::Long nDistX
, tools::Long nDistY
, tools::Long nWidth
,
265 FontLineStyle eTextLine
,
269 LogicalFontInstance
* pFontInstance
= mpFontInstance
.get();
270 tools::Long nLineHeight
= 0;
271 tools::Long nLinePos
= 0;
272 tools::Long nLinePos2
= 0;
274 const tools::Long nY
= nDistY
;
276 if ( eTextLine
> UNDERLINE_LAST
)
277 eTextLine
= LINESTYLE_SINGLE
;
281 case LINESTYLE_SINGLE
:
282 case LINESTYLE_DOTTED
:
284 case LINESTYLE_LONGDASH
:
285 case LINESTYLE_DASHDOT
:
286 case LINESTYLE_DASHDOTDOT
:
289 nLineHeight
= pFontInstance
->mxFontMetric
->GetAboveUnderlineSize();
290 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetAboveUnderlineOffset();
294 nLineHeight
= pFontInstance
->mxFontMetric
->GetUnderlineSize();
295 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetUnderlineOffset();
299 case LINESTYLE_BOLDDOTTED
:
300 case LINESTYLE_BOLDDASH
:
301 case LINESTYLE_BOLDLONGDASH
:
302 case LINESTYLE_BOLDDASHDOT
:
303 case LINESTYLE_BOLDDASHDOTDOT
:
306 nLineHeight
= pFontInstance
->mxFontMetric
->GetAboveBoldUnderlineSize();
307 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetAboveBoldUnderlineOffset();
311 nLineHeight
= pFontInstance
->mxFontMetric
->GetBoldUnderlineSize();
312 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetBoldUnderlineOffset();
315 case LINESTYLE_DOUBLE
:
318 nLineHeight
= pFontInstance
->mxFontMetric
->GetAboveDoubleUnderlineSize();
319 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetAboveDoubleUnderlineOffset1();
320 nLinePos2
= nY
+ pFontInstance
->mxFontMetric
->GetAboveDoubleUnderlineOffset2();
324 nLineHeight
= pFontInstance
->mxFontMetric
->GetDoubleUnderlineSize();
325 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetDoubleUnderlineOffset1();
326 nLinePos2
= nY
+ pFontInstance
->mxFontMetric
->GetDoubleUnderlineOffset2();
336 if ( mbLineColor
|| mbInitLineColor
)
338 mpGraphics
->SetLineColor();
339 mbInitLineColor
= true;
341 mpGraphics
->SetFillColor( aColor
);
342 mbInitFillColor
= true;
344 tools::Long nLeft
= nDistX
;
348 case LINESTYLE_SINGLE
:
350 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
352 case LINESTYLE_DOUBLE
:
353 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
354 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos2
, nWidth
, nLineHeight
);
356 case LINESTYLE_DOTTED
:
357 case LINESTYLE_BOLDDOTTED
:
359 tools::Long nDotWidth
= nLineHeight
*mnDPIY
;
360 nDotWidth
+= mnDPIY
/2;
363 tools::Long nTempWidth
= nDotWidth
;
364 tools::Long nEnd
= nLeft
+nWidth
;
365 while ( nLeft
< nEnd
)
367 if ( nLeft
+nTempWidth
> nEnd
)
368 nTempWidth
= nEnd
-nLeft
;
370 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempWidth
, nLineHeight
);
371 nLeft
+= nDotWidth
*2;
376 case LINESTYLE_LONGDASH
:
377 case LINESTYLE_BOLDDASH
:
378 case LINESTYLE_BOLDLONGDASH
:
380 tools::Long nDotWidth
= nLineHeight
*mnDPIY
;
381 nDotWidth
+= mnDPIY
/2;
384 tools::Long nMinDashWidth
;
385 tools::Long nMinSpaceWidth
;
386 tools::Long nSpaceWidth
;
387 tools::Long nDashWidth
;
388 if ( (eTextLine
== LINESTYLE_LONGDASH
) ||
389 (eTextLine
== LINESTYLE_BOLDLONGDASH
) )
391 nMinDashWidth
= nDotWidth
*6;
392 nMinSpaceWidth
= nDotWidth
*2;
398 nMinDashWidth
= nDotWidth
*4;
399 nMinSpaceWidth
= (nDotWidth
*150)/100;
403 nDashWidth
= ((nDashWidth
*mnDPIX
)+1270)/2540;
404 nSpaceWidth
= ((nSpaceWidth
*mnDPIX
)+1270)/2540;
405 // DashWidth will be increased if the line is getting too thick
406 // in proportion to the line's length
407 if ( nDashWidth
< nMinDashWidth
)
408 nDashWidth
= nMinDashWidth
;
409 if ( nSpaceWidth
< nMinSpaceWidth
)
410 nSpaceWidth
= nMinSpaceWidth
;
412 tools::Long nTempWidth
= nDashWidth
;
413 tools::Long nEnd
= nLeft
+nWidth
;
414 while ( nLeft
< nEnd
)
416 if ( nLeft
+nTempWidth
> nEnd
)
417 nTempWidth
= nEnd
-nLeft
;
418 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempWidth
, nLineHeight
);
419 nLeft
+= nDashWidth
+nSpaceWidth
;
423 case LINESTYLE_DASHDOT
:
424 case LINESTYLE_BOLDDASHDOT
:
426 tools::Long nDotWidth
= nLineHeight
*mnDPIY
;
427 nDotWidth
+= mnDPIY
/2;
430 tools::Long nDashWidth
= ((100*mnDPIX
)+1270)/2540;
431 tools::Long nMinDashWidth
= nDotWidth
*4;
432 // DashWidth will be increased if the line is getting too thick
433 // in proportion to the line's length
434 if ( nDashWidth
< nMinDashWidth
)
435 nDashWidth
= nMinDashWidth
;
437 tools::Long nTempDotWidth
= nDotWidth
;
438 tools::Long nTempDashWidth
= nDashWidth
;
439 tools::Long nEnd
= nLeft
+nWidth
;
440 while ( nLeft
< nEnd
)
442 if ( nLeft
+nTempDotWidth
> nEnd
)
443 nTempDotWidth
= nEnd
-nLeft
;
445 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDotWidth
, nLineHeight
);
446 nLeft
+= nDotWidth
*2;
450 if ( nLeft
+nTempDashWidth
> nEnd
)
451 nTempDashWidth
= nEnd
-nLeft
;
453 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDashWidth
, nLineHeight
);
454 nLeft
+= nDashWidth
+nDotWidth
;
458 case LINESTYLE_DASHDOTDOT
:
459 case LINESTYLE_BOLDDASHDOTDOT
:
461 tools::Long nDotWidth
= nLineHeight
*mnDPIY
;
462 nDotWidth
+= mnDPIY
/2;
465 tools::Long nDashWidth
= ((100*mnDPIX
)+1270)/2540;
466 tools::Long nMinDashWidth
= nDotWidth
*4;
467 // DashWidth will be increased if the line is getting too thick
468 // in proportion to the line's length
469 if ( nDashWidth
< nMinDashWidth
)
470 nDashWidth
= nMinDashWidth
;
472 tools::Long nTempDotWidth
= nDotWidth
;
473 tools::Long nTempDashWidth
= nDashWidth
;
474 tools::Long nEnd
= nLeft
+nWidth
;
475 while ( nLeft
< nEnd
)
477 if ( nLeft
+nTempDotWidth
> nEnd
)
478 nTempDotWidth
= nEnd
-nLeft
;
480 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDotWidth
, nLineHeight
);
481 nLeft
+= nDotWidth
*2;
485 if ( nLeft
+nTempDotWidth
> nEnd
)
486 nTempDotWidth
= nEnd
-nLeft
;
488 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDotWidth
, nLineHeight
);
489 nLeft
+= nDotWidth
*2;
493 if ( nLeft
+nTempDashWidth
> nEnd
)
494 nTempDashWidth
= nEnd
-nLeft
;
496 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDashWidth
, nLineHeight
);
497 nLeft
+= nDashWidth
+nDotWidth
;
506 void OutputDevice::ImplDrawStrikeoutLine( tools::Long nBaseX
, tools::Long nBaseY
,
507 tools::Long nDistX
, tools::Long nDistY
, tools::Long nWidth
,
508 FontStrikeout eStrikeout
,
511 LogicalFontInstance
* pFontInstance
= mpFontInstance
.get();
512 tools::Long nLineHeight
= 0;
513 tools::Long nLinePos
= 0;
514 tools::Long nLinePos2
= 0;
516 tools::Long nY
= nDistY
;
518 if ( eStrikeout
> STRIKEOUT_LAST
)
519 eStrikeout
= STRIKEOUT_SINGLE
;
521 switch ( eStrikeout
)
523 case STRIKEOUT_SINGLE
:
524 nLineHeight
= pFontInstance
->mxFontMetric
->GetStrikeoutSize();
525 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetStrikeoutOffset();
528 nLineHeight
= pFontInstance
->mxFontMetric
->GetBoldStrikeoutSize();
529 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetBoldStrikeoutOffset();
531 case STRIKEOUT_DOUBLE
:
532 nLineHeight
= pFontInstance
->mxFontMetric
->GetDoubleStrikeoutSize();
533 nLinePos
= nY
+ pFontInstance
->mxFontMetric
->GetDoubleStrikeoutOffset1();
534 nLinePos2
= nY
+ pFontInstance
->mxFontMetric
->GetDoubleStrikeoutOffset2();
543 if ( mbLineColor
|| mbInitLineColor
)
545 mpGraphics
->SetLineColor();
546 mbInitLineColor
= true;
548 mpGraphics
->SetFillColor( aColor
);
549 mbInitFillColor
= true;
551 const tools::Long
& nLeft
= nDistX
;
553 switch ( eStrikeout
)
555 case STRIKEOUT_SINGLE
:
557 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
559 case STRIKEOUT_DOUBLE
:
560 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
561 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos2
, nWidth
, nLineHeight
);
568 void OutputDevice::ImplDrawStrikeoutChar( tools::Long nBaseX
, tools::Long nBaseY
,
569 tools::Long nDistX
, tools::Long nDistY
, tools::Long nWidth
,
570 FontStrikeout eStrikeout
,
573 // See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
578 // prepare string for strikeout measurement
579 const char cStrikeoutChar
= eStrikeout
== STRIKEOUT_SLASH
? '/' : 'X';
580 static const int nTestStrLen
= 4;
581 static const int nMaxStrikeStrLen
= 2048;
582 sal_Unicode aChars
[nMaxStrikeStrLen
+1]; // +1 for valgrind...
584 for( int i
= 0; i
< nTestStrLen
; ++i
)
585 aChars
[i
] = cStrikeoutChar
;
587 const OUString
aStrikeoutTest(aChars
, nTestStrLen
);
589 // calculate approximation of strikeout atom size
590 tools::Long nStrikeoutWidth
= 0;
591 std::unique_ptr
<SalLayout
> pLayout
= ImplLayout( aStrikeoutTest
, 0, nTestStrLen
);
594 nStrikeoutWidth
= pLayout
->GetTextWidth() / (nTestStrLen
* pLayout
->GetUnitsPerPixel());
596 if( nStrikeoutWidth
<= 0 ) // sanity check
599 int nStrikeStrLen
= (nWidth
+(nStrikeoutWidth
-1)) / nStrikeoutWidth
;
600 if( nStrikeStrLen
> nMaxStrikeStrLen
)
601 nStrikeStrLen
= nMaxStrikeStrLen
;
603 // build the strikeout string
604 for( int i
= nTestStrLen
; i
< nStrikeStrLen
; ++i
)
605 aChars
[i
] = cStrikeoutChar
;
607 const OUString
aStrikeoutText(aChars
, nStrikeStrLen
);
609 if( mpFontInstance
->mnOrientation
)
611 Point
aOriginPt(0, 0);
612 aOriginPt
.RotateAround( nDistX
, nDistY
, mpFontInstance
->mnOrientation
);
618 // strikeout text has to be left aligned
619 ComplexTextLayoutFlags nOrigTLM
= mnTextLayoutMode
;
620 mnTextLayoutMode
= ComplexTextLayoutFlags::BiDiStrong
;
621 pLayout
= ImplLayout( aStrikeoutText
, 0, aStrikeoutText
.getLength() );
622 mnTextLayoutMode
= nOrigTLM
;
627 // draw the strikeout text
628 const Color aOldColor
= GetTextColor();
629 SetTextColor( aColor
);
632 pLayout
->DrawBase() = Point( nBaseX
+mnTextOffX
, nBaseY
+mnTextOffY
);
634 tools::Rectangle aPixelRect
;
635 aPixelRect
.SetLeft( nBaseX
+mnTextOffX
);
636 aPixelRect
.SetRight( aPixelRect
.Left()+nWidth
);
637 aPixelRect
.SetBottom( nBaseY
+mpFontInstance
->mxFontMetric
->GetDescent() );
638 aPixelRect
.SetTop( nBaseY
-mpFontInstance
->mxFontMetric
->GetAscent() );
640 if (mpFontInstance
->mnOrientation
)
642 tools::Polygon
aPoly( aPixelRect
);
643 aPoly
.Rotate( Point(nBaseX
+mnTextOffX
, nBaseY
+mnTextOffY
), mpFontInstance
->mnOrientation
);
644 aPixelRect
= aPoly
.GetBoundRect();
647 Push( PushFlags::CLIPREGION
);
648 IntersectClipRegion( PixelToLogic(aPixelRect
) );
649 if( mbInitClipRegion
)
652 pLayout
->DrawText( *mpGraphics
);
656 SetTextColor( aOldColor
);
660 void OutputDevice::ImplDrawTextLine( tools::Long nX
, tools::Long nY
,
661 tools::Long nDistX
, DeviceCoordinate nWidth
,
662 FontStrikeout eStrikeout
,
663 FontLineStyle eUnderline
,
664 FontLineStyle eOverline
,
665 bool bUnderlineAbove
)
670 Color aStrikeoutColor
= GetTextColor();
671 Color aUnderlineColor
= GetTextLineColor();
672 Color aOverlineColor
= GetOverlineColor();
673 bool bStrikeoutDone
= false;
674 bool bUnderlineDone
= false;
675 bool bOverlineDone
= false;
677 if ( IsRTLEnabled() )
679 tools::Long nXAdd
= nWidth
- nDistX
;
680 if( mpFontInstance
->mnOrientation
)
681 nXAdd
= FRound( nXAdd
* cos( mpFontInstance
->mnOrientation
.get() * F_PI1800
) );
686 if ( !IsTextLineColor() )
687 aUnderlineColor
= GetTextColor();
689 if ( !IsOverlineColor() )
690 aOverlineColor
= GetTextColor();
692 if ( (eUnderline
== LINESTYLE_SMALLWAVE
) ||
693 (eUnderline
== LINESTYLE_WAVE
) ||
694 (eUnderline
== LINESTYLE_DOUBLEWAVE
) ||
695 (eUnderline
== LINESTYLE_BOLDWAVE
) )
697 ImplDrawWaveTextLine( nX
, nY
, nDistX
, 0, nWidth
, eUnderline
, aUnderlineColor
, bUnderlineAbove
);
698 bUnderlineDone
= true;
700 if ( (eOverline
== LINESTYLE_SMALLWAVE
) ||
701 (eOverline
== LINESTYLE_WAVE
) ||
702 (eOverline
== LINESTYLE_DOUBLEWAVE
) ||
703 (eOverline
== LINESTYLE_BOLDWAVE
) )
705 ImplDrawWaveTextLine( nX
, nY
, nDistX
, 0, nWidth
, eOverline
, aOverlineColor
, true );
706 bOverlineDone
= true;
709 if ( (eStrikeout
== STRIKEOUT_SLASH
) ||
710 (eStrikeout
== STRIKEOUT_X
) )
712 ImplDrawStrikeoutChar( nX
, nY
, nDistX
, 0, nWidth
, eStrikeout
, aStrikeoutColor
);
713 bStrikeoutDone
= true;
716 if ( !bUnderlineDone
)
717 ImplDrawStraightTextLine( nX
, nY
, nDistX
, 0, nWidth
, eUnderline
, aUnderlineColor
, bUnderlineAbove
);
719 if ( !bOverlineDone
)
720 ImplDrawStraightTextLine( nX
, nY
, nDistX
, 0, nWidth
, eOverline
, aOverlineColor
, true );
722 if ( !bStrikeoutDone
)
723 ImplDrawStrikeoutLine( nX
, nY
, nDistX
, 0, nWidth
, eStrikeout
, aStrikeoutColor
);
726 void OutputDevice::ImplDrawTextLines( SalLayout
& rSalLayout
, FontStrikeout eStrikeout
,
727 FontLineStyle eUnderline
, FontLineStyle eOverline
,
728 bool bWordLine
, bool bUnderlineAbove
)
732 // draw everything relative to the layout base point
733 const Point aStartPt
= rSalLayout
.DrawBase();
735 // calculate distance of each word from the base point
737 DeviceCoordinate nDist
= 0;
738 DeviceCoordinate nWidth
= 0;
739 const GlyphItem
* pGlyph
;
741 while (rSalLayout
.GetNextGlyph(&pGlyph
, aPos
, nStart
))
743 // calculate the boundaries of each word
744 if (!pGlyph
->IsSpacing())
748 // get the distance to the base point (as projected to baseline)
749 nDist
= aPos
.X() - aStartPt
.X();
750 if( mpFontInstance
->mnOrientation
)
752 const tools::Long nDY
= aPos
.Y() - aStartPt
.Y();
753 const double fRad
= mpFontInstance
->mnOrientation
.get() * F_PI1800
;
754 nDist
= FRound( nDist
*cos(fRad
) - nDY
*sin(fRad
) );
758 // update the length of the textline
759 nWidth
+= pGlyph
->m_nNewWidth
;
761 else if( nWidth
> 0 )
763 // draw the textline for each word
764 ImplDrawTextLine( aStartPt
.X(), aStartPt
.Y(), nDist
, nWidth
,
765 eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
770 // draw textline for the last word
773 ImplDrawTextLine( aStartPt
.X(), aStartPt
.Y(), nDist
, nWidth
,
774 eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
779 Point aStartPt
= rSalLayout
.GetDrawPosition();
780 ImplDrawTextLine( aStartPt
.X(), aStartPt
.Y(), 0,
781 rSalLayout
.GetTextWidth() / rSalLayout
.GetUnitsPerPixel(),
782 eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
786 void OutputDevice::ImplDrawMnemonicLine( tools::Long nX
, tools::Long nY
, tools::Long nWidth
)
788 tools::Long nBaseX
= nX
;
789 if( /*HasMirroredGraphics() &&*/ IsRTLEnabled() )
791 // add some strange offset
793 // revert the hack that will be done later in ImplDrawTextLine
794 nX
= nBaseX
- nWidth
- (nX
- nBaseX
- 1);
797 ImplDrawTextLine( nX
, nY
, 0, nWidth
, STRIKEOUT_NONE
, LINESTYLE_SINGLE
, LINESTYLE_NONE
, false );
800 void OutputDevice::SetTextLineColor()
804 mpMetaFile
->AddAction( new MetaTextLineColorAction( Color(), false ) );
806 maTextLineColor
= COL_TRANSPARENT
;
809 mpAlphaVDev
->SetTextLineColor();
812 void OutputDevice::SetTextLineColor( const Color
& rColor
)
815 Color
aColor( rColor
);
817 if ( mnDrawMode
& ( DrawModeFlags::BlackText
| DrawModeFlags::WhiteText
|
818 DrawModeFlags::GrayText
|
819 DrawModeFlags::SettingsText
) )
821 if ( mnDrawMode
& DrawModeFlags::BlackText
)
825 else if ( mnDrawMode
& DrawModeFlags::WhiteText
)
829 else if ( mnDrawMode
& DrawModeFlags::GrayText
)
831 const sal_uInt8 cLum
= aColor
.GetLuminance();
832 aColor
= Color( cLum
, cLum
, cLum
);
834 else if ( mnDrawMode
& DrawModeFlags::SettingsText
)
836 aColor
= GetSettings().GetStyleSettings().GetFontColor();
841 mpMetaFile
->AddAction( new MetaTextLineColorAction( aColor
, true ) );
843 maTextLineColor
= aColor
;
846 mpAlphaVDev
->SetTextLineColor( COL_BLACK
);
849 void OutputDevice::SetOverlineColor()
853 mpMetaFile
->AddAction( new MetaOverlineColorAction( Color(), false ) );
855 maOverlineColor
= COL_TRANSPARENT
;
858 mpAlphaVDev
->SetOverlineColor();
861 void OutputDevice::SetOverlineColor( const Color
& rColor
)
864 Color
aColor( rColor
);
866 if ( mnDrawMode
& ( DrawModeFlags::BlackText
| DrawModeFlags::WhiteText
|
867 DrawModeFlags::GrayText
|
868 DrawModeFlags::SettingsText
) )
870 if ( mnDrawMode
& DrawModeFlags::BlackText
)
874 else if ( mnDrawMode
& DrawModeFlags::WhiteText
)
878 else if ( mnDrawMode
& DrawModeFlags::GrayText
)
880 const sal_uInt8 cLum
= aColor
.GetLuminance();
881 aColor
= Color( cLum
, cLum
, cLum
);
883 else if ( mnDrawMode
& DrawModeFlags::SettingsText
)
885 aColor
= GetSettings().GetStyleSettings().GetFontColor();
890 mpMetaFile
->AddAction( new MetaOverlineColorAction( aColor
, true ) );
892 maOverlineColor
= aColor
;
895 mpAlphaVDev
->SetOverlineColor( COL_BLACK
);
898 void OutputDevice::DrawTextLine( const Point
& rPos
, tools::Long nWidth
,
899 FontStrikeout eStrikeout
,
900 FontLineStyle eUnderline
,
901 FontLineStyle eOverline
,
902 bool bUnderlineAbove
)
904 assert(!is_double_buffered_window());
907 mpMetaFile
->AddAction( new MetaTextLineAction( rPos
, nWidth
, eStrikeout
, eUnderline
, eOverline
) );
909 if ( ((eUnderline
== LINESTYLE_NONE
) || (eUnderline
== LINESTYLE_DONTKNOW
)) &&
910 ((eOverline
== LINESTYLE_NONE
) || (eOverline
== LINESTYLE_DONTKNOW
)) &&
911 ((eStrikeout
== STRIKEOUT_NONE
) || (eStrikeout
== STRIKEOUT_DONTKNOW
)) )
915 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
918 if( mbInitClipRegion
)
921 if( mbOutputClipped
)
924 // initialize font if needed to get text offsets
925 // TODO: only needed for mnTextOff!=(0,0)
929 Point aPos
= ImplLogicToDevicePixel( rPos
);
930 DeviceCoordinate fWidth
;
931 fWidth
= LogicWidthToDeviceCoordinate( nWidth
);
932 aPos
+= Point( mnTextOffX
, mnTextOffY
);
933 ImplDrawTextLine( aPos
.X(), aPos
.X(), 0, fWidth
, eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
936 mpAlphaVDev
->DrawTextLine( rPos
, nWidth
, eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
939 void OutputDevice::DrawWaveLine(const Point
& rStartPos
, const Point
& rEndPos
, tools::Long nLineWidth
)
941 assert(!is_double_buffered_window());
943 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
946 // we need a graphics
947 if( !mpGraphics
&& !AcquireGraphics() )
950 if ( mbInitClipRegion
)
953 if ( mbOutputClipped
)
959 Point aStartPt
= ImplLogicToDevicePixel(rStartPos
);
960 Point aEndPt
= ImplLogicToDevicePixel(rEndPos
);
962 tools::Long nStartX
= aStartPt
.X();
963 tools::Long nStartY
= aStartPt
.Y();
964 tools::Long nEndX
= aEndPt
.X();
965 tools::Long nEndY
= aEndPt
.Y();
966 double fOrientation
= 0.0;
969 if (nStartY
!= nEndY
|| nStartX
> nEndX
)
971 tools::Long nLengthX
= nEndX
- nStartX
;
972 fOrientation
= std::atan2(nStartY
- nEndY
, (nLengthX
== 0 ? 0.000000001 : nLengthX
));
973 fOrientation
/= F_PI180
;
974 // un-rotate the end point
975 aStartPt
.RotateAround(nEndX
, nEndY
, Degree10(static_cast<sal_Int16
>(-fOrientation
* 10.0)));
978 tools::Long nWaveHeight
= 3;
981 float fScaleFactor
= GetDPIScaleFactor();
982 if (fScaleFactor
> 1.0f
)
984 nWaveHeight
*= fScaleFactor
;
986 nStartY
+= fScaleFactor
- 1; // Shift down additional pixel(s) to create more visual separation.
988 // odd heights look better than even
989 if (nWaveHeight
% 2 == 0)
995 // #109280# make sure the waveline does not exceed the descent to avoid paint problems
996 LogicalFontInstance
* pFontInstance
= mpFontInstance
.get();
997 if (nWaveHeight
> pFontInstance
->mxFontMetric
->GetWavelineUnderlineSize())
999 nWaveHeight
= pFontInstance
->mxFontMetric
->GetWavelineUnderlineSize();
1000 // tdf#124848 hairline
1004 const basegfx::B2DRectangle
aWaveLineRectangle(nStartX
, nStartY
, nEndX
, nEndY
+ nWaveHeight
);
1005 const basegfx::B2DPolygon aWaveLinePolygon
= basegfx::createWaveLinePolygon(aWaveLineRectangle
);
1006 const basegfx::B2DHomMatrix aRotationMatrix
= basegfx::utils::createRotateAroundPoint(nStartX
, nStartY
, basegfx::deg2rad(-fOrientation
));
1007 const bool bPixelSnapHairline(mnAntialiasing
& AntialiasingFlags::PixelSnapHairline
);
1009 mpGraphics
->SetLineColor(GetLineColor());
1010 mpGraphics
->DrawPolyLine(
1016 basegfx::B2DLineJoin::NONE
,
1017 css::drawing::LineCap_BUTT
,
1018 basegfx::deg2rad(15.0),
1023 mpAlphaVDev
->DrawWaveLine( rStartPos
, rEndPos
, nLineWidth
);
1026 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */