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