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