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 <sal/config.h>
21 #include <sal/log.hxx>
22
23 #include <tools/debug.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/metaact.hxx>
26 #include <vcl/outdevstate.hxx>
27 #include <vcl/virdev.hxx>
28 #include <vcl/settings.hxx>
29
30 #include <outdev.h>
31 #include <salgdi.hxx>
32
OutDevState()33 OutDevState::OutDevState()
34 : mbMapActive(false)
35 , meTextAlign(ALIGN_TOP)
36 , meRasterOp(RasterOp::OverPaint)
37 , mnTextLayoutMode(ComplexTextLayoutFlags::Default)
38 , meTextLanguage(0)
39 , mnFlags(PushFlags::NONE)
40 {
41 }
42
43 OutDevState::OutDevState(OutDevState&&) = default;
44
~OutDevState()45 OutDevState::~OutDevState()
46 {
47 mpLineColor.reset();
48 mpFillColor.reset();
49 mpFont.reset();
50 mpTextColor.reset();
51 mpTextFillColor.reset();
52 mpTextLineColor.reset();
53 mpOverlineColor.reset();
54 mpMapMode.reset();
55 mpClipRegion.reset();
56 mpRefPoint.reset();
57 }
58
Push(PushFlags nFlags)59 void OutputDevice::Push( PushFlags nFlags )
60 {
61
62 if ( mpMetaFile )
63 mpMetaFile->AddAction( new MetaPushAction( nFlags ) );
64
65 maOutDevStateStack.emplace_back();
66 OutDevState& rState = maOutDevStateStack.back();
67
68 rState.mnFlags = nFlags;
69
70 if (nFlags & PushFlags::LINECOLOR && mbLineColor)
71 {
72 rState.mpLineColor = maLineColor;
73 }
74 if (nFlags & PushFlags::FILLCOLOR && mbFillColor)
75 {
76 rState.mpFillColor = maFillColor;
77 }
78 if ( nFlags & PushFlags::FONT )
79 rState.mpFont.reset( new vcl::Font( maFont ) );
80 if ( nFlags & PushFlags::TEXTCOLOR )
81 rState.mpTextColor = GetTextColor();
82 if (nFlags & PushFlags::TEXTFILLCOLOR && IsTextFillColor())
83 {
84 rState.mpTextFillColor = GetTextFillColor();
85 }
86 if (nFlags & PushFlags::TEXTLINECOLOR && IsTextLineColor())
87 {
88 rState.mpTextLineColor = GetTextLineColor();
89 }
90 if (nFlags & PushFlags::OVERLINECOLOR && IsOverlineColor())
91 {
92 rState.mpOverlineColor = GetOverlineColor();
93 }
94 if ( nFlags & PushFlags::TEXTALIGN )
95 rState.meTextAlign = GetTextAlign();
96 if( nFlags & PushFlags::TEXTLAYOUTMODE )
97 rState.mnTextLayoutMode = GetLayoutMode();
98 if( nFlags & PushFlags::TEXTLANGUAGE )
99 rState.meTextLanguage = GetDigitLanguage();
100 if ( nFlags & PushFlags::RASTEROP )
101 rState.meRasterOp = GetRasterOp();
102 if ( nFlags & PushFlags::MAPMODE )
103 {
104 rState.mpMapMode = maMapMode;
105 rState.mbMapActive = mbMap;
106 }
107 if (nFlags & PushFlags::CLIPREGION && mbClipRegion)
108 {
109 rState.mpClipRegion.reset( new vcl::Region( maRegion ) );
110 }
111 if (nFlags & PushFlags::REFPOINT && mbRefPoint)
112 {
113 rState.mpRefPoint = maRefPoint;
114 }
115
116 if( mpAlphaVDev )
117 mpAlphaVDev->Push();
118 }
119
Pop()120 void OutputDevice::Pop()
121 {
122
123 if( mpMetaFile )
124 mpMetaFile->AddAction( new MetaPopAction() );
125
126 GDIMetaFile* pOldMetaFile = mpMetaFile;
127 mpMetaFile = nullptr;
128
129 if ( maOutDevStateStack.empty() )
130 {
131 SAL_WARN( "vcl.gdi", "OutputDevice::Pop() without OutputDevice::Push()" );
132 return;
133 }
134 const OutDevState& rState = maOutDevStateStack.back();
135
136 if( mpAlphaVDev )
137 mpAlphaVDev->Pop();
138
139 if ( rState.mnFlags & PushFlags::LINECOLOR )
140 {
141 if ( rState.mpLineColor )
142 SetLineColor( *rState.mpLineColor );
143 else
144 SetLineColor();
145 }
146
147 if ( rState.mnFlags & PushFlags::FILLCOLOR )
148 {
149 if ( rState.mpFillColor )
150 SetFillColor( *rState.mpFillColor );
151 else
152 SetFillColor();
153 }
154
155 if ( rState.mnFlags & PushFlags::FONT )
156 SetFont( *rState.mpFont );
157
158 if ( rState.mnFlags & PushFlags::TEXTCOLOR )
159 SetTextColor( *rState.mpTextColor );
160
161 if ( rState.mnFlags & PushFlags::TEXTFILLCOLOR )
162 {
163 if ( rState.mpTextFillColor )
164 SetTextFillColor( *rState.mpTextFillColor );
165 else
166 SetTextFillColor();
167 }
168
169 if ( rState.mnFlags & PushFlags::TEXTLINECOLOR )
170 {
171 if ( rState.mpTextLineColor )
172 SetTextLineColor( *rState.mpTextLineColor );
173 else
174 SetTextLineColor();
175 }
176
177 if ( rState.mnFlags & PushFlags::OVERLINECOLOR )
178 {
179 if ( rState.mpOverlineColor )
180 SetOverlineColor( *rState.mpOverlineColor );
181 else
182 SetOverlineColor();
183 }
184
185 if ( rState.mnFlags & PushFlags::TEXTALIGN )
186 SetTextAlign( rState.meTextAlign );
187
188 if( rState.mnFlags & PushFlags::TEXTLAYOUTMODE )
189 SetLayoutMode( rState.mnTextLayoutMode );
190
191 if( rState.mnFlags & PushFlags::TEXTLANGUAGE )
192 SetDigitLanguage( rState.meTextLanguage );
193
194 if ( rState.mnFlags & PushFlags::RASTEROP )
195 SetRasterOp( rState.meRasterOp );
196
197 if ( rState.mnFlags & PushFlags::MAPMODE )
198 {
199 if ( rState.mpMapMode )
200 SetMapMode( *rState.mpMapMode );
201 else
202 SetMapMode();
203 mbMap = rState.mbMapActive;
204 }
205
206 if ( rState.mnFlags & PushFlags::CLIPREGION )
207 SetDeviceClipRegion( rState.mpClipRegion.get() );
208
209 if ( rState.mnFlags & PushFlags::REFPOINT )
210 {
211 if ( rState.mpRefPoint )
212 SetRefPoint( *rState.mpRefPoint );
213 else
214 SetRefPoint();
215 }
216
217 maOutDevStateStack.pop_back();
218
219 mpMetaFile = pOldMetaFile;
220 }
221
GetGCStackDepth() const222 sal_uInt32 OutputDevice::GetGCStackDepth() const
223 {
224 return maOutDevStateStack.size();
225 }
226
ClearStack()227 void OutputDevice::ClearStack()
228 {
229 sal_uInt32 nCount = GetGCStackDepth();
230 while( nCount-- )
231 Pop();
232 }
233
EnableOutput(bool bEnable)234 void OutputDevice::EnableOutput( bool bEnable )
235 {
236 mbOutput = bEnable;
237
238 if( mpAlphaVDev )
239 mpAlphaVDev->EnableOutput( bEnable );
240 }
241
SetAntialiasing(AntialiasingFlags nMode)242 void OutputDevice::SetAntialiasing( AntialiasingFlags nMode )
243 {
244 if ( mnAntialiasing != nMode )
245 {
246 mnAntialiasing = nMode;
247 mbInitFont = true;
248
249 if(mpGraphics)
250 {
251 mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable));
252 }
253 }
254
255 if( mpAlphaVDev )
256 mpAlphaVDev->SetAntialiasing( nMode );
257 }
258
SetDrawMode(DrawModeFlags nDrawMode)259 void OutputDevice::SetDrawMode( DrawModeFlags nDrawMode )
260 {
261
262 mnDrawMode = nDrawMode;
263
264 if( mpAlphaVDev )
265 mpAlphaVDev->SetDrawMode( nDrawMode );
266 }
267
SetLayoutMode(ComplexTextLayoutFlags nTextLayoutMode)268 void OutputDevice::SetLayoutMode( ComplexTextLayoutFlags nTextLayoutMode )
269 {
270 if( mpMetaFile )
271 mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
272
273 mnTextLayoutMode = nTextLayoutMode;
274
275 if( mpAlphaVDev )
276 mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
277 }
278
SetDigitLanguage(LanguageType eTextLanguage)279 void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
280 {
281 if( mpMetaFile )
282 mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
283
284 meTextLanguage = eTextLanguage;
285
286 if( mpAlphaVDev )
287 mpAlphaVDev->SetDigitLanguage( eTextLanguage );
288 }
289
SetRasterOp(RasterOp eRasterOp)290 void OutputDevice::SetRasterOp( RasterOp eRasterOp )
291 {
292
293 if ( mpMetaFile )
294 mpMetaFile->AddAction( new MetaRasterOpAction( eRasterOp ) );
295
296 if ( meRasterOp != eRasterOp )
297 {
298 meRasterOp = eRasterOp;
299 mbInitLineColor = mbInitFillColor = true;
300
301 if( mpGraphics || AcquireGraphics() )
302 {
303 assert(mpGraphics);
304 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp );
305 }
306 }
307
308 if( mpAlphaVDev )
309 mpAlphaVDev->SetRasterOp( eRasterOp );
310 }
311
312
SetFillColor()313 void OutputDevice::SetFillColor()
314 {
315
316 if ( mpMetaFile )
317 mpMetaFile->AddAction( new MetaFillColorAction( Color(), false ) );
318
319 if ( mbFillColor )
320 {
321 mbInitFillColor = true;
322 mbFillColor = false;
323 maFillColor = COL_TRANSPARENT;
324 }
325
326 if( mpAlphaVDev )
327 mpAlphaVDev->SetFillColor();
328 }
329
SetFillColor(const Color & rColor)330 void OutputDevice::SetFillColor( const Color& rColor )
331 {
332
333 Color aColor( rColor );
334
335 if( mnDrawMode & ( DrawModeFlags::BlackFill | DrawModeFlags::WhiteFill |
336 DrawModeFlags::GrayFill | DrawModeFlags::NoFill |
337 DrawModeFlags::SettingsFill ) )
338 {
339 if( !aColor.IsTransparent() )
340 {
341 if( mnDrawMode & DrawModeFlags::BlackFill )
342 {
343 aColor = COL_BLACK;
344 }
345 else if( mnDrawMode & DrawModeFlags::WhiteFill )
346 {
347 aColor = COL_WHITE;
348 }
349 else if( mnDrawMode & DrawModeFlags::GrayFill )
350 {
351 const sal_uInt8 cLum = aColor.GetLuminance();
352 aColor = Color( cLum, cLum, cLum );
353 }
354 else if( mnDrawMode & DrawModeFlags::NoFill )
355 {
356 aColor = COL_TRANSPARENT;
357 }
358 else if( mnDrawMode & DrawModeFlags::SettingsFill )
359 {
360 aColor = GetSettings().GetStyleSettings().GetWindowColor();
361 }
362 }
363 }
364
365 if ( mpMetaFile )
366 mpMetaFile->AddAction( new MetaFillColorAction( aColor, true ) );
367
368 if ( aColor.IsTransparent() )
369 {
370 if ( mbFillColor )
371 {
372 mbInitFillColor = true;
373 mbFillColor = false;
374 maFillColor = COL_TRANSPARENT;
375 }
376 }
377 else
378 {
379 if ( maFillColor != aColor )
380 {
381 mbInitFillColor = true;
382 mbFillColor = true;
383 maFillColor = aColor;
384 }
385 }
386
387 if( mpAlphaVDev )
388 mpAlphaVDev->SetFillColor( COL_BLACK );
389 }
390
SetLineColor()391 void OutputDevice::SetLineColor()
392 {
393
394 if ( mpMetaFile )
395 mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) );
396
397 if ( mbLineColor )
398 {
399 mbInitLineColor = true;
400 mbLineColor = false;
401 maLineColor = COL_TRANSPARENT;
402 }
403
404 if( mpAlphaVDev )
405 mpAlphaVDev->SetLineColor();
406 }
407
SetLineColor(const Color & rColor)408 void OutputDevice::SetLineColor( const Color& rColor )
409 {
410
411 Color aColor = ImplDrawModeToColor( rColor );
412
413 if( mpMetaFile )
414 mpMetaFile->AddAction( new MetaLineColorAction( aColor, true ) );
415
416 if( aColor.IsTransparent() )
417 {
418 if ( mbLineColor )
419 {
420 mbInitLineColor = true;
421 mbLineColor = false;
422 maLineColor = COL_TRANSPARENT;
423 }
424 }
425 else
426 {
427 if( maLineColor != aColor )
428 {
429 mbInitLineColor = true;
430 mbLineColor = true;
431 maLineColor = aColor;
432 }
433 }
434
435 if( mpAlphaVDev )
436 mpAlphaVDev->SetLineColor( COL_BLACK );
437 }
438
SetBackground()439 void OutputDevice::SetBackground()
440 {
441
442 maBackground = Wallpaper();
443 mbBackground = false;
444
445 if( mpAlphaVDev )
446 mpAlphaVDev->SetBackground();
447 }
448
SetBackground(const Wallpaper & rBackground)449 void OutputDevice::SetBackground( const Wallpaper& rBackground )
450 {
451
452 maBackground = rBackground;
453
454 if( rBackground.GetStyle() == WallpaperStyle::NONE )
455 mbBackground = false;
456 else
457 mbBackground = true;
458
459 if( mpAlphaVDev )
460 {
461 // Some of these are probably wrong (e.g. if the gradient has transparency),
462 // but hopefully nobody uses that. If you do, feel free to implement it properly.
463 if( rBackground.GetStyle() == WallpaperStyle::NONE )
464 mpAlphaVDev->SetBackground( rBackground );
465 else if( rBackground.IsBitmap())
466 {
467 BitmapEx bitmap = rBackground.GetBitmap();
468 if( bitmap.IsAlpha())
469 mpAlphaVDev->SetBackground( Wallpaper( BitmapEx( Bitmap( bitmap.GetAlpha()))));
470 else
471 mpAlphaVDev->SetBackground( Wallpaper( COL_BLACK ));
472 }
473 else if( rBackground.IsGradient())
474 mpAlphaVDev->SetBackground( Wallpaper( COL_BLACK ));
475 else
476 {
477 // Color background.
478 int transparency = 255 - rBackground.GetColor().GetAlpha();
479 mpAlphaVDev->SetBackground( Wallpaper( Color( transparency, transparency, transparency )));
480 }
481 }
482 }
483
SetFont(const vcl::Font & rNewFont)484 void OutputDevice::SetFont( const vcl::Font& rNewFont )
485 {
486
487 vcl::Font aFont( rNewFont );
488 if ( mnDrawMode & (DrawModeFlags::BlackText | DrawModeFlags::WhiteText | DrawModeFlags::GrayText | DrawModeFlags::SettingsText |
489 DrawModeFlags::BlackFill | DrawModeFlags::WhiteFill | DrawModeFlags::GrayFill | DrawModeFlags::NoFill |
490 DrawModeFlags::SettingsFill ) )
491 {
492 Color aTextColor( aFont.GetColor() );
493
494 if ( mnDrawMode & DrawModeFlags::BlackText )
495 aTextColor = COL_BLACK;
496 else if ( mnDrawMode & DrawModeFlags::WhiteText )
497 aTextColor = COL_WHITE;
498 else if ( mnDrawMode & DrawModeFlags::GrayText )
499 {
500 const sal_uInt8 cLum = aTextColor.GetLuminance();
501 aTextColor = Color( cLum, cLum, cLum );
502 }
503 else if ( mnDrawMode & DrawModeFlags::SettingsText )
504 aTextColor = GetSettings().GetStyleSettings().GetFontColor();
505
506 aFont.SetColor( aTextColor );
507
508 bool bTransFill = aFont.IsTransparent();
509 if ( !bTransFill )
510 {
511 Color aTextFillColor( aFont.GetFillColor() );
512
513 if ( mnDrawMode & DrawModeFlags::BlackFill )
514 aTextFillColor = COL_BLACK;
515 else if ( mnDrawMode & DrawModeFlags::WhiteFill )
516 aTextFillColor = COL_WHITE;
517 else if ( mnDrawMode & DrawModeFlags::GrayFill )
518 {
519 const sal_uInt8 cLum = aTextFillColor.GetLuminance();
520 aTextFillColor = Color( cLum, cLum, cLum );
521 }
522 else if( mnDrawMode & DrawModeFlags::SettingsFill )
523 aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
524 else if ( mnDrawMode & DrawModeFlags::NoFill )
525 {
526 aTextFillColor = COL_TRANSPARENT;
527 }
528
529 aFont.SetFillColor( aTextFillColor );
530 }
531 }
532
533 if ( mpMetaFile )
534 {
535 mpMetaFile->AddAction( new MetaFontAction( aFont ) );
536 // the color and alignment actions don't belong here
537 // TODO: get rid of them without breaking anything...
538 mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) );
539 mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
540 }
541
542 if ( maFont.IsSameInstance( aFont ) )
543 return;
544
545 // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
546 // because SetTextColor() is used for this.
547 // #i28759# maTextColor might have been changed behind our back, commit then, too.
548 if( aFont.GetColor() != COL_TRANSPARENT
549 && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
550 {
551 maTextColor = aFont.GetColor();
552 mbInitTextColor = true;
553 if( mpMetaFile )
554 mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
555 }
556 maFont = aFont;
557 mbNewFont = true;
558
559 if( !mpAlphaVDev )
560 return;
561
562 // #i30463#
563 // Since SetFont might change the text color, apply that only
564 // selectively to alpha vdev (which normally paints opaque text
565 // with COL_BLACK)
566 if( aFont.GetColor() != COL_TRANSPARENT )
567 {
568 mpAlphaVDev->SetTextColor( COL_BLACK );
569 aFont.SetColor( COL_TRANSPARENT );
570 }
571
572 mpAlphaVDev->SetFont( aFont );
573 }
574
575
InitLineColor()576 void OutputDevice::InitLineColor()
577 {
578 DBG_TESTSOLARMUTEX();
579
580 if( mbLineColor )
581 {
582 if( RasterOp::N0 == meRasterOp )
583 mpGraphics->SetROPLineColor( SalROPColor::N0 );
584 else if( RasterOp::N1 == meRasterOp )
585 mpGraphics->SetROPLineColor( SalROPColor::N1 );
586 else if( RasterOp::Invert == meRasterOp )
587 mpGraphics->SetROPLineColor( SalROPColor::Invert );
588 else
589 mpGraphics->SetLineColor( maLineColor );
590 }
591 else
592 mpGraphics->SetLineColor();
593
594 mbInitLineColor = false;
595 }
596
597
InitFillColor()598 void OutputDevice::InitFillColor()
599 {
600 DBG_TESTSOLARMUTEX();
601
602 if( mbFillColor )
603 {
604 if( RasterOp::N0 == meRasterOp )
605 mpGraphics->SetROPFillColor( SalROPColor::N0 );
606 else if( RasterOp::N1 == meRasterOp )
607 mpGraphics->SetROPFillColor( SalROPColor::N1 );
608 else if( RasterOp::Invert == meRasterOp )
609 mpGraphics->SetROPFillColor( SalROPColor::Invert );
610 else
611 mpGraphics->SetFillColor( maFillColor );
612 }
613 else
614 mpGraphics->SetFillColor();
615
616 mbInitFillColor = false;
617 }
618
ImplReleaseFonts()619 void OutputDevice::ImplReleaseFonts()
620 {
621 mpGraphics->ReleaseFonts();
622
623 mbNewFont = true;
624 mbInitFont = true;
625
626 mpFontInstance.clear();
627 mpDeviceFontList.reset();
628 mpDeviceFontSizeList.reset();
629 }
630
631
632 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
633