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  return;
335 
336  if ( mbLineColor || mbInitLineColor )
337  {
339  mbInitLineColor = true;
340  }
341  mpGraphics->SetFillColor( aColor );
342  mbInitFillColor = true;
343 
344  long nLeft = nDistX;
345 
346  switch ( eTextLine )
347  {
348  case LINESTYLE_SINGLE:
349  case LINESTYLE_BOLD:
350  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
351  break;
352  case LINESTYLE_DOUBLE:
353  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
354  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
355  break;
356  case LINESTYLE_DOTTED:
358  {
359  long nDotWidth = nLineHeight*mnDPIY;
360  nDotWidth += mnDPIY/2;
361  nDotWidth /= mnDPIY;
362 
363  long nTempWidth = nDotWidth;
364  long nEnd = nLeft+nWidth;
365  while ( nLeft < nEnd )
366  {
367  if ( nLeft+nTempWidth > nEnd )
368  nTempWidth = nEnd-nLeft;
369 
370  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
371  nLeft += nDotWidth*2;
372  }
373  }
374  break;
375  case LINESTYLE_DASH:
376  case LINESTYLE_LONGDASH:
377  case LINESTYLE_BOLDDASH:
379  {
380  long nDotWidth = nLineHeight*mnDPIY;
381  nDotWidth += mnDPIY/2;
382  nDotWidth /= mnDPIY;
383 
384  long nMinDashWidth;
385  long nMinSpaceWidth;
386  long nSpaceWidth;
387  long nDashWidth;
388  if ( (eTextLine == LINESTYLE_LONGDASH) ||
389  (eTextLine == LINESTYLE_BOLDLONGDASH) )
390  {
391  nMinDashWidth = nDotWidth*6;
392  nMinSpaceWidth = nDotWidth*2;
393  nDashWidth = 200;
394  nSpaceWidth = 100;
395  }
396  else
397  {
398  nMinDashWidth = nDotWidth*4;
399  nMinSpaceWidth = (nDotWidth*150)/100;
400  nDashWidth = 100;
401  nSpaceWidth = 50;
402  }
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;
411 
412  long nTempWidth = nDashWidth;
413  long nEnd = nLeft+nWidth;
414  while ( nLeft < nEnd )
415  {
416  if ( nLeft+nTempWidth > nEnd )
417  nTempWidth = nEnd-nLeft;
418  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
419  nLeft += nDashWidth+nSpaceWidth;
420  }
421  }
422  break;
423  case LINESTYLE_DASHDOT:
425  {
426  long nDotWidth = nLineHeight*mnDPIY;
427  nDotWidth += mnDPIY/2;
428  nDotWidth /= mnDPIY;
429 
430  long nDashWidth = ((100*mnDPIX)+1270)/2540;
431  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;
436 
437  long nTempDotWidth = nDotWidth;
438  long nTempDashWidth = nDashWidth;
439  long nEnd = nLeft+nWidth;
440  while ( nLeft < nEnd )
441  {
442  if ( nLeft+nTempDotWidth > nEnd )
443  nTempDotWidth = nEnd-nLeft;
444 
445  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
446  nLeft += nDotWidth*2;
447  if ( nLeft > nEnd )
448  break;
449 
450  if ( nLeft+nTempDashWidth > nEnd )
451  nTempDashWidth = nEnd-nLeft;
452 
453  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
454  nLeft += nDashWidth+nDotWidth;
455  }
456  }
457  break;
460  {
461  long nDotWidth = nLineHeight*mnDPIY;
462  nDotWidth += mnDPIY/2;
463  nDotWidth /= mnDPIY;
464 
465  long nDashWidth = ((100*mnDPIX)+1270)/2540;
466  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;
471 
472  long nTempDotWidth = nDotWidth;
473  long nTempDashWidth = nDashWidth;
474  long nEnd = nLeft+nWidth;
475  while ( nLeft < nEnd )
476  {
477  if ( nLeft+nTempDotWidth > nEnd )
478  nTempDotWidth = nEnd-nLeft;
479 
480  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
481  nLeft += nDotWidth*2;
482  if ( nLeft > nEnd )
483  break;
484 
485  if ( nLeft+nTempDotWidth > nEnd )
486  nTempDotWidth = nEnd-nLeft;
487 
488  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
489  nLeft += nDotWidth*2;
490  if ( nLeft > nEnd )
491  break;
492 
493  if ( nLeft+nTempDashWidth > nEnd )
494  nTempDashWidth = nEnd-nLeft;
495 
496  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
497  nLeft += nDashWidth+nDotWidth;
498  }
499  }
500  break;
501  default:
502  break;
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  return;
542 
543  if ( mbLineColor || mbInitLineColor )
544  {
546  mbInitLineColor = true;
547  }
548  mpGraphics->SetFillColor( aColor );
549  mbInitFillColor = true;
550 
551  const long& nLeft = nDistX;
552 
553  switch ( eStrikeout )
554  {
555  case STRIKEOUT_SINGLE:
556  case STRIKEOUT_BOLD:
557  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
558  break;
559  case STRIKEOUT_DOUBLE:
560  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
561  ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
562  break;
563  default:
564  break;
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 )
804  mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), false ) );
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 )
853  mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), false ) );
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 {
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 {
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  // tdf#124848 hairline
1001  nLineWidth = 0;
1002  }
1003 
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);
1008 
1011  aRotationMatrix,
1012  aWaveLinePolygon,
1013  0.0,
1014  nLineWidth,
1015  nullptr, // MM01
1017  css::drawing::LineCap_BUTT,
1018  basegfx::deg2rad(15.0),
1019  bPixelSnapHairline,
1020  this);
1021 
1022  if( mpAlphaVDev )
1023  mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nLineWidth );
1024 }
1025 
1026 /* 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:1135
OutDevType GetOutDevType() const
Definition: outdev.hxx:524
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:641
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:1144
DrawModeFlags mnDrawMode
Definition: outdev.hxx:353
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:1145
virtual DeviceCoordinate GetTextWidth() const
Definition: vcllayout.hxx:86
bool mbOutputClipped
Definition: outdev.hxx:379
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:75
SAL_DLLPRIVATE bool is_double_buffered_window() const
sal_Int32 mnDPIY
Definition: outdev.hxx:346
long GetDoubleStrikeoutOffset2() const
void IntersectClipRegion(const tools::Rectangle &rRect)
sal_Int32 mnDPIX
Definition: outdev.hxx:345
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:1149
LINESTYLE_DASHDOT
sal_uInt16 sal_Unicode
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
Color maOverlineColor
Definition: outdev.hxx:365
LINESTYLE_BOLDDASHDOTDOT
long GetAboveDoubleUnderlineOffset2() const
long GetBoldUnderlineSize() const
LINESTYLE_NONE
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
#define UNDERLINE_LAST
Definition: textline.cxx:37
long GetAboveUnderlineSize() const
int nCount
AntialiasingFlags mnAntialiasing
Definition: outdev.hxx:371
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:314
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:1366
void SetTop(long v)
int i
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
long GetUnderlineSize() const
SAL_DLLPRIVATE void ImplInitAboveTextLineSize()
Definition: textline.cxx:45
void SetRight(long v)
bool mbInitLineColor
Definition: outdev.hxx:382
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:302
const Color & GetFontColor() const
const Color & GetLineColor() const
Definition: outdev.hxx:630
LINESTYLE_SINGLE
void SetTextColor(const Color &rColor)
Definition: text.cxx:666
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:380
constexpr double deg2rad(double v)
LINESTYLE_SMALLWAVE
void SetOverlineColor()
Definition: textline.cxx:849
long GetWavelineUnderlineSize() const
const AllSettings & GetSettings() const
Definition: outdev.hxx:418
Color maTextLineColor
Definition: outdev.hxx:364
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:1253
LINESTYLE_DONTKNOW
SAL_DLLPRIVATE void ImplDrawTextRect(long nBaseX, long nBaseY, long nX, long nY, long nWidth, long nHeight)
Definition: text.cxx:86
sal_Int32 nLineWidth
void DrawPixel(long nX, long nY, const OutputDevice *pOutDev)
STRIKEOUT_X
Point & DrawBase()
Definition: vcllayout.hxx:69
float GetDPIScaleFactor() const
Definition: outdev.hxx:514
LINESTYLE_LONGDASH
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1186
long GetStrikeoutSize() const
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:329
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:566
bool mbInitClipRegion
Definition: outdev.hxx:386
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
void SetBottom(long v)
virtual void InitClipRegion()
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
#define STRIKEOUT_LAST
Definition: textline.cxx:38
long Left() const
rtl::Reference< LogicalFontInstance > mpFontInstance
Definition: outdev.hxx:318
bool mbInitFillColor
Definition: outdev.hxx:383
long mnTextOffX
font specific text alignment offsets in pixel units
Definition: outdev.hxx:349
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
virtual bool GetNextGlyph(const GlyphItem **pGlyph, Point &rPos, int &nStart, const PhysicalFontFace **pFallbackFont=nullptr) const =0
ComplexTextLayoutFlags mnTextLayoutMode
Definition: outdev.hxx:354
LINESTYLE_BOLDDASH
void SetLeft(long v)
void(* f)(TrueTypeTable *)
Definition: ttcr.cxx:483
SAL_DLLPRIVATE void ImplInitTextLineSize()
Definition: textline.cxx:40
tools::Rectangle GetBoundRect() const
LINESTYLE_DOUBLE
bool IsOverlineColor() const
Definition: outdev.hxx:1150
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:1928
void ImplDrawTextLines(SalLayout &, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bWordLine, bool bUnderlineAbove)
Definition: textline.cxx:726
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:601
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
FontStrikeout
long mnTextOffY
Definition: outdev.hxx:350
SAL_DLLPRIVATE void ImplDrawMnemonicLine(long nX, long nY, long nWidth)
Definition: textline.cxx:786
LINESTYLE_BOLDDASHDOT
long GetBoldStrikeoutOffset() const
STRIKEOUT_BOLD
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:317
long GetDoubleStrikeoutSize() const
SAL_DLLPRIVATE bool InitFont() const