/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include OutDevState::OutDevState() : mbMapActive(false) , meTextAlign(ALIGN_TOP) , meRasterOp(RasterOp::OverPaint) , mnTextLayoutMode(ComplexTextLayoutFlags::Default) , meTextLanguage(0) , mnFlags(PushFlags::NONE) { } OutDevState::OutDevState(OutDevState&&) = default; OutDevState::~OutDevState() { mpLineColor.reset(); mpFillColor.reset(); mpFont.reset(); mpTextColor.reset(); mpTextFillColor.reset(); mpTextLineColor.reset(); mpOverlineColor.reset(); mpMapMode.reset(); mpClipRegion.reset(); mpRefPoint.reset(); } void OutputDevice::Push( PushFlags nFlags ) { if ( mpMetaFile ) mpMetaFile->AddAction( new MetaPushAction( nFlags ) ); maOutDevStateStack.emplace_back(); OutDevState& rState = maOutDevStateStack.back(); rState.mnFlags = nFlags; if (nFlags & PushFlags::LINECOLOR && mbLineColor) { rState.mpLineColor = maLineColor; } if (nFlags & PushFlags::FILLCOLOR && mbFillColor) { rState.mpFillColor = maFillColor; } if ( nFlags & PushFlags::FONT ) rState.mpFont.reset( new vcl::Font( maFont ) ); if ( nFlags & PushFlags::TEXTCOLOR ) rState.mpTextColor = GetTextColor(); if (nFlags & PushFlags::TEXTFILLCOLOR && IsTextFillColor()) { rState.mpTextFillColor = GetTextFillColor(); } if (nFlags & PushFlags::TEXTLINECOLOR && IsTextLineColor()) { rState.mpTextLineColor = GetTextLineColor(); } if (nFlags & PushFlags::OVERLINECOLOR && IsOverlineColor()) { rState.mpOverlineColor = GetOverlineColor(); } if ( nFlags & PushFlags::TEXTALIGN ) rState.meTextAlign = GetTextAlign(); if( nFlags & PushFlags::TEXTLAYOUTMODE ) rState.mnTextLayoutMode = GetLayoutMode(); if( nFlags & PushFlags::TEXTLANGUAGE ) rState.meTextLanguage = GetDigitLanguage(); if ( nFlags & PushFlags::RASTEROP ) rState.meRasterOp = GetRasterOp(); if ( nFlags & PushFlags::MAPMODE ) { rState.mpMapMode = maMapMode; rState.mbMapActive = mbMap; } if (nFlags & PushFlags::CLIPREGION && mbClipRegion) { rState.mpClipRegion.reset( new vcl::Region( maRegion ) ); } if (nFlags & PushFlags::REFPOINT && mbRefPoint) { rState.mpRefPoint = maRefPoint; } if( mpAlphaVDev ) mpAlphaVDev->Push(); } void OutputDevice::Pop() { if( mpMetaFile ) mpMetaFile->AddAction( new MetaPopAction() ); GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = nullptr; if ( maOutDevStateStack.empty() ) { SAL_WARN( "vcl.gdi", "OutputDevice::Pop() without OutputDevice::Push()" ); return; } const OutDevState& rState = maOutDevStateStack.back(); if( mpAlphaVDev ) mpAlphaVDev->Pop(); if ( rState.mnFlags & PushFlags::LINECOLOR ) { if ( rState.mpLineColor ) SetLineColor( *rState.mpLineColor ); else SetLineColor(); } if ( rState.mnFlags & PushFlags::FILLCOLOR ) { if ( rState.mpFillColor ) SetFillColor( *rState.mpFillColor ); else SetFillColor(); } if ( rState.mnFlags & PushFlags::FONT ) SetFont( *rState.mpFont ); if ( rState.mnFlags & PushFlags::TEXTCOLOR ) SetTextColor( *rState.mpTextColor ); if ( rState.mnFlags & PushFlags::TEXTFILLCOLOR ) { if ( rState.mpTextFillColor ) SetTextFillColor( *rState.mpTextFillColor ); else SetTextFillColor(); } if ( rState.mnFlags & PushFlags::TEXTLINECOLOR ) { if ( rState.mpTextLineColor ) SetTextLineColor( *rState.mpTextLineColor ); else SetTextLineColor(); } if ( rState.mnFlags & PushFlags::OVERLINECOLOR ) { if ( rState.mpOverlineColor ) SetOverlineColor( *rState.mpOverlineColor ); else SetOverlineColor(); } if ( rState.mnFlags & PushFlags::TEXTALIGN ) SetTextAlign( rState.meTextAlign ); if( rState.mnFlags & PushFlags::TEXTLAYOUTMODE ) SetLayoutMode( rState.mnTextLayoutMode ); if( rState.mnFlags & PushFlags::TEXTLANGUAGE ) SetDigitLanguage( rState.meTextLanguage ); if ( rState.mnFlags & PushFlags::RASTEROP ) SetRasterOp( rState.meRasterOp ); if ( rState.mnFlags & PushFlags::MAPMODE ) { if ( rState.mpMapMode ) SetMapMode( *rState.mpMapMode ); else SetMapMode(); mbMap = rState.mbMapActive; } if ( rState.mnFlags & PushFlags::CLIPREGION ) SetDeviceClipRegion( rState.mpClipRegion.get() ); if ( rState.mnFlags & PushFlags::REFPOINT ) { if ( rState.mpRefPoint ) SetRefPoint( *rState.mpRefPoint ); else SetRefPoint(); } maOutDevStateStack.pop_back(); mpMetaFile = pOldMetaFile; } sal_uInt32 OutputDevice::GetGCStackDepth() const { return maOutDevStateStack.size(); } void OutputDevice::ClearStack() { sal_uInt32 nCount = GetGCStackDepth(); while( nCount-- ) Pop(); } void OutputDevice::EnableOutput( bool bEnable ) { mbOutput = bEnable; if( mpAlphaVDev ) mpAlphaVDev->EnableOutput( bEnable ); } void OutputDevice::SetAntialiasing( AntialiasingFlags nMode ) { if ( mnAntialiasing != nMode ) { mnAntialiasing = nMode; mbInitFont = true; if(mpGraphics) { mpGraphics->setAntiAliasB2DDraw(bool(mnAntialiasing & AntialiasingFlags::EnableB2dDraw)); } } if( mpAlphaVDev ) mpAlphaVDev->SetAntialiasing( nMode ); } void OutputDevice::SetDrawMode( DrawModeFlags nDrawMode ) { mnDrawMode = nDrawMode; if( mpAlphaVDev ) mpAlphaVDev->SetDrawMode( nDrawMode ); } void OutputDevice::SetLayoutMode( ComplexTextLayoutFlags nTextLayoutMode ) { if( mpMetaFile ) mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) ); mnTextLayoutMode = nTextLayoutMode; if( mpAlphaVDev ) mpAlphaVDev->SetLayoutMode( nTextLayoutMode ); } void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage ) { if( mpMetaFile ) mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) ); meTextLanguage = eTextLanguage; if( mpAlphaVDev ) mpAlphaVDev->SetDigitLanguage( eTextLanguage ); } void OutputDevice::SetRasterOp( RasterOp eRasterOp ) { if ( mpMetaFile ) mpMetaFile->AddAction( new MetaRasterOpAction( eRasterOp ) ); if ( meRasterOp != eRasterOp ) { meRasterOp = eRasterOp; mbInitLineColor = mbInitFillColor = true; if( mpGraphics || AcquireGraphics() ) mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp ); } if( mpAlphaVDev ) mpAlphaVDev->SetRasterOp( eRasterOp ); } void OutputDevice::SetFillColor() { if ( mpMetaFile ) mpMetaFile->AddAction( new MetaFillColorAction( Color(), false ) ); if ( mbFillColor ) { mbInitFillColor = true; mbFillColor = false; maFillColor = COL_TRANSPARENT; } if( mpAlphaVDev ) mpAlphaVDev->SetFillColor(); } void OutputDevice::SetFillColor( const Color& rColor ) { Color aColor( rColor ); if( mnDrawMode & ( DrawModeFlags::BlackFill | DrawModeFlags::WhiteFill | DrawModeFlags::GrayFill | DrawModeFlags::NoFill | DrawModeFlags::SettingsFill ) ) { if( !ImplIsColorTransparent( aColor ) ) { if( mnDrawMode & DrawModeFlags::BlackFill ) { aColor = COL_BLACK; } else if( mnDrawMode & DrawModeFlags::WhiteFill ) { aColor = COL_WHITE; } else if( mnDrawMode & DrawModeFlags::GrayFill ) { const sal_uInt8 cLum = aColor.GetLuminance(); aColor = Color( cLum, cLum, cLum ); } else if( mnDrawMode & DrawModeFlags::NoFill ) { aColor = COL_TRANSPARENT; } else if( mnDrawMode & DrawModeFlags::SettingsFill ) { aColor = GetSettings().GetStyleSettings().GetWindowColor(); } } } if ( mpMetaFile ) mpMetaFile->AddAction( new MetaFillColorAction( aColor, true ) ); if ( ImplIsColorTransparent( aColor ) ) { if ( mbFillColor ) { mbInitFillColor = true; mbFillColor = false; maFillColor = COL_TRANSPARENT; } } else { if ( maFillColor != aColor ) { mbInitFillColor = true; mbFillColor = true; maFillColor = aColor; } } if( mpAlphaVDev ) mpAlphaVDev->SetFillColor( COL_BLACK ); } void OutputDevice::SetLineColor() { if ( mpMetaFile ) mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) ); if ( mbLineColor ) { mbInitLineColor = true; mbLineColor = false; maLineColor = COL_TRANSPARENT; } if( mpAlphaVDev ) mpAlphaVDev->SetLineColor(); } void OutputDevice::SetLineColor( const Color& rColor ) { Color aColor = ImplDrawModeToColor( rColor ); if( mpMetaFile ) mpMetaFile->AddAction( new MetaLineColorAction( aColor, true ) ); if( ImplIsColorTransparent( aColor ) ) { if ( mbLineColor ) { mbInitLineColor = true; mbLineColor = false; maLineColor = COL_TRANSPARENT; } } else { if( maLineColor != aColor ) { mbInitLineColor = true; mbLineColor = true; maLineColor = aColor; } } if( mpAlphaVDev ) mpAlphaVDev->SetLineColor( COL_BLACK ); } void OutputDevice::SetBackground() { maBackground = Wallpaper(); mbBackground = false; if( mpAlphaVDev ) mpAlphaVDev->SetBackground(); } void OutputDevice::SetBackground( const Wallpaper& rBackground ) { maBackground = rBackground; if( rBackground.GetStyle() == WallpaperStyle::NONE ) mbBackground = false; else mbBackground = true; if( mpAlphaVDev ) { // Some of these are probably wrong (e.g. if the gradient has transparency), // but hopefully nobody uses that. If you do, feel free to implement it properly. if( rBackground.GetStyle() == WallpaperStyle::NONE ) mpAlphaVDev->SetBackground( rBackground ); else if( rBackground.IsBitmap()) { BitmapEx bitmap = rBackground.GetBitmap(); if( bitmap.IsAlpha()) mpAlphaVDev->SetBackground( Wallpaper( BitmapEx( Bitmap( bitmap.GetAlpha())))); else { switch( bitmap.GetTransparentType()) { case TransparentType::NONE: mpAlphaVDev->SetBackground( Wallpaper( COL_BLACK )); break; case TransparentType::Color: { AlphaMask mask( bitmap.GetBitmap().CreateMask( bitmap.GetTransparentColor())); mpAlphaVDev->SetBackground( Wallpaper( BitmapEx( bitmap.GetBitmap(), mask ))); break; } case TransparentType::Bitmap: mpAlphaVDev->SetBackground( Wallpaper( BitmapEx( bitmap.GetMask()))); break; } } } else if( rBackground.IsGradient()) mpAlphaVDev->SetBackground( Wallpaper( COL_BLACK )); else { // Color background. int transparency = rBackground.GetColor().GetTransparency(); mpAlphaVDev->SetBackground( Wallpaper( Color( transparency, transparency, transparency ))); } } } void OutputDevice::SetFont( const vcl::Font& rNewFont ) { vcl::Font aFont( rNewFont ); if ( mnDrawMode & (DrawModeFlags::BlackText | DrawModeFlags::WhiteText | DrawModeFlags::GrayText | DrawModeFlags::SettingsText | DrawModeFlags::BlackFill | DrawModeFlags::WhiteFill | DrawModeFlags::GrayFill | DrawModeFlags::NoFill | DrawModeFlags::SettingsFill ) ) { Color aTextColor( aFont.GetColor() ); if ( mnDrawMode & DrawModeFlags::BlackText ) aTextColor = COL_BLACK; else if ( mnDrawMode & DrawModeFlags::WhiteText ) aTextColor = COL_WHITE; else if ( mnDrawMode & DrawModeFlags::GrayText ) { const sal_uInt8 cLum = aTextColor.GetLuminance(); aTextColor = Color( cLum, cLum, cLum ); } else if ( mnDrawMode & DrawModeFlags::SettingsText ) aTextColor = GetSettings().GetStyleSettings().GetFontColor(); aFont.SetColor( aTextColor ); bool bTransFill = aFont.IsTransparent(); if ( !bTransFill ) { Color aTextFillColor( aFont.GetFillColor() ); if ( mnDrawMode & DrawModeFlags::BlackFill ) aTextFillColor = COL_BLACK; else if ( mnDrawMode & DrawModeFlags::WhiteFill ) aTextFillColor = COL_WHITE; else if ( mnDrawMode & DrawModeFlags::GrayFill ) { const sal_uInt8 cLum = aTextFillColor.GetLuminance(); aTextFillColor = Color( cLum, cLum, cLum ); } else if( mnDrawMode & DrawModeFlags::SettingsFill ) aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor(); else if ( mnDrawMode & DrawModeFlags::NoFill ) { aTextFillColor = COL_TRANSPARENT; } aFont.SetFillColor( aTextFillColor ); } } if ( mpMetaFile ) { mpMetaFile->AddAction( new MetaFontAction( aFont ) ); // the color and alignment actions don't belong here // TODO: get rid of them without breaking anything... mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) ); mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) ); } if ( maFont.IsSameInstance( aFont ) ) return; // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color, // because SetTextColor() is used for this. // #i28759# maTextColor might have been changed behind our back, commit then, too. if( aFont.GetColor() != COL_TRANSPARENT && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) ) { maTextColor = aFont.GetColor(); mbInitTextColor = true; if( mpMetaFile ) mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) ); } maFont = aFont; mbNewFont = true; if( !mpAlphaVDev ) return; // #i30463# // Since SetFont might change the text color, apply that only // selectively to alpha vdev (which normally paints opaque text // with COL_BLACK) if( aFont.GetColor() != COL_TRANSPARENT ) { mpAlphaVDev->SetTextColor( COL_BLACK ); aFont.SetColor( COL_TRANSPARENT ); } mpAlphaVDev->SetFont( aFont ); } void OutputDevice::InitLineColor() { DBG_TESTSOLARMUTEX(); if( mbLineColor ) { if( RasterOp::N0 == meRasterOp ) mpGraphics->SetROPLineColor( SalROPColor::N0 ); else if( RasterOp::N1 == meRasterOp ) mpGraphics->SetROPLineColor( SalROPColor::N1 ); else if( RasterOp::Invert == meRasterOp ) mpGraphics->SetROPLineColor( SalROPColor::Invert ); else mpGraphics->SetLineColor( maLineColor ); } else mpGraphics->SetLineColor(); mbInitLineColor = false; } void OutputDevice::InitFillColor() { DBG_TESTSOLARMUTEX(); if( mbFillColor ) { if( RasterOp::N0 == meRasterOp ) mpGraphics->SetROPFillColor( SalROPColor::N0 ); else if( RasterOp::N1 == meRasterOp ) mpGraphics->SetROPFillColor( SalROPColor::N1 ); else if( RasterOp::Invert == meRasterOp ) mpGraphics->SetROPFillColor( SalROPColor::Invert ); else mpGraphics->SetFillColor( maFillColor ); } else mpGraphics->SetFillColor(); mbInitFillColor = false; } void OutputDevice::ImplReleaseFonts() { mpGraphics->ReleaseFonts(); mbNewFont = true; mbInitFont = true; mpFontInstance.clear(); mpDeviceFontList.reset(); mpDeviceFontSizeList.reset(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */