Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 : #include <sal/types.h>
20 :
21 : #include <vcl/outdev.hxx>
22 : #include <vcl/virdev.hxx>
23 : #include <vcl/settings.hxx>
24 :
25 : #include <tools/helpers.hxx>
26 :
27 : #include "salgdi.hxx"
28 : #include "impfont.hxx"
29 : #include "outdata.hxx"
30 :
31 : #include <config_graphite.h>
32 : #if ENABLE_GRAPHITE
33 : #include "graphite_features.hxx"
34 : #endif
35 :
36 : #define UNDERLINE_LAST UNDERLINE_BOLDWAVE
37 : #define STRIKEOUT_LAST STRIKEOUT_X
38 :
39 12378 : bool OutputDevice::ImplIsUnderlineAbove( const vcl::Font& rFont )
40 : {
41 12378 : if ( !rFont.IsVertical() )
42 12378 : return false;
43 :
44 0 : if( (LANGUAGE_JAPANESE == rFont.GetLanguage()) ||
45 0 : (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
46 : {
47 : // the underline is right for Japanese only
48 0 : return true;
49 : }
50 0 : return false;
51 : }
52 :
53 0 : void OutputDevice::ImplInitTextLineSize()
54 : {
55 0 : mpFontEntry->maMetric.ImplInitTextLineSize( this );
56 0 : }
57 :
58 0 : void OutputDevice::ImplInitAboveTextLineSize()
59 : {
60 0 : mpFontEntry->maMetric.ImplInitAboveTextLineSize();
61 0 : }
62 :
63 100834 : void OutputDevice::ImplDrawWavePixel( long nOriginX, long nOriginY,
64 : long nCurX, long nCurY,
65 : short nOrientation,
66 : SalGraphics* pGraphics,
67 : OutputDevice* pOutDev,
68 : bool bDrawPixAsRect,
69 : long nPixWidth, long nPixHeight )
70 : {
71 100834 : if ( nOrientation )
72 : {
73 84344 : Point aPoint( nOriginX, nOriginY );
74 84344 : aPoint.RotateAround( nCurX, nCurY, nOrientation );
75 : }
76 :
77 100834 : if ( bDrawPixAsRect )
78 : {
79 :
80 84344 : pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
81 : }
82 : else
83 : {
84 16490 : pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
85 : }
86 100834 : }
87 :
88 1564 : void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
89 : long nDistX, long nDistY,
90 : long nWidth, long nHeight,
91 : long nLineWidth, short nOrientation,
92 : const Color& rColor )
93 : {
94 1564 : if ( !nHeight )
95 1564 : return;
96 :
97 1564 : long nStartX = nBaseX + nDistX;
98 1564 : long nStartY = nBaseY + nDistY;
99 :
100 : // If the height is 1 pixel, it's enough ouput a line
101 1564 : if ( (nLineWidth == 1) && (nHeight == 1) )
102 : {
103 0 : mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
104 0 : mbInitLineColor = true;
105 :
106 0 : long nEndX = nStartX+nWidth;
107 0 : long nEndY = nStartY;
108 0 : if ( nOrientation )
109 : {
110 0 : Point aOriginPt( nBaseX, nBaseY );
111 0 : aOriginPt.RotateAround( nStartX, nStartY, nOrientation );
112 0 : aOriginPt.RotateAround( nEndX, nEndY, nOrientation );
113 : }
114 0 : mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
115 : }
116 : else
117 : {
118 1564 : long nCurX = nStartX;
119 1564 : long nCurY = nStartY;
120 1564 : long nDiffX = 2;
121 1564 : long nDiffY = nHeight-1;
122 1564 : long nCount = nWidth;
123 1564 : long nOffY = -1;
124 : long nFreq;
125 : long i;
126 : long nPixWidth;
127 : long nPixHeight;
128 : bool bDrawPixAsRect;
129 : // On printers that ouput pixel via DrawRect()
130 1564 : if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
131 : {
132 1468 : if ( mbLineColor || mbInitLineColor )
133 : {
134 1384 : mpGraphics->SetLineColor();
135 1384 : mbInitLineColor = true;
136 : }
137 1468 : mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
138 1468 : mbInitFillColor = true;
139 1468 : bDrawPixAsRect = true;
140 1468 : nPixWidth = nLineWidth;
141 1468 : nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
142 : }
143 : else
144 : {
145 96 : mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
146 96 : mbInitLineColor = true;
147 96 : nPixWidth = 1;
148 96 : nPixHeight = 1;
149 96 : bDrawPixAsRect = false;
150 : }
151 :
152 1564 : if ( !nDiffY )
153 : {
154 0 : while ( nWidth )
155 : {
156 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
157 : mpGraphics, this,
158 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
159 0 : nCurX++;
160 0 : nWidth--;
161 : }
162 : }
163 : else
164 : {
165 1564 : nCurY += nDiffY;
166 1564 : nFreq = nCount / (nDiffX+nDiffY);
167 18037 : while ( nFreq-- )
168 : {
169 81953 : for( i = nDiffY; i; --i )
170 : {
171 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
172 : mpGraphics, this,
173 67044 : bDrawPixAsRect, nPixWidth, nPixHeight );
174 67044 : nCurX++;
175 67044 : nCurY += nOffY;
176 : }
177 44727 : for( i = nDiffX; i; --i )
178 : {
179 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
180 : mpGraphics, this,
181 29818 : bDrawPixAsRect, nPixWidth, nPixHeight );
182 29818 : nCurX++;
183 : }
184 14909 : nOffY = -nOffY;
185 : }
186 1564 : nFreq = nCount % (nDiffX+nDiffY);
187 1564 : if ( nFreq )
188 : {
189 4531 : for( i = nDiffY; i && nFreq; --i, --nFreq )
190 : {
191 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
192 : mpGraphics, this,
193 3869 : bDrawPixAsRect, nPixWidth, nPixHeight );
194 3869 : nCurX++;
195 3869 : nCurY += nOffY;
196 :
197 : }
198 765 : for( i = nDiffX; i && nFreq; --i, --nFreq )
199 : {
200 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
201 : mpGraphics, this,
202 103 : bDrawPixAsRect, nPixWidth, nPixHeight );
203 103 : nCurX++;
204 : }
205 : }
206 : }
207 : }
208 : }
209 :
210 1470 : void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
211 : long nDistX, long nDistY, long nWidth,
212 : FontUnderline eTextLine,
213 : Color aColor,
214 : bool bIsAbove )
215 : {
216 1470 : ImplFontEntry* pFontEntry = mpFontEntry;
217 : long nLineHeight;
218 : long nLinePos;
219 :
220 1470 : if ( bIsAbove )
221 : {
222 0 : nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
223 0 : nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
224 : }
225 : else
226 : {
227 1470 : nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
228 1470 : nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
229 : }
230 1470 : if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
231 0 : nLineHeight = 3;
232 :
233 1470 : long nLineWidth = (mnDPIX / 300);
234 1470 : if ( !nLineWidth )
235 1470 : nLineWidth = 1;
236 :
237 1470 : if ( eTextLine == UNDERLINE_BOLDWAVE )
238 1468 : nLineWidth *= 2;
239 :
240 1470 : nLinePos += nDistY - (nLineHeight / 2);
241 :
242 1470 : long nLineWidthHeight = ((nLineWidth * mnDPIX) + (mnDPIY / 2)) / mnDPIY;
243 1470 : if ( eTextLine == UNDERLINE_DOUBLEWAVE )
244 : {
245 0 : long nOrgLineHeight = nLineHeight;
246 0 : nLineHeight /= 3;
247 0 : if ( nLineHeight < 2 )
248 : {
249 0 : if ( nOrgLineHeight > 1 )
250 0 : nLineHeight = 2;
251 : else
252 0 : nLineHeight = 1;
253 : }
254 :
255 0 : long nLineDY = nOrgLineHeight-(nLineHeight*2);
256 0 : if ( nLineDY < nLineWidthHeight )
257 0 : nLineDY = nLineWidthHeight;
258 :
259 0 : long nLineDY2 = nLineDY/2;
260 0 : if ( !nLineDY2 )
261 0 : nLineDY2 = 1;
262 :
263 0 : nLinePos -= nLineWidthHeight-nLineDY2;
264 : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
265 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
266 0 : nLinePos += nLineWidthHeight+nLineDY;
267 : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
268 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
269 : }
270 : else
271 : {
272 1470 : nLinePos -= nLineWidthHeight/2;
273 : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
274 1470 : nLineWidth, mpFontEntry->mnOrientation, aColor );
275 : }
276 1470 : }
277 :
278 56950 : void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
279 : long nDistX, long nDistY, long nWidth,
280 : FontUnderline eTextLine,
281 : Color aColor,
282 : bool bIsAbove )
283 : {
284 56950 : ImplFontEntry* pFontEntry = mpFontEntry;
285 56950 : long nLineHeight = 0;
286 56950 : long nLinePos = 0;
287 56950 : long nLinePos2 = 0;
288 :
289 56950 : const long nY = nDistY;
290 :
291 56950 : if ( eTextLine > UNDERLINE_LAST )
292 916 : eTextLine = UNDERLINE_SINGLE;
293 :
294 56950 : switch ( eTextLine )
295 : {
296 : case UNDERLINE_SINGLE:
297 : case UNDERLINE_DOTTED:
298 : case UNDERLINE_DASH:
299 : case UNDERLINE_LONGDASH:
300 : case UNDERLINE_DASHDOT:
301 : case UNDERLINE_DASHDOTDOT:
302 27825 : if ( bIsAbove )
303 : {
304 2653 : nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
305 2653 : nLinePos = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
306 : }
307 : else
308 : {
309 25172 : nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
310 25172 : nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
311 : }
312 27825 : break;
313 : case UNDERLINE_BOLD:
314 : case UNDERLINE_BOLDDOTTED:
315 : case UNDERLINE_BOLDDASH:
316 : case UNDERLINE_BOLDLONGDASH:
317 : case UNDERLINE_BOLDDASHDOT:
318 : case UNDERLINE_BOLDDASHDOTDOT:
319 466 : if ( bIsAbove )
320 : {
321 4 : nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
322 4 : nLinePos = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
323 : }
324 : else
325 : {
326 462 : nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
327 462 : nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
328 : }
329 466 : break;
330 : case UNDERLINE_DOUBLE:
331 2806 : if ( bIsAbove )
332 : {
333 1920 : nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
334 1920 : nLinePos = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
335 1920 : nLinePos2 = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
336 : }
337 : else
338 : {
339 886 : nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
340 886 : nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
341 886 : nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
342 : }
343 2806 : break;
344 : default:
345 25853 : break;
346 : }
347 :
348 56950 : if ( nLineHeight )
349 : {
350 31085 : if ( mbLineColor || mbInitLineColor )
351 : {
352 26291 : mpGraphics->SetLineColor();
353 26291 : mbInitLineColor = true;
354 : }
355 31085 : mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
356 31085 : mbInitFillColor = true;
357 :
358 31085 : long nLeft = nDistX;
359 :
360 31085 : switch ( eTextLine )
361 : {
362 : case UNDERLINE_SINGLE:
363 : case UNDERLINE_BOLD:
364 24659 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
365 24659 : break;
366 : case UNDERLINE_DOUBLE:
367 2806 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
368 2806 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
369 2806 : break;
370 : case UNDERLINE_DOTTED:
371 : case UNDERLINE_BOLDDOTTED:
372 : {
373 2348 : long nDotWidth = nLineHeight*mnDPIY;
374 2348 : nDotWidth += mnDPIY/2;
375 2348 : nDotWidth /= mnDPIY;
376 :
377 2348 : long nTempWidth = nDotWidth;
378 2348 : long nEnd = nLeft+nWidth;
379 26322 : while ( nLeft < nEnd )
380 : {
381 21626 : if ( nLeft+nTempWidth > nEnd )
382 594 : nTempWidth = nEnd-nLeft;
383 :
384 21626 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
385 21626 : nLeft += nDotWidth*2;
386 : }
387 : }
388 2348 : break;
389 : case UNDERLINE_DASH:
390 : case UNDERLINE_LONGDASH:
391 : case UNDERLINE_BOLDDASH:
392 : case UNDERLINE_BOLDLONGDASH:
393 : {
394 828 : long nDotWidth = nLineHeight*mnDPIY;
395 828 : nDotWidth += mnDPIY/2;
396 828 : nDotWidth /= mnDPIY;
397 :
398 : long nMinDashWidth;
399 : long nMinSpaceWidth;
400 : long nSpaceWidth;
401 : long nDashWidth;
402 828 : if ( (eTextLine == UNDERLINE_LONGDASH) ||
403 : (eTextLine == UNDERLINE_BOLDLONGDASH) )
404 : {
405 452 : nMinDashWidth = nDotWidth*6;
406 452 : nMinSpaceWidth = nDotWidth*2;
407 452 : nDashWidth = 200;
408 452 : nSpaceWidth = 100;
409 : }
410 : else
411 : {
412 376 : nMinDashWidth = nDotWidth*4;
413 376 : nMinSpaceWidth = (nDotWidth*150)/100;
414 376 : nDashWidth = 100;
415 376 : nSpaceWidth = 50;
416 : }
417 828 : nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
418 828 : nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
419 : // DashWidth will be increased if the line is getting too thick
420 : // in proportion to the line's length
421 828 : if ( nDashWidth < nMinDashWidth )
422 612 : nDashWidth = nMinDashWidth;
423 828 : if ( nSpaceWidth < nMinSpaceWidth )
424 612 : nSpaceWidth = nMinSpaceWidth;
425 :
426 828 : long nTempWidth = nDashWidth;
427 828 : long nEnd = nLeft+nWidth;
428 2560 : while ( nLeft < nEnd )
429 : {
430 904 : if ( nLeft+nTempWidth > nEnd )
431 814 : nTempWidth = nEnd-nLeft;
432 904 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
433 904 : nLeft += nDashWidth+nSpaceWidth;
434 : }
435 : }
436 828 : break;
437 : case UNDERLINE_DASHDOT:
438 : case UNDERLINE_BOLDDASHDOT:
439 : {
440 0 : long nDotWidth = nLineHeight*mnDPIY;
441 0 : nDotWidth += mnDPIY/2;
442 0 : nDotWidth /= mnDPIY;
443 :
444 0 : long nDashWidth = ((100*mnDPIX)+1270)/2540;
445 0 : long nMinDashWidth = nDotWidth*4;
446 : // DashWidth will be increased if the line is getting too thick
447 : // in proportion to the line's length
448 0 : if ( nDashWidth < nMinDashWidth )
449 0 : nDashWidth = nMinDashWidth;
450 :
451 0 : long nTempDotWidth = nDotWidth;
452 0 : long nTempDashWidth = nDashWidth;
453 0 : long nEnd = nLeft+nWidth;
454 0 : while ( nLeft < nEnd )
455 : {
456 0 : if ( nLeft+nTempDotWidth > nEnd )
457 0 : nTempDotWidth = nEnd-nLeft;
458 :
459 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
460 0 : nLeft += nDotWidth*2;
461 0 : if ( nLeft > nEnd )
462 0 : break;
463 :
464 0 : if ( nLeft+nTempDashWidth > nEnd )
465 0 : nTempDashWidth = nEnd-nLeft;
466 :
467 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
468 0 : nLeft += nDashWidth+nDotWidth;
469 : }
470 : }
471 0 : break;
472 : case UNDERLINE_DASHDOTDOT:
473 : case UNDERLINE_BOLDDASHDOTDOT:
474 : {
475 444 : long nDotWidth = nLineHeight*mnDPIY;
476 444 : nDotWidth += mnDPIY/2;
477 444 : nDotWidth /= mnDPIY;
478 :
479 444 : long nDashWidth = ((100*mnDPIX)+1270)/2540;
480 444 : long nMinDashWidth = nDotWidth*4;
481 : // DashWidth will be increased if the line is getting too thick
482 : // in proportion to the line's length
483 444 : if ( nDashWidth < nMinDashWidth )
484 444 : nDashWidth = nMinDashWidth;
485 :
486 444 : long nTempDotWidth = nDotWidth;
487 444 : long nTempDashWidth = nDashWidth;
488 444 : long nEnd = nLeft+nWidth;
489 1810 : while ( nLeft < nEnd )
490 : {
491 1086 : if ( nLeft+nTempDotWidth > nEnd )
492 24 : nTempDotWidth = nEnd-nLeft;
493 :
494 1086 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
495 1086 : nLeft += nDotWidth*2;
496 1086 : if ( nLeft > nEnd )
497 60 : break;
498 :
499 1026 : if ( nLeft+nTempDotWidth > nEnd )
500 92 : nTempDotWidth = nEnd-nLeft;
501 :
502 1026 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
503 1026 : nLeft += nDotWidth*2;
504 1026 : if ( nLeft > nEnd )
505 104 : break;
506 :
507 922 : if ( nLeft+nTempDashWidth > nEnd )
508 240 : nTempDashWidth = nEnd-nLeft;
509 :
510 922 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
511 922 : nLeft += nDashWidth+nDotWidth;
512 : }
513 : }
514 444 : break;
515 : default:
516 0 : break;
517 : }
518 : }
519 56950 : }
520 :
521 28272 : void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
522 : long nDistX, long nDistY, long nWidth,
523 : FontStrikeout eStrikeout,
524 : Color aColor )
525 : {
526 28272 : ImplFontEntry* pFontEntry = mpFontEntry;
527 28272 : long nLineHeight = 0;
528 28272 : long nLinePos = 0;
529 28272 : long nLinePos2 = 0;
530 :
531 28272 : long nY = nDistY;
532 :
533 28272 : if ( eStrikeout > STRIKEOUT_LAST )
534 2402 : eStrikeout = STRIKEOUT_SINGLE;
535 :
536 28272 : switch ( eStrikeout )
537 : {
538 : case STRIKEOUT_SINGLE:
539 4227 : nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
540 4227 : nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
541 4227 : break;
542 : case STRIKEOUT_BOLD:
543 324 : nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
544 324 : nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
545 324 : break;
546 : case STRIKEOUT_DOUBLE:
547 2195 : nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
548 2195 : nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
549 2195 : nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
550 2195 : break;
551 : default:
552 21526 : break;
553 : }
554 :
555 28272 : if ( nLineHeight )
556 : {
557 6746 : if ( mbLineColor || mbInitLineColor )
558 : {
559 4952 : mpGraphics->SetLineColor();
560 4952 : mbInitLineColor = true;
561 : }
562 6746 : mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
563 6746 : mbInitFillColor = true;
564 :
565 6746 : const long& nLeft = nDistX;
566 :
567 6746 : switch ( eStrikeout )
568 : {
569 : case STRIKEOUT_SINGLE:
570 : case STRIKEOUT_BOLD:
571 4551 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
572 4551 : break;
573 : case STRIKEOUT_DOUBLE:
574 2195 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
575 2195 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
576 2195 : break;
577 : default:
578 0 : break;
579 : }
580 : }
581 28272 : }
582 :
583 938 : void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
584 : long nDistX, long nDistY, long nWidth,
585 : FontStrikeout eStrikeout,
586 : Color aColor )
587 : {
588 : // See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
589 : // to tweak this
590 938 : if (!nWidth)
591 80 : return;
592 :
593 : // prepare string for strikeout measurement
594 938 : static char cStrikeoutChar = eStrikeout == STRIKEOUT_SLASH ? '/' : 'X';
595 : static const int nTestStrLen = 4;
596 : static const int nMaxStrikeStrLen = 2048;
597 : sal_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
598 :
599 4690 : for( int i = 0; i < nTestStrLen; ++i)
600 3752 : aChars[i] = cStrikeoutChar;
601 :
602 938 : const OUString aStrikeoutTest(aChars, nTestStrLen);
603 :
604 : // calculate approximation of strikeout atom size
605 938 : long nStrikeoutWidth = 0;
606 938 : SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
607 938 : if( pLayout )
608 : {
609 938 : nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
610 938 : pLayout->Release();
611 : }
612 938 : if( nStrikeoutWidth <= 0 ) // sanity check
613 80 : return;
614 :
615 858 : int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
616 858 : if( nStrikeStrLen > nMaxStrikeStrLen )
617 0 : nStrikeStrLen = nMaxStrikeStrLen;
618 :
619 : // build the strikeout string
620 4918 : for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
621 4060 : aChars[i] = cStrikeoutChar;
622 :
623 1716 : const OUString aStrikeoutText(aChars, nStrikeStrLen);
624 :
625 858 : if( mpFontEntry->mnOrientation )
626 : {
627 858 : Point aOriginPt(0, 0);
628 858 : aOriginPt.RotateAround( nDistX, nDistY, mpFontEntry->mnOrientation );
629 : }
630 :
631 858 : nBaseX += nDistX;
632 858 : nBaseY += nDistY;
633 :
634 : // strikeout text has to be left aligned
635 858 : ComplexTextLayoutMode nOrigTLM = mnTextLayoutMode;
636 858 : mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
637 858 : pLayout = ImplLayout( aStrikeoutText, 0, aStrikeoutText.getLength() );
638 858 : mnTextLayoutMode = nOrigTLM;
639 :
640 858 : if( !pLayout )
641 0 : return;
642 :
643 : // draw the strikeout text
644 858 : const Color aOldColor = GetTextColor();
645 858 : SetTextColor( aColor );
646 858 : ImplInitTextColor();
647 :
648 858 : pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
649 :
650 858 : Rectangle aPixelRect;
651 858 : aPixelRect.Left() = nBaseX+mnTextOffX;
652 858 : aPixelRect.Right() = aPixelRect.Left()+nWidth;
653 858 : aPixelRect.Bottom() = nBaseY+mpFontEntry->maMetric.mnDescent;
654 858 : aPixelRect.Top() = nBaseY-mpFontEntry->maMetric.mnAscent;
655 :
656 858 : if (mpFontEntry->mnOrientation)
657 : {
658 858 : Polygon aPoly( aPixelRect );
659 858 : aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
660 858 : aPixelRect = aPoly.GetBoundRect();
661 : }
662 :
663 858 : Push( PushFlags::CLIPREGION );
664 858 : IntersectClipRegion( PixelToLogic(aPixelRect) );
665 858 : if( mbInitClipRegion )
666 858 : InitClipRegion();
667 :
668 858 : pLayout->DrawText( *mpGraphics );
669 :
670 858 : pLayout->Release();
671 858 : Pop();
672 :
673 858 : SetTextColor( aOldColor );
674 1716 : ImplInitTextColor();
675 : }
676 :
677 30130 : void OutputDevice::ImplDrawTextLine( long nX, long nY,
678 : long nDistX, DeviceCoordinate nWidth,
679 : FontStrikeout eStrikeout,
680 : FontUnderline eUnderline,
681 : FontUnderline eOverline,
682 : bool bUnderlineAbove )
683 : {
684 30130 : if ( !nWidth )
685 31050 : return;
686 :
687 29210 : Color aStrikeoutColor = GetTextColor();
688 29210 : Color aUnderlineColor = GetTextLineColor();
689 29210 : Color aOverlineColor = GetOverlineColor();
690 29210 : bool bStrikeoutDone = false;
691 29210 : bool bUnderlineDone = false;
692 29210 : bool bOverlineDone = false;
693 :
694 29210 : if ( IsRTLEnabled() )
695 : {
696 : // --- RTL --- mirror at basex
697 152 : long nXAdd = nWidth - nDistX;
698 152 : if( mpFontEntry->mnOrientation )
699 152 : nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
700 :
701 152 : nX += nXAdd - 1;
702 : }
703 :
704 29210 : if ( !IsTextLineColor() )
705 21364 : aUnderlineColor = GetTextColor();
706 :
707 29210 : if ( !IsOverlineColor() )
708 22304 : aOverlineColor = GetTextColor();
709 :
710 29210 : if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
711 29208 : (eUnderline == UNDERLINE_WAVE) ||
712 29208 : (eUnderline == UNDERLINE_DOUBLEWAVE) ||
713 : (eUnderline == UNDERLINE_BOLDWAVE) )
714 : {
715 1470 : ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
716 1470 : bUnderlineDone = true;
717 : }
718 29210 : if ( (eOverline == UNDERLINE_SMALLWAVE) ||
719 29210 : (eOverline == UNDERLINE_WAVE) ||
720 29210 : (eOverline == UNDERLINE_DOUBLEWAVE) ||
721 : (eOverline == UNDERLINE_BOLDWAVE) )
722 : {
723 0 : ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
724 0 : bOverlineDone = true;
725 : }
726 :
727 29210 : if ( (eStrikeout == STRIKEOUT_SLASH) ||
728 : (eStrikeout == STRIKEOUT_X) )
729 : {
730 938 : ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
731 938 : bStrikeoutDone = true;
732 : }
733 :
734 29210 : if ( !bUnderlineDone )
735 27740 : ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
736 :
737 29210 : if ( !bOverlineDone )
738 29210 : ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
739 :
740 29210 : if ( !bStrikeoutDone )
741 28272 : ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
742 : }
743 :
744 12378 : void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout, FontStrikeout eStrikeout,
745 : FontUnderline eUnderline, FontUnderline eOverline,
746 : bool bWordLine, bool bUnderlineAbove )
747 : {
748 12378 : if( bWordLine )
749 : {
750 : // draw everything relative to the layout base point
751 6231 : const Point aStartPt = rSalLayout.DrawBase();
752 :
753 : // calculate distance of each word from the base point
754 6231 : Point aPos;
755 6231 : DeviceCoordinate nDist = 0;
756 6231 : DeviceCoordinate nWidth = 0;
757 6231 : DeviceCoordinate nAdvance = 0;
758 6231 : for( int nStart = 0;;)
759 : {
760 : // iterate through the layouted glyphs
761 : sal_GlyphId aGlyphId;
762 26300 : if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
763 6231 : break;
764 :
765 : // calculate the boundaries of each word
766 20069 : if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
767 : {
768 19193 : if( !nWidth )
769 : {
770 : // get the distance to the base point (as projected to baseline)
771 5889 : nDist = aPos.X() - aStartPt.X();
772 5889 : if( mpFontEntry->mnOrientation )
773 : {
774 3364 : const long nDY = aPos.Y() - aStartPt.Y();
775 3364 : const double fRad = mpFontEntry->mnOrientation * F_PI1800;
776 3364 : nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
777 : }
778 : }
779 :
780 : // update the length of the textline
781 19193 : nWidth += nAdvance;
782 : }
783 876 : else if( nWidth > 0 )
784 : {
785 : // draw the textline for each word
786 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
787 852 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
788 852 : nWidth = 0;
789 : }
790 20069 : }
791 :
792 : // draw textline for the last word
793 6231 : if( nWidth > 0 )
794 : {
795 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
796 5037 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
797 : }
798 : }
799 : else
800 : {
801 6147 : Point aStartPt = rSalLayout.GetDrawPosition();
802 12294 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0,
803 6147 : rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel(),
804 24588 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
805 : }
806 12378 : }
807 :
808 18094 : void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
809 : {
810 18094 : long nBaseX = nX;
811 18094 : if( /*HasMirroredGraphics() &&*/ IsRTLEnabled() )
812 : {
813 : // --- RTL ---
814 : // add some strange offset
815 0 : nX += 2;
816 : // revert the hack that will be done later in ImplDrawTextLine
817 0 : nX = nBaseX - nWidth - (nX - nBaseX - 1);
818 : }
819 :
820 18094 : ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, false );
821 18094 : }
822 :
823 100299 : void OutputDevice::SetTextLineColor()
824 : {
825 :
826 100299 : if ( mpMetaFile )
827 6631 : mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), false ) );
828 :
829 100299 : maTextLineColor = Color( COL_TRANSPARENT );
830 :
831 100299 : if( mpAlphaVDev )
832 13282 : mpAlphaVDev->SetTextLineColor();
833 100299 : }
834 :
835 29359 : void OutputDevice::SetTextLineColor( const Color& rColor )
836 : {
837 :
838 29359 : Color aColor( rColor );
839 :
840 29359 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
841 : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
842 : DRAWMODE_SETTINGSTEXT ) )
843 : {
844 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
845 : {
846 0 : aColor = Color( COL_BLACK );
847 : }
848 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
849 : {
850 0 : aColor = Color( COL_WHITE );
851 : }
852 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
853 : {
854 0 : const sal_uInt8 cLum = aColor.GetLuminance();
855 0 : aColor = Color( cLum, cLum, cLum );
856 : }
857 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
858 : {
859 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
860 : }
861 :
862 0 : if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT) &&
863 0 : (aColor.GetColor() != COL_TRANSPARENT) )
864 : {
865 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
866 0 : (aColor.GetGreen() >> 1) | 0x80,
867 0 : (aColor.GetBlue() >> 1) | 0x80 );
868 : }
869 : }
870 :
871 29359 : if ( mpMetaFile )
872 12 : mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, true ) );
873 :
874 29359 : maTextLineColor = aColor;
875 :
876 29359 : if( mpAlphaVDev )
877 3528 : mpAlphaVDev->SetTextLineColor( COL_BLACK );
878 29359 : }
879 :
880 99372 : void OutputDevice::SetOverlineColor()
881 : {
882 :
883 99372 : if ( mpMetaFile )
884 6631 : mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), false ) );
885 :
886 99372 : maOverlineColor = Color( COL_TRANSPARENT );
887 :
888 99372 : if( mpAlphaVDev )
889 13282 : mpAlphaVDev->SetOverlineColor();
890 99372 : }
891 :
892 26020 : void OutputDevice::SetOverlineColor( const Color& rColor )
893 : {
894 :
895 26020 : Color aColor( rColor );
896 :
897 26020 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
898 : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
899 : DRAWMODE_SETTINGSTEXT ) )
900 : {
901 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
902 : {
903 0 : aColor = Color( COL_BLACK );
904 : }
905 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
906 : {
907 0 : aColor = Color( COL_WHITE );
908 : }
909 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
910 : {
911 0 : const sal_uInt8 cLum = aColor.GetLuminance();
912 0 : aColor = Color( cLum, cLum, cLum );
913 : }
914 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
915 : {
916 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
917 : }
918 :
919 0 : if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT) &&
920 0 : (aColor.GetColor() != COL_TRANSPARENT) )
921 : {
922 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
923 0 : (aColor.GetGreen() >> 1) | 0x80,
924 0 : (aColor.GetBlue() >> 1) | 0x80 );
925 : }
926 : }
927 :
928 26020 : if ( mpMetaFile )
929 12 : mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, true ) );
930 :
931 26020 : maOverlineColor = aColor;
932 :
933 26020 : if( mpAlphaVDev )
934 3528 : mpAlphaVDev->SetOverlineColor( COL_BLACK );
935 26020 : }
936 :
937 0 : void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
938 : FontStrikeout eStrikeout,
939 : FontUnderline eUnderline,
940 : FontUnderline eOverline,
941 : bool bUnderlineAbove )
942 : {
943 :
944 0 : if ( mpMetaFile )
945 0 : mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
946 :
947 0 : if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
948 0 : ((eOverline == UNDERLINE_NONE) || (eOverline == UNDERLINE_DONTKNOW)) &&
949 0 : ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
950 : {
951 0 : return;
952 : }
953 0 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
954 0 : return;
955 :
956 : // we need a graphics
957 0 : if( !mpGraphics && !AcquireGraphics() )
958 0 : return;
959 :
960 0 : if( mbInitClipRegion )
961 0 : InitClipRegion();
962 :
963 0 : if( mbOutputClipped )
964 0 : return;
965 :
966 : // initialize font if needed to get text offsets
967 : // TODO: only needed for mnTextOff!=(0,0)
968 0 : if( mbNewFont && !ImplNewFont() )
969 0 : return;
970 :
971 0 : if( mbInitFont )
972 0 : InitFont();
973 :
974 0 : Point aPos = ImplLogicToDevicePixel( rPos );
975 : DeviceCoordinate fWidth;
976 0 : fWidth = LogicWidthToDeviceCoordinate( nWidth );
977 0 : aPos += Point( mnTextOffX, mnTextOffY );
978 0 : ImplDrawTextLine( aPos.X(), aPos.X(), 0, fWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
979 :
980 0 : if( mpAlphaVDev )
981 0 : mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
982 : }
983 :
984 94 : void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos )
985 : {
986 :
987 94 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
988 0 : return;
989 :
990 : // we need a graphics
991 94 : if( !mpGraphics && !AcquireGraphics() )
992 0 : return;
993 :
994 94 : if ( mbInitClipRegion )
995 6 : InitClipRegion();
996 :
997 94 : if ( mbOutputClipped )
998 0 : return;
999 :
1000 94 : if( mbNewFont && !ImplNewFont() )
1001 0 : return;
1002 :
1003 94 : Point aStartPt = ImplLogicToDevicePixel( rStartPos );
1004 94 : Point aEndPt = ImplLogicToDevicePixel( rEndPos );
1005 94 : long nStartX = aStartPt.X();
1006 94 : long nStartY = aStartPt.Y();
1007 94 : long nEndX = aEndPt.X();
1008 94 : long nEndY = aEndPt.Y();
1009 94 : short nOrientation = 0;
1010 :
1011 : // when rotated
1012 94 : if ( (nStartY != nEndY) || (nStartX > nEndX) )
1013 : {
1014 0 : long nDX = nEndX - nStartX;
1015 0 : double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
1016 0 : nO /= F_PI1800;
1017 0 : nOrientation = (short)nO;
1018 0 : aStartPt.RotateAround( nEndX, nEndY, -nOrientation );
1019 : }
1020 :
1021 : long nWaveHeight;
1022 :
1023 94 : nWaveHeight = 3;
1024 94 : nStartY++;
1025 94 : nEndY++;
1026 :
1027 94 : if (mnDPIScaleFactor > 1)
1028 : {
1029 0 : nWaveHeight *= mnDPIScaleFactor;
1030 :
1031 0 : nStartY += mnDPIScaleFactor - 1; // Shift down additional pixel(s) to create more visual separation.
1032 :
1033 : // odd heights look better than even
1034 0 : if (mnDPIScaleFactor % 2 == 0)
1035 : {
1036 0 : nWaveHeight--;
1037 : }
1038 : }
1039 :
1040 : // #109280# make sure the waveline does not exceed the descent to avoid paint problems
1041 94 : ImplFontEntry* pFontEntry = mpFontEntry;
1042 94 : if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
1043 : {
1044 2 : nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
1045 : }
1046 : ImplDrawWaveLine(nStartX, nStartY, 0, 0,
1047 : nEndX-nStartX, nWaveHeight,
1048 94 : mnDPIScaleFactor, nOrientation, GetLineColor());
1049 :
1050 94 : if( mpAlphaVDev )
1051 0 : mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos );
1052 1233 : }
1053 :
1054 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|