LibreOffice Module vcl (master)  1
textline.cxx
Go to the documentation of this file.
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 <cassert>
21 
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>
28 
29 #include <tools/helpers.hxx>
30 
31 #include <salgdi.hxx>
32 #include <impglyphitem.hxx>
33 
36 
37 #define UNDERLINE_LAST LINESTYLE_BOLDWAVE
38 #define STRIKEOUT_LAST STRIKEOUT_X
39 
41 {
42  mpFontInstance->mxFontMetric->ImplInitTextLineSize( this );
43 }
44 
46 {
47  mpFontInstance->mxFontMetric->ImplInitAboveTextLineSize();
48 }
49 
50 void OutputDevice::ImplDrawWavePixel( long nOriginX, long nOriginY,
51  long nCurX, long nCurY,
52  short nOrientation,
53  SalGraphics* pGraphics,
54  OutputDevice const * pOutDev,
55  bool bDrawPixAsRect,
56  long nPixWidth, long nPixHeight )
57 {
58  if ( nOrientation )
59  {
60  Point aPoint( nOriginX, nOriginY );
61  aPoint.RotateAround( nCurX, nCurY, nOrientation );
62  }
63 
64  if ( bDrawPixAsRect )
65  {
66 
67  pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
68  }
69  else
70  {
71  pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
72  }
73 }
74 
75 void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
76  long nDistX, long nDistY,
77  long nWidth, long nHeight,
78  long nLineWidth, short nOrientation,
79  const Color& rColor )
80 {
81  if ( !nHeight )
82  return;
83 
84  long nStartX = nBaseX + nDistX;
85  long nStartY = nBaseY + nDistY;
86 
87  // If the height is 1 pixel, it's enough output a line
88  if ( (nLineWidth == 1) && (nHeight == 1) )
89  {
90  mpGraphics->SetLineColor( rColor );
91  mbInitLineColor = true;
92 
93  long nEndX = nStartX+nWidth;
94  long nEndY = nStartY;
95  if ( nOrientation )
96  {
97  Point aOriginPt( nBaseX, nBaseY );
98  aOriginPt.RotateAround( nStartX, nStartY, nOrientation );
99  aOriginPt.RotateAround( nEndX, nEndY, nOrientation );
100  }
101  mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
102  }
103  else
104  {
105  long nCurX = nStartX;
106  long nCurY = nStartY;
107  long nDiffX = 2;
108  long nDiffY = nHeight-1;
109  long nCount = nWidth;
110  long nOffY = -1;
111  long nPixWidth;
112  long nPixHeight;
113  bool bDrawPixAsRect;
114  // On printers that output pixel via DrawRect()
115  if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
116  {
117  if ( mbLineColor || mbInitLineColor )
118  {
120  mbInitLineColor = true;
121  }
122  mpGraphics->SetFillColor( rColor );
123  mbInitFillColor = true;
124  bDrawPixAsRect = true;
125  nPixWidth = nLineWidth;
126  nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
127  }
128  else
129  {
130  mpGraphics->SetLineColor( rColor );
131  mbInitLineColor = true;
132  nPixWidth = 1;
133  nPixHeight = 1;
134  bDrawPixAsRect = false;
135  }
136 
137  if ( !nDiffY )
138  {
139  while ( nWidth )
140  {
141  ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
142  mpGraphics, this,
143  bDrawPixAsRect, nPixWidth, nPixHeight );
144  nCurX++;
145  nWidth--;
146  }
147  }
148  else
149  {
150  nCurY += nDiffY;
151  long nFreq = nCount / (nDiffX+nDiffY);
152  while ( nFreq-- )
153  {
154  for( long i = nDiffY; i; --i )
155  {
156  ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
157  mpGraphics, this,
158  bDrawPixAsRect, nPixWidth, nPixHeight );
159  nCurX++;
160  nCurY += nOffY;
161  }
162  for( long i = nDiffX; i; --i )
163  {
164  ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
165  mpGraphics, this,
166  bDrawPixAsRect, nPixWidth, nPixHeight );
167  nCurX++;
168  }
169  nOffY = -nOffY;
170  }
171  nFreq = nCount % (nDiffX+nDiffY);
172  if ( nFreq )
173  {
174  for( long i = nDiffY; i && nFreq; --i, --nFreq )
175  {
176  ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
177  mpGraphics, this,
178  bDrawPixAsRect, nPixWidth, nPixHeight );
179  nCurX++;
180  nCurY += nOffY;
181 
182  }
183  for( long i = nDiffX; i && nFreq; --i, --nFreq )
184  {
185  ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
186  mpGraphics, this,
187  bDrawPixAsRect, nPixWidth, nPixHeight );
188  nCurX++;
189  }
190  }
191  }
192  }
193 }
194 
195 void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
196  long nDistX, long nDistY, long nWidth,
197  FontLineStyle eTextLine,
198  Color aColor,
199  bool bIsAbove )
200 {
201  LogicalFontInstance* pFontInstance = mpFontInstance.get();
202  long nLineHeight;
203  long nLinePos;
204 
205  if ( bIsAbove )
206  {
207  nLineHeight = pFontInstance->mxFontMetric->GetAboveWavelineUnderlineSize();
208  nLinePos = pFontInstance->mxFontMetric->GetAboveWavelineUnderlineOffset();
209  }
210  else
211  {
212  nLineHeight = pFontInstance->mxFontMetric->GetWavelineUnderlineSize();
213  nLinePos = pFontInstance->mxFontMetric->GetWavelineUnderlineOffset();
214  }
215  if ( (eTextLine == LINESTYLE_SMALLWAVE) && (nLineHeight > 3) )
216  nLineHeight = 3;
217 
218  long nLineWidth = mnDPIX / 300;
219  if ( !nLineWidth )
220  nLineWidth = 1;
221 
222  if ( eTextLine == LINESTYLE_BOLDWAVE )
223  nLineWidth *= 2;
224 
225  nLinePos += nDistY - (nLineHeight / 2);
226 
227  long nLineWidthHeight = ((nLineWidth * mnDPIX) + (mnDPIY / 2)) / mnDPIY;
228  if ( eTextLine == LINESTYLE_DOUBLEWAVE )
229  {
230  long nOrgLineHeight = nLineHeight;
231  nLineHeight /= 3;
232  if ( nLineHeight < 2 )
233  {
234  if ( nOrgLineHeight > 1 )
235  nLineHeight = 2;
236  else
237  nLineHeight = 1;
238  }
239 
240  long nLineDY = nOrgLineHeight-(nLineHeight*2);
241  if ( nLineDY < nLineWidthHeight )
242  nLineDY = nLineWidthHeight;
243 
244  long nLineDY2 = nLineDY/2;
245  if ( !nLineDY2 )
246  nLineDY2 = 1;
247 
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 );
254  }
255  else
256  {
257  nLinePos -= nLineWidthHeight/2;
258  ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
259  nLineWidth, mpFontInstance->mnOrientation, aColor );
260  }
261 }
262 
263 void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
264  long nDistX, long nDistY, long nWidth,
265  FontLineStyle eTextLine,
266  Color aColor,
267  bool bIsAbove )
268 {
269  LogicalFontInstance* pFontInstance = mpFontInstance.get();
270  long nLineHeight = 0;
271  long nLinePos = 0;
272  long nLinePos2 = 0;
273 
274  const long nY = nDistY;
275 
276  if ( eTextLine > UNDERLINE_LAST )
277  eTextLine = LINESTYLE_SINGLE;
278 
279  switch ( eTextLine )
280  {
281  case LINESTYLE_SINGLE:
282  case LINESTYLE_DOTTED:
283  case LINESTYLE_DASH:
284  case LINESTYLE_LONGDASH:
285  case LINESTYLE_DASHDOT:
287  if ( bIsAbove )
288  {
289  nLineHeight = pFontInstance->mxFontMetric->GetAboveUnderlineSize();
290  nLinePos = nY + pFontInstance->mxFontMetric->GetAboveUnderlineOffset();
291  }
292  else
293  {
294  nLineHeight = pFontInstance->mxFontMetric->GetUnderlineSize();
295  nLinePos = nY + pFontInstance->mxFontMetric->GetUnderlineOffset();
296  }
297  break;
298  case LINESTYLE_BOLD:
300  case LINESTYLE_BOLDDASH:
304  if ( bIsAbove )
305  {
306  nLineHeight = pFontInstance->mxFontMetric->GetAboveBoldUnderlineSize();
307  nLinePos = nY + pFontInstance->mxFontMetric->GetAboveBoldUnderlineOffset();
308  }
309  else
310  {
311  nLineHeight = pFontInstance->mxFontMetric->GetBoldUnderlineSize();
312  nLinePos = nY + pFontInstance->mxFontMetric->GetBoldUnderlineOffset();
313  }
314  break;
315  case LINESTYLE_DOUBLE:
316  if ( bIsAbove )
317  {
318  nLineHeight = pFontInstance->mxFontMetric->GetAboveDoubleUnderlineSize();
319  nLinePos = nY + pFontInstance->mxFontMetric->GetAboveDoubleUnderlineOffset1();
320  nLinePos2 = nY + pFontInstance->mxFontMetric->GetAboveDoubleUnderlineOffset2();
321  }
322  else
323  {
324  nLineHeight = pFontInstance->mxFontMetric->GetDoubleUnderlineSize();
325  nLinePos = nY + pFontInstance->mxFontMetric->GetDoubleUnderlineOffset1();
326  nLinePos2 = nY + pFontInstance->mxFontMetric->GetDoubleUnderlineOffset2();
327  }
328  break;
329  default:
330  break;
331  }
332 
333  if ( nLineHeight )
334  {
335  if ( mbLineColor || mbInitLineColor )
336  {
338  mbInitLineColor = true;
339  }
340  mpGraphics->SetFillColor( aColor );
341  mbInitFillColor = true;
342 
343  long nLeft = nDistX;
344 
345  switch ( eTextLine )
346  {
347  case LINESTYLE_SINGLE:
348  case LINESTYLE_BOLD:
349  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
350  break;
351  case LINESTYLE_DOUBLE:
352  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
353  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
354  break;
355  case LINESTYLE_DOTTED:
357  {
358  long nDotWidth = nLineHeight*mnDPIY;
359  nDotWidth += mnDPIY/2;
360  nDotWidth /= mnDPIY;
361 
362  long nTempWidth = nDotWidth;
363  long nEnd = nLeft+nWidth;
364  while ( nLeft < nEnd )
365  {
366  if ( nLeft+nTempWidth > nEnd )
367  nTempWidth = nEnd-nLeft;
368 
369  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
370  nLeft += nDotWidth*2;
371  }
372  }
373  break;
374  case LINESTYLE_DASH:
375  case LINESTYLE_LONGDASH:
376  case LINESTYLE_BOLDDASH:
378  {
379  long nDotWidth = nLineHeight*mnDPIY;
380  nDotWidth += mnDPIY/2;
381  nDotWidth /= mnDPIY;
382 
383  long nMinDashWidth;
384  long nMinSpaceWidth;
385  long nSpaceWidth;
386  long nDashWidth;
387  if ( (eTextLine == LINESTYLE_LONGDASH) ||
388  (eTextLine == LINESTYLE_BOLDLONGDASH) )
389  {
390  nMinDashWidth = nDotWidth*6;
391  nMinSpaceWidth = nDotWidth*2;
392  nDashWidth = 200;
393  nSpaceWidth = 100;
394  }
395  else
396  {
397  nMinDashWidth = nDotWidth*4;
398  nMinSpaceWidth = (nDotWidth*150)/100;
399  nDashWidth = 100;
400  nSpaceWidth = 50;
401  }
402  nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
403  nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
404  // DashWidth will be increased if the line is getting too thick
405  // in proportion to the line's length
406  if ( nDashWidth < nMinDashWidth )
407  nDashWidth = nMinDashWidth;
408  if ( nSpaceWidth < nMinSpaceWidth )
409  nSpaceWidth = nMinSpaceWidth;
410 
411  long nTempWidth = nDashWidth;
412  long nEnd = nLeft+nWidth;
413  while ( nLeft < nEnd )
414  {
415  if ( nLeft+nTempWidth > nEnd )
416  nTempWidth = nEnd-nLeft;
417  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
418  nLeft += nDashWidth+nSpaceWidth;
419  }
420  }
421  break;
422  case LINESTYLE_DASHDOT:
424  {
425  long nDotWidth = nLineHeight*mnDPIY;
426  nDotWidth += mnDPIY/2;
427  nDotWidth /= mnDPIY;
428 
429  long nDashWidth = ((100*mnDPIX)+1270)/2540;
430  long nMinDashWidth = nDotWidth*4;
431  // DashWidth will be increased if the line is getting too thick
432  // in proportion to the line's length
433  if ( nDashWidth < nMinDashWidth )
434  nDashWidth = nMinDashWidth;
435 
436  long nTempDotWidth = nDotWidth;
437  long nTempDashWidth = nDashWidth;
438  long nEnd = nLeft+nWidth;
439  while ( nLeft < nEnd )
440  {
441  if ( nLeft+nTempDotWidth > nEnd )
442  nTempDotWidth = nEnd-nLeft;
443 
444  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
445  nLeft += nDotWidth*2;
446  if ( nLeft > nEnd )
447  break;
448 
449  if ( nLeft+nTempDashWidth > nEnd )
450  nTempDashWidth = nEnd-nLeft;
451 
452  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
453  nLeft += nDashWidth+nDotWidth;
454  }
455  }
456  break;
459  {
460  long nDotWidth = nLineHeight*mnDPIY;
461  nDotWidth += mnDPIY/2;
462  nDotWidth /= mnDPIY;
463 
464  long nDashWidth = ((100*mnDPIX)+1270)/2540;
465  long nMinDashWidth = nDotWidth*4;
466  // DashWidth will be increased if the line is getting too thick
467  // in proportion to the line's length
468  if ( nDashWidth < nMinDashWidth )
469  nDashWidth = nMinDashWidth;
470 
471  long nTempDotWidth = nDotWidth;
472  long nTempDashWidth = nDashWidth;
473  long nEnd = nLeft+nWidth;
474  while ( nLeft < nEnd )
475  {
476  if ( nLeft+nTempDotWidth > nEnd )
477  nTempDotWidth = nEnd-nLeft;
478 
479  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
480  nLeft += nDotWidth*2;
481  if ( nLeft > nEnd )
482  break;
483 
484  if ( nLeft+nTempDotWidth > nEnd )
485  nTempDotWidth = nEnd-nLeft;
486 
487  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
488  nLeft += nDotWidth*2;
489  if ( nLeft > nEnd )
490  break;
491 
492  if ( nLeft+nTempDashWidth > nEnd )
493  nTempDashWidth = nEnd-nLeft;
494 
495  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
496  nLeft += nDashWidth+nDotWidth;
497  }
498  }
499  break;
500  default:
501  break;
502  }
503  }
504 }
505 
506 void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
507  long nDistX, long nDistY, long nWidth,
508  FontStrikeout eStrikeout,
509  Color aColor )
510 {
511  LogicalFontInstance* pFontInstance = mpFontInstance.get();
512  long nLineHeight = 0;
513  long nLinePos = 0;
514  long nLinePos2 = 0;
515 
516  long nY = nDistY;
517 
518  if ( eStrikeout > STRIKEOUT_LAST )
519  eStrikeout = STRIKEOUT_SINGLE;
520 
521  switch ( eStrikeout )
522  {
523  case STRIKEOUT_SINGLE:
524  nLineHeight = pFontInstance->mxFontMetric->GetStrikeoutSize();
525  nLinePos = nY + pFontInstance->mxFontMetric->GetStrikeoutOffset();
526  break;
527  case STRIKEOUT_BOLD:
528  nLineHeight = pFontInstance->mxFontMetric->GetBoldStrikeoutSize();
529  nLinePos = nY + pFontInstance->mxFontMetric->GetBoldStrikeoutOffset();
530  break;
531  case STRIKEOUT_DOUBLE:
532  nLineHeight = pFontInstance->mxFontMetric->GetDoubleStrikeoutSize();
533  nLinePos = nY + pFontInstance->mxFontMetric->GetDoubleStrikeoutOffset1();
534  nLinePos2 = nY + pFontInstance->mxFontMetric->GetDoubleStrikeoutOffset2();
535  break;
536  default:
537  break;
538  }
539 
540  if ( nLineHeight )
541  {
542  if ( mbLineColor || mbInitLineColor )
543  {
545  mbInitLineColor = true;
546  }
547  mpGraphics->SetFillColor( aColor );
548  mbInitFillColor = true;
549 
550  const long& nLeft = nDistX;
551 
552  switch ( eStrikeout )
553  {
554  case STRIKEOUT_SINGLE:
555  case STRIKEOUT_BOLD:
556  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
557  break;
558  case STRIKEOUT_DOUBLE:
559  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
560  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
561  break;
562  default:
563  break;
564  }
565  }
566 }
567 
568 void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
569  long nDistX, long nDistY, long nWidth,
570  FontStrikeout eStrikeout,
571  Color aColor )
572 {
573  // See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
574  // to tweak this
575  if (!nWidth)
576  return;
577 
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...
583 
584  for( int i = 0; i < nTestStrLen; ++i)
585  aChars[i] = cStrikeoutChar;
586 
587  const OUString aStrikeoutTest(aChars, nTestStrLen);
588 
589  // calculate approximation of strikeout atom size
590  long nStrikeoutWidth = 0;
591  std::unique_ptr<SalLayout> pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
592  if( pLayout )
593  {
594  nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
595  }
596  if( nStrikeoutWidth <= 0 ) // sanity check
597  return;
598 
599  int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
600  if( nStrikeStrLen > nMaxStrikeStrLen )
601  nStrikeStrLen = nMaxStrikeStrLen;
602 
603  // build the strikeout string
604  for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
605  aChars[i] = cStrikeoutChar;
606 
607  const OUString aStrikeoutText(aChars, nStrikeStrLen);
608 
609  if( mpFontInstance->mnOrientation )
610  {
611  Point aOriginPt(0, 0);
612  aOriginPt.RotateAround( nDistX, nDistY, mpFontInstance->mnOrientation );
613  }
614 
615  nBaseX += nDistX;
616  nBaseY += nDistY;
617 
618  // strikeout text has to be left aligned
621  pLayout = ImplLayout( aStrikeoutText, 0, aStrikeoutText.getLength() );
622  mnTextLayoutMode = nOrigTLM;
623 
624  if( !pLayout )
625  return;
626 
627  // draw the strikeout text
628  const Color aOldColor = GetTextColor();
629  SetTextColor( aColor );
631 
632  pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
633 
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() );
639 
640  if (mpFontInstance->mnOrientation)
641  {
642  tools::Polygon aPoly( aPixelRect );
643  aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontInstance->mnOrientation);
644  aPixelRect = aPoly.GetBoundRect();
645  }
646 
648  IntersectClipRegion( PixelToLogic(aPixelRect) );
649  if( mbInitClipRegion )
650  InitClipRegion();
651 
652  pLayout->DrawText( *mpGraphics );
653 
654  Pop();
655 
656  SetTextColor( aOldColor );
658 }
659 
660 void OutputDevice::ImplDrawTextLine( long nX, long nY,
661  long nDistX, DeviceCoordinate nWidth,
662  FontStrikeout eStrikeout,
663  FontLineStyle eUnderline,
664  FontLineStyle eOverline,
665  bool bUnderlineAbove )
666 {
667  if ( !nWidth )
668  return;
669 
670  Color aStrikeoutColor = GetTextColor();
671  Color aUnderlineColor = GetTextLineColor();
672  Color aOverlineColor = GetOverlineColor();
673  bool bStrikeoutDone = false;
674  bool bUnderlineDone = false;
675  bool bOverlineDone = false;
676 
677  if ( IsRTLEnabled() )
678  {
679  long nXAdd = nWidth - nDistX;
680  if( mpFontInstance->mnOrientation )
681  nXAdd = FRound( nXAdd * cos( mpFontInstance->mnOrientation * F_PI1800 ) );
682 
683  nX += nXAdd - 1;
684  }
685 
686  if ( !IsTextLineColor() )
687  aUnderlineColor = GetTextColor();
688 
689  if ( !IsOverlineColor() )
690  aOverlineColor = GetTextColor();
691 
692  if ( (eUnderline == LINESTYLE_SMALLWAVE) ||
693  (eUnderline == LINESTYLE_WAVE) ||
694  (eUnderline == LINESTYLE_DOUBLEWAVE) ||
695  (eUnderline == LINESTYLE_BOLDWAVE) )
696  {
697  ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
698  bUnderlineDone = true;
699  }
700  if ( (eOverline == LINESTYLE_SMALLWAVE) ||
701  (eOverline == LINESTYLE_WAVE) ||
702  (eOverline == LINESTYLE_DOUBLEWAVE) ||
703  (eOverline == LINESTYLE_BOLDWAVE) )
704  {
705  ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
706  bOverlineDone = true;
707  }
708 
709  if ( (eStrikeout == STRIKEOUT_SLASH) ||
710  (eStrikeout == STRIKEOUT_X) )
711  {
712  ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
713  bStrikeoutDone = true;
714  }
715 
716  if ( !bUnderlineDone )
717  ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
718 
719  if ( !bOverlineDone )
720  ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
721 
722  if ( !bStrikeoutDone )
723  ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
724 }
725 
727  FontLineStyle eUnderline, FontLineStyle eOverline,
728  bool bWordLine, bool bUnderlineAbove )
729 {
730  if( bWordLine )
731  {
732  // draw everything relative to the layout base point
733  const Point aStartPt = rSalLayout.DrawBase();
734 
735  // calculate distance of each word from the base point
736  Point aPos;
737  DeviceCoordinate nDist = 0;
738  DeviceCoordinate nWidth = 0;
739  const GlyphItem* pGlyph;
740  int nStart = 0;
741  while (rSalLayout.GetNextGlyph(&pGlyph, aPos, nStart))
742  {
743  // calculate the boundaries of each word
744  if (!pGlyph->IsSpacing())
745  {
746  if( !nWidth )
747  {
748  // get the distance to the base point (as projected to baseline)
749  nDist = aPos.X() - aStartPt.X();
750  if( mpFontInstance->mnOrientation )
751  {
752  const long nDY = aPos.Y() - aStartPt.Y();
753  const double fRad = mpFontInstance->mnOrientation * F_PI1800;
754  nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
755  }
756  }
757 
758  // update the length of the textline
759  nWidth += pGlyph->m_nNewWidth;
760  }
761  else if( nWidth > 0 )
762  {
763  // draw the textline for each word
764  ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
765  eStrikeout, eUnderline, eOverline, bUnderlineAbove );
766  nWidth = 0;
767  }
768  }
769 
770  // draw textline for the last word
771  if( nWidth > 0 )
772  {
773  ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
774  eStrikeout, eUnderline, eOverline, bUnderlineAbove );
775  }
776  }
777  else
778  {
779  Point aStartPt = rSalLayout.GetDrawPosition();
780  ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0,
781  rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel(),
782  eStrikeout, eUnderline, eOverline, bUnderlineAbove );
783  }
784 }
785 
786 void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
787 {
788  long nBaseX = nX;
789  if( /*HasMirroredGraphics() &&*/ IsRTLEnabled() )
790  {
791  // add some strange offset
792  nX += 2;
793  // revert the hack that will be done later in ImplDrawTextLine
794  nX = nBaseX - nWidth - (nX - nBaseX - 1);
795  }
796 
797  ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, LINESTYLE_SINGLE, LINESTYLE_NONE, false );
798 }
799 
801 {
802 
803  if ( mpMetaFile )
805 
807 
808  if( mpAlphaVDev )
810 }
811 
813 {
814 
815  Color aColor( rColor );
816 
820  {
822  {
823  aColor = COL_BLACK;
824  }
826  {
827  aColor = COL_WHITE;
828  }
829  else if ( mnDrawMode & DrawModeFlags::GrayText )
830  {
831  const sal_uInt8 cLum = aColor.GetLuminance();
832  aColor = Color( cLum, cLum, cLum );
833  }
835  {
837  }
838  }
839 
840  if ( mpMetaFile )
841  mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, true ) );
842 
843  maTextLineColor = aColor;
844 
845  if( mpAlphaVDev )
847 }
848 
850 {
851 
852  if ( mpMetaFile )
854 
856 
857  if( mpAlphaVDev )
859 }
860 
862 {
863 
864  Color aColor( rColor );
865 
869  {
871  {
872  aColor = COL_BLACK;
873  }
875  {
876  aColor = COL_WHITE;
877  }
878  else if ( mnDrawMode & DrawModeFlags::GrayText )
879  {
880  const sal_uInt8 cLum = aColor.GetLuminance();
881  aColor = Color( cLum, cLum, cLum );
882  }
884  {
886  }
887  }
888 
889  if ( mpMetaFile )
890  mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, true ) );
891 
892  maOverlineColor = aColor;
893 
894  if( mpAlphaVDev )
896 }
897 
898 void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
899  FontStrikeout eStrikeout,
900  FontLineStyle eUnderline,
901  FontLineStyle eOverline,
902  bool bUnderlineAbove )
903 {
904  assert(!is_double_buffered_window());
905 
906  if ( mpMetaFile )
907  mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
908 
909  if ( ((eUnderline == LINESTYLE_NONE) || (eUnderline == LINESTYLE_DONTKNOW)) &&
910  ((eOverline == LINESTYLE_NONE) || (eOverline == LINESTYLE_DONTKNOW)) &&
911  ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
912  {
913  return;
914  }
916  return;
917 
918  if( mbInitClipRegion )
919  InitClipRegion();
920 
921  if( mbOutputClipped )
922  return;
923 
924  // initialize font if needed to get text offsets
925  // TODO: only needed for mnTextOff!=(0,0)
926  if (!InitFont())
927  return;
928 
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 );
934 
935  if( mpAlphaVDev )
936  mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
937 }
938 
939 void OutputDevice::DrawWaveLine(const Point& rStartPos, const Point& rEndPos, long nLineWidth)
940 {
941  assert(!is_double_buffered_window());
942 
944  return;
945 
946  // we need a graphics
947  if( !mpGraphics && !AcquireGraphics() )
948  return;
949 
950  if ( mbInitClipRegion )
951  InitClipRegion();
952 
953  if ( mbOutputClipped )
954  return;
955 
956  if (!InitFont())
957  return;
958 
959  Point aStartPt = ImplLogicToDevicePixel(rStartPos);
960  Point aEndPt = ImplLogicToDevicePixel(rEndPos);
961 
962  long nStartX = aStartPt.X();
963  long nStartY = aStartPt.Y();
964  long nEndX = aEndPt.X();
965  long nEndY = aEndPt.Y();
966  double fOrientation = 0.0;
967 
968  // handle rotation
969  if (nStartY != nEndY || nStartX > nEndX)
970  {
971  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, -fOrientation * 10.0);
976  }
977 
978  long nWaveHeight = 3;
979 
980  // Handle HiDPI
981  float fScaleFactor = GetDPIScaleFactor();
982  if (fScaleFactor > 1.0f)
983  {
984  nWaveHeight *= fScaleFactor;
985 
986  nStartY += fScaleFactor - 1; // Shift down additional pixel(s) to create more visual separation.
987 
988  // odd heights look better than even
989  if (nWaveHeight % 2 == 0)
990  {
991  nWaveHeight--;
992  }
993  }
994 
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())
998  {
999  nWaveHeight = pFontInstance->mxFontMetric->GetWavelineUnderlineSize();
1000  nLineWidth = 1;
1001  }
1002 
1003  const basegfx::B2DRectangle aWaveLineRectangle(nStartX, nStartY, nEndX, nEndY + nWaveHeight);
1004  const basegfx::B2DPolygon aWaveLinePolygon = basegfx::createWaveLinePolygon(aWaveLineRectangle);
1005  const basegfx::B2DHomMatrix aRotationMatrix = basegfx::utils::createRotateAroundPoint(nStartX, nStartY, basegfx::deg2rad(-fOrientation));
1006  const basegfx::B2DVector aLineWidth(nLineWidth, nLineWidth);
1007  const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
1008 
1011  aRotationMatrix, aWaveLinePolygon, 0.0, aLineWidth,
1012  basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT,
1013  basegfx::deg2rad(15.0), bPixelSnapHairline, this);
1014 
1015  if( mpAlphaVDev )
1016  mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nLineWidth );
1017 }
1018 
1019 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long GetAboveDoubleUnderlineSize() const
SAL_DLLPRIVATE void ImplDrawStrikeoutChar(long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontStrikeout eStrikeout, Color aColor)
Definition: textline.cxx:568
const Color & GetTextColor() const
Definition: outdev.hxx:1110
OutDevType GetOutDevType() const
Definition: outdev.hxx:522
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:657
int GetUnitsPerPixel() const
Definition: vcllayout.hxx:80
long FRound(double fVal)
void DrawWaveLine(const Point &rStartPos, const Point &rEndPos, long nLineWidth=1)
Definition: textline.cxx:939
long GetBoldStrikeoutSize() const
long GetAboveDoubleUnderlineOffset1() const
const Color & GetTextLineColor() const
Definition: outdev.hxx:1119
DrawModeFlags mnDrawMode
Definition: outdev.hxx:355
LINESTYLE_BOLD
long GetAboveWavelineUnderlineSize() const
const StyleSettings & GetStyleSettings() const
#define F_PI1800
sal_uInt8 GetLuminance() const
long GetStrikeoutOffset() const
bool IsTextLineColor() const
Definition: outdev.hxx:1120
virtual DeviceCoordinate GetTextWidth() const
Definition: vcllayout.hxx:86
bool mbOutputClipped
Definition: outdev.hxx:381
static SAL_DLLPRIVATE void ImplDrawWavePixel(long nOriginX, long nOriginY, long nCurX, long nCurY, short nOrientation, SalGraphics *pGraphics, OutputDevice const *pOutDev, bool bDrawPixAsRect, long nPixWidth, long nPixHeight)
Definition: textline.cxx:50
LINESTYLE_BOLDWAVE
void ImplDrawTextLine(long nBaseX, long nX, long nY, DeviceCoordinate nWidth, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bUnderlineAbove)
Definition: textline.cxx:660
SAL_DLLPRIVATE void ImplInitTextColor()
Definition: text.cxx:72
SAL_DLLPRIVATE bool is_double_buffered_window() const
sal_Int32 mnDPIY
Definition: outdev.hxx:348
long GetDoubleStrikeoutOffset2() const
void IntersectClipRegion(const tools::Rectangle &rRect)
sal_Int32 mnDPIX
Definition: outdev.hxx:347
STRIKEOUT_SLASH
bool IsSpacing() const
void DrawRect(long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev)
ImplFontMetricDataRef mxFontMetric
long GetAboveBoldUnderlineOffset() const
LINESTYLE_DASH
long GetAboveBoldUnderlineSize() const
long GetAboveWavelineUnderlineOffset() const
const Color & GetOverlineColor() const
Definition: outdev.hxx:1124
LINESTYLE_DASHDOT
sal_uInt16 sal_Unicode
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
Color maOverlineColor
Definition: outdev.hxx:367
LINESTYLE_BOLDDASHDOTDOT
long GetAboveDoubleUnderlineOffset2() const
long GetBoldUnderlineSize() const
LINESTYLE_NONE
#define UNDERLINE_LAST
Definition: textline.cxx:37
long GetAboveUnderlineSize() const
AntialiasingFlags mnAntialiasing
Definition: outdev.hxx:373
long DeviceCoordinate
STRIKEOUT_SINGLE
void SetTextLineColor()
Definition: textline.cxx:800
void DrawPolyLine(sal_uInt32 nPoints, SalPoint const *pPtAry, const OutputDevice *pOutDev)
void Rotate(const Point &rCenter, double fSin, double fCos)
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:316
long GetDoubleStrikeoutOffset1() const
virtual void SetFillColor()=0
SAL_DLLPRIVATE void ImplDrawWaveTextLine(long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove)
Definition: textline.cxx:195
SAL_DLLPRIVATE void ImplDrawWaveLine(long nBaseX, long nBaseY, long nStartX, long nStartY, long nWidth, long nHeight, long nLineWidth, short nOrientation, const Color &rColor)
Definition: textline.cxx:75
long GetDoubleUnderlineSize() const
bool IsRTLEnabled() const
Definition: outdev.hxx:1354
void SetTop(long v)
virtual void SetLineColor()=0
ComplexTextLayoutFlags
Definition: outdevstate.hxx:66
LINESTYLE_DOUBLEWAVE
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
LINESTYLE_WAVE
int i
long GetUnderlineSize() const
SAL_DLLPRIVATE void ImplInitAboveTextLineSize()
Definition: textline.cxx:45
void SetRight(long v)
bool mbInitLineColor
Definition: outdev.hxx:384
SAL_DLLPRIVATE void ImplDrawStrikeoutLine(long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontStrikeout eStrikeout, Color aColor)
Definition: textline.cxx:506
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:304
const Color & GetFontColor() const
const Color & GetLineColor() const
Definition: outdev.hxx:618
LINESTYLE_SINGLE
void SetTextColor(const Color &rColor)
Definition: text.cxx:663
void DrawTextLine(const Point &rPos, long nWidth, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bUnderlineAbove=false)
Definition: textline.cxx:898
long GetBoldUnderlineOffset() const
LINESTYLE_BOLDLONGDASH
Point GetDrawPosition(const Point &rRelative=Point(0, 0)) const
Definition: sallayout.cxx:560
bool mbLineColor
Definition: outdev.hxx:382
constexpr double deg2rad(double v)
LINESTYLE_SMALLWAVE
void SetOverlineColor()
Definition: textline.cxx:849
long GetWavelineUnderlineSize() const
const AllSettings & GetSettings() const
Definition: outdev.hxx:420
Color maTextLineColor
Definition: outdev.hxx:366
long GetWavelineUnderlineOffset() const
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), long nLogicWidth=0, const long *pLogicDXArray=nullptr, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1234
LINESTYLE_DONTKNOW
long X() const
SAL_DLLPRIVATE void ImplDrawTextRect(long nBaseX, long nBaseY, long nX, long nY, long nWidth, long nHeight)
Definition: text.cxx:83
void DrawPixel(long nX, long nY, const OutputDevice *pOutDev)
STRIKEOUT_X
Point & DrawBase()
Definition: vcllayout.hxx:69
float GetDPIScaleFactor() const
Definition: outdev.hxx:512
LINESTYLE_LONGDASH
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1185
long GetStrikeoutSize() const
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:331
SAL_DLLPRIVATE void ImplDrawStraightTextLine(long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove)
Definition: textline.cxx:263
BASEGFX_DLLPUBLIC B2DPolygon createWaveLinePolygon(basegfx::B2DRectangle const &rRectangle)
#define F_PI180
STRIKEOUT_DOUBLE
LINESTYLE_DASHDOTDOT
long GetDoubleUnderlineOffset1() const
unsigned char sal_uInt8
long GetUnderlineOffset() const
LINESTYLE_DOTTED
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:540
bool mbInitClipRegion
Definition: outdev.hxx:388
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
void RotateAround(long &rX, long &rY, short nOrientation) const
void SetBottom(long v)
virtual void InitClipRegion()
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
#define STRIKEOUT_LAST
Definition: textline.cxx:38
long Left() const
rtl::Reference< LogicalFontInstance > mpFontInstance
Definition: outdev.hxx:320
virtual bool GetNextGlyph(const GlyphItem **pGlyph, Point &rPos, int &nStart, const PhysicalFontFace **pFallbackFont=nullptr, int *const pFallbackLevel=nullptr) const =0
bool mbInitFillColor
Definition: outdev.hxx:385
long mnTextOffX
font specific text alignment offsets in pixel units
Definition: outdev.hxx:351
LINESTYLE_BOLDDOTTED
long GetDoubleUnderlineOffset2() const
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:504
STRIKEOUT_DONTKNOW
ComplexTextLayoutFlags mnTextLayoutMode
Definition: outdev.hxx:356
LINESTYLE_BOLDDASH
void SetLeft(long v)
void(* f)(TrueTypeTable *)
Definition: ttcr.cxx:466
SAL_DLLPRIVATE void ImplInitTextLineSize()
Definition: textline.cxx:40
tools::Rectangle GetBoundRect() const
LINESTYLE_DOUBLE
bool IsOverlineColor() const
Definition: outdev.hxx:1125
void DrawLine(long nX1, long nY1, long nX2, long nY2, const OutputDevice *pOutDev)
STRIKEOUT_NONE
long GetAboveUnderlineOffset() const
FontLineStyle
SAL_DLLPRIVATE DeviceCoordinate LogicWidthToDeviceCoordinate(long nWidth) const
Definition: map.cxx:1927
void ImplDrawTextLines(SalLayout &, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bWordLine, bool bUnderlineAbove)
Definition: textline.cxx:726
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:589
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
FontStrikeout
long mnTextOffY
Definition: outdev.hxx:352
SAL_DLLPRIVATE void ImplDrawMnemonicLine(long nX, long nY, long nWidth)
Definition: textline.cxx:786
LINESTYLE_BOLDDASHDOT
long GetBoldStrikeoutOffset() const
STRIKEOUT_BOLD
long Y() const
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:319
long GetDoubleStrikeoutSize() const
SAL_DLLPRIVATE bool InitFont() const