diff options
author | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-15 01:06:48 +1000 |
---|---|---|
committer | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-16 07:33:58 +1000 |
commit | aa5b97fa3d8970813c3fd7c9fc88cd38db80482e (patch) | |
tree | 8879d79e105e6e71230feba9bc850331ab53744a | |
parent | d92ee5d8bebdd6f120c7478127a1be5f78d4b1af (diff) |
Split outdev5.cxx and outdev6.cxx
outdev5.cxx deals with curved shapes, so renamed to curvedshapes.cxx
Moved polygon functions to polygon.cxx, transparency functions to
transparent.cxx, a few miscellaneous functions to outdev.cxx and as the
rest of the functions are wallpaper functions then renamed outdev6.cxx
to wallpaper.cxx
Change-Id: I62a0b66d4d66740fb5f70ecb558db1ad3bf76eb5
-rw-r--r-- | vcl/Library_vcl.mk | 6 | ||||
-rw-r--r-- | vcl/source/outdev/curvedshapes.cxx (renamed from vcl/source/outdev/outdev5.cxx) | 0 | ||||
-rw-r--r-- | vcl/source/outdev/outdev.cxx | 118 | ||||
-rw-r--r-- | vcl/source/outdev/outdev6.cxx | 1196 | ||||
-rw-r--r-- | vcl/source/outdev/polygon.cxx | 94 | ||||
-rw-r--r-- | vcl/source/outdev/transparent.cxx | 603 | ||||
-rw-r--r-- | vcl/source/outdev/wallpaper.cxx | 384 |
7 files changed, 1202 insertions, 1199 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index b1fd7e8d52fe..6851f0cc8b65 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -234,6 +234,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/gdi/metric \ vcl/source/gdi/octree \ vcl/source/gdi/oldprintadaptor \ + vcl/source/outdev/outdev \ vcl/source/outdev/tworect \ vcl/source/outdev/bezier \ vcl/source/outdev/polygon \ @@ -250,9 +251,8 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/outdev/polyline \ vcl/source/outdev/hatch \ vcl/source/outdev/gradient \ - vcl/source/outdev/outdev5 \ - vcl/source/outdev/outdev6 \ - vcl/source/outdev/outdev \ + vcl/source/outdev/curvedshapes \ + vcl/source/outdev/wallpaper \ vcl/source/outdev/outdevnative \ vcl/source/outdev/outmap \ vcl/source/gdi/pdfextoutdevdata \ diff --git a/vcl/source/outdev/outdev5.cxx b/vcl/source/outdev/curvedshapes.cxx index 7fe7e684db58..7fe7e684db58 100644 --- a/vcl/source/outdev/outdev5.cxx +++ b/vcl/source/outdev/curvedshapes.cxx diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx index 25d8992e3927..cba75421b4e4 100644 --- a/vcl/source/outdev/outdev.cxx +++ b/vcl/source/outdev/outdev.cxx @@ -1576,4 +1576,122 @@ css::uno::Reference< css::rendering::XCanvas > OutputDevice::GetCanvas() const return xCanvas; } +void OutputDevice::Erase() +{ + if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) + return; + + bool bNativeOK = false; + + if( meOutDevType == OUTDEV_WINDOW ) + { + Window* pWindow = static_cast<Window*>(this); + ControlPart aCtrlPart = pWindow->ImplGetWindowImpl()->mnNativeBackground; + if( aCtrlPart != 0 && ! pWindow->IsControlBackground() ) + { + ImplControlValue aControlValue; + Point aGcc3WorkaroundTemporary; + Rectangle aCtrlRegion( aGcc3WorkaroundTemporary, GetOutputSizePixel() ); + ControlState nState = 0; + + if( pWindow->IsEnabled() ) nState |= CTRL_STATE_ENABLED; + bNativeOK = pWindow->DrawNativeControl( CTRL_WINDOW_BACKGROUND, aCtrlPart, aCtrlRegion, + nState, aControlValue, OUString() ); + } + } + + if ( mbBackground && ! bNativeOK ) + { + RasterOp eRasterOp = GetRasterOp(); + if ( eRasterOp != ROP_OVERPAINT ) + SetRasterOp( ROP_OVERPAINT ); + ImplDrawWallpaper( 0, 0, mnOutWidth, mnOutHeight, maBackground ); + if ( eRasterOp != ROP_OVERPAINT ) + SetRasterOp( eRasterOp ); + } + + if( mpAlphaVDev ) + mpAlphaVDev->Erase(); +} + +bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, + const GfxLink& rGfxLink, GDIMetaFile* pSubst ) +{ + bool bDrawn(true); + + if ( mpMetaFile ) + { + GDIMetaFile aSubst; + + if( pSubst ) + aSubst = *pSubst; + + mpMetaFile->AddAction( new MetaEPSAction( rPoint, rSize, rGfxLink, aSubst ) ); + } + + if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) + return bDrawn; + + if( mbOutputClipped ) + return bDrawn; + + Rectangle aRect( ImplLogicToDevicePixel( Rectangle( rPoint, rSize ) ) ); + + if( !aRect.IsEmpty() ) + { + // draw the real EPS graphics + if( rGfxLink.GetData() && rGfxLink.GetDataSize() ) + { + if( !mpGraphics && !ImplGetGraphics() ) + return bDrawn; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + + aRect.Justify(); + bDrawn = mpGraphics->DrawEPS( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), + (sal_uInt8*) rGfxLink.GetData(), rGfxLink.GetDataSize(), this ); + } + + // else draw the substitution graphics + if( !bDrawn && pSubst ) + { + GDIMetaFile* pOldMetaFile = mpMetaFile; + + mpMetaFile = NULL; + Graphic( *pSubst ).Draw( this, rPoint, rSize ); + mpMetaFile = pOldMetaFile; + } + } + + if( mpAlphaVDev ) + mpAlphaVDev->DrawEPS( rPoint, rSize, rGfxLink, pSubst ); + + return bDrawn; +} + +void OutputDevice::DrawCheckered(const Point& rPos, const Size& rSize, sal_uInt32 nLen, Color aStart, Color aEnd) +{ + const sal_uInt32 nMaxX(rPos.X() + rSize.Width()); + const sal_uInt32 nMaxY(rPos.Y() + rSize.Height()); + + Push(PUSH_LINECOLOR|PUSH_FILLCOLOR); + SetLineColor(); + + for(sal_uInt32 x(0), nX(rPos.X()); nX < nMaxX; x++, nX += nLen) + { + const sal_uInt32 nRight(std::min(nMaxX, nX + nLen)); + + for(sal_uInt32 y(0), nY(rPos.Y()); nY < nMaxY; y++, nY += nLen) + { + const sal_uInt32 nBottom(std::min(nMaxY, nY + nLen)); + + SetFillColor((x & 0x0001) ^ (y & 0x0001) ? aStart : aEnd); + DrawRect(Rectangle(nX, nY, nRight, nBottom)); + } + } + + Pop(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/outdev6.cxx b/vcl/source/outdev/outdev6.cxx deleted file mode 100644 index b4de152f6ad4..000000000000 --- a/vcl/source/outdev/outdev6.cxx +++ /dev/null @@ -1,1196 +0,0 @@ -/* -*- 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 <tools/debug.hxx> -#include <vcl/outdev.hxx> -#include <vcl/virdev.hxx> -#include <vcl/bmpacc.hxx> -#include <vcl/metaact.hxx> -#include <vcl/gdimtf.hxx> -#include <vcl/svapp.hxx> -#include <vcl/wrkwin.hxx> -#include <vcl/graph.hxx> - -#include <wall2.hxx> -#include <salgdi.hxx> -#include <window.h> -#include <svdata.hxx> -#include <outdev.h> - -#include <com/sun/star/uno/Sequence.hxx> - -#include <basegfx/vector/b2dvector.hxx> -#include <basegfx/polygon/b2dpolypolygon.hxx> -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/matrix/b2dhommatrix.hxx> - -#include <math.h> -#include <boost/scoped_ptr.hpp> - -namespace { - -/** - * Perform a safe approximation of a polygon from double-precision - * coordinates to integer coordinates, to ensure that it has at least 2 - * pixels in both X and Y directions. - */ -Polygon toPolygon( const basegfx::B2DPolygon& rPoly ) -{ - basegfx::B2DRange aRange = rPoly.getB2DRange(); - double fW = aRange.getWidth(), fH = aRange.getHeight(); - if (0.0 < fW && 0.0 < fH && (fW <= 1.0 || fH <= 1.0)) - { - // This polygon not empty but is too small to display. Approximate it - // with a rectangle large enough to be displayed. - double nX = aRange.getMinX(), nY = aRange.getMinY(); - double nW = std::max<double>(1.0, rtl::math::round(fW)); - double nH = std::max<double>(1.0, rtl::math::round(fH)); - - Polygon aTarget; - aTarget.Insert(0, Point(nX, nY)); - aTarget.Insert(1, Point(nX+nW, nY)); - aTarget.Insert(2, Point(nX+nW, nY+nH)); - aTarget.Insert(3, Point(nX, nY+nH)); - aTarget.Insert(4, Point(nX, nY)); - return aTarget; - } - return Polygon(rPoly); -} - -PolyPolygon toPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly ) -{ - PolyPolygon aTarget; - for (sal_uInt32 i = 0; i < rPolyPoly.count(); ++i) - aTarget.Insert(toPolygon(rPolyPoly.getB2DPolygon(i))); - - return aTarget; -} - -} - -void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLong nFlags ) -{ - - Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() ); - aDstRect.Intersection( rRect ); - - if( aDstRect.IsEmpty() || ImplIsRecordLayout() ) - return; - - if( !mpGraphics && !ImplGetGraphics() ) - return; - - if( mbInitClipRegion ) - ImplInitClipRegion(); - - if( mbOutputClipped ) - return; - - const long nDistX = std::max( rDist.Width(), 1L ); - const long nDistY = std::max( rDist.Height(), 1L ); - long nX = ( rRect.Left() >= aDstRect.Left() ) ? rRect.Left() : ( rRect.Left() + ( ( aDstRect.Left() - rRect.Left() ) / nDistX ) * nDistX ); - long nY = ( rRect.Top() >= aDstRect.Top() ) ? rRect.Top() : ( rRect.Top() + ( ( aDstRect.Top() - rRect.Top() ) / nDistY ) * nDistY ); - const long nRight = aDstRect.Right(); - const long nBottom = aDstRect.Bottom(); - const long nStartX = ImplLogicXToDevicePixel( nX ); - const long nEndX = ImplLogicXToDevicePixel( nRight ); - const long nStartY = ImplLogicYToDevicePixel( nY ); - const long nEndY = ImplLogicYToDevicePixel( nBottom ); - long nHorzCount = 0L; - long nVertCount = 0L; - - ::com::sun::star::uno::Sequence< sal_Int32 > aVertBuf; - ::com::sun::star::uno::Sequence< sal_Int32 > aHorzBuf; - - if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_HORZLINES ) ) - { - aVertBuf.realloc( aDstRect.GetHeight() / nDistY + 2L ); - aVertBuf[ nVertCount++ ] = nStartY; - while( ( nY += nDistY ) <= nBottom ) - aVertBuf[ nVertCount++ ] = ImplLogicYToDevicePixel( nY ); - } - - if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_VERTLINES ) ) - { - aHorzBuf.realloc( aDstRect.GetWidth() / nDistX + 2L ); - aHorzBuf[ nHorzCount++ ] = nStartX; - while( ( nX += nDistX ) <= nRight ) - aHorzBuf[ nHorzCount++ ] = ImplLogicXToDevicePixel( nX ); - } - - if( mbInitLineColor ) - ImplInitLineColor(); - - if( mbInitFillColor ) - ImplInitFillColor(); - - const bool bOldMap = mbMap; - EnableMapMode( false ); - - if( nFlags & GRID_DOTS ) - { - for( long i = 0L; i < nVertCount; i++ ) - for( long j = 0L, Y = aVertBuf[ i ]; j < nHorzCount; j++ ) - mpGraphics->DrawPixel( aHorzBuf[ j ], Y, this ); - } - else - { - if( nFlags & GRID_HORZLINES ) - { - for( long i = 0L; i < nVertCount; i++ ) - { - nY = aVertBuf[ i ]; - mpGraphics->DrawLine( nStartX, nY, nEndX, nY, this ); - } - } - - if( nFlags & GRID_VERTLINES ) - { - for( long i = 0L; i < nHorzCount; i++ ) - { - nX = aHorzBuf[ i ]; - mpGraphics->DrawLine( nX, nStartY, nX, nEndY, this ); - } - } - } - - EnableMapMode( bOldMap ); - - if( mpAlphaVDev ) - mpAlphaVDev->DrawGrid( rRect, rDist, nFlags ); -} - -// Caution: This method is nearly the same as -// void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly ) -// so when changes are made here do not forget to make changes there, too - -void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency) -{ - // AW: Do NOT paint empty PolyPolygons - if(!rB2DPolyPoly.count()) - return; - - // we need a graphics - if( !mpGraphics ) - if( !ImplGetGraphics() ) - return; - - if( mbInitClipRegion ) - ImplInitClipRegion(); - if( mbOutputClipped ) - return; - - if( mbInitLineColor ) - ImplInitLineColor(); - if( mbInitFillColor ) - ImplInitFillColor(); - - if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) - && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) - && ROP_OVERPAINT == GetRasterOp() ) - { - // b2dpolygon support not implemented yet on non-UNX platforms - const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); - basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly); - - // transform the polygon into device space and ensure it is closed - aB2DPolyPolygon.transform( aTransform ); - aB2DPolyPolygon.setClosed( true ); - - bool bDrawnOk = true; - if( IsFillColor() ) - bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this ); - if( bDrawnOk && IsLineColor() ) - { - const basegfx::B2DVector aHairlineWidth(1,1); - const int nPolyCount = aB2DPolyPolygon.count(); - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); - mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this ); - } - } - - if( bDrawnOk ) - { - if( mpMetaFile ) - mpMetaFile->AddAction( new MetaTransparentAction( PolyPolygon( rB2DPolyPoly ), static_cast< sal_uInt16 >(fTransparency * 100.0))); - return; - } - } - - // fallback to old polygon drawing if needed - DrawTransparent(toPolyPolygon(rB2DPolyPoly), static_cast<sal_uInt16>(fTransparency * 100.0)); -} - -void OutputDevice::DrawInvisiblePolygon( const PolyPolygon& rPolyPoly ) -{ - // short circuit if the polygon border is invisible too - if( !mbLineColor ) - return; - - // we assume that the border is NOT to be drawn transparently??? - Push( PUSH_FILLCOLOR ); - SetFillColor(); - DrawPolyPolygon( rPolyPoly ); - Pop(); -} - -bool OutputDevice::DrawTransparentNatively ( const PolyPolygon& rPolyPoly, - sal_uInt16 nTransparencePercent ) -{ - bool bDrawn = false; - - // debug helper: - static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA"); - - if( !pDisableNative - && mpGraphics->supportsOperation( OutDevSupport_B2DDraw ) -#if defined UNX && ! defined MACOSX && ! defined IOS - && GetBitCount() > 8 -#endif -#ifdef WIN32 - // workaround bad dithering on remote displaying when using GDI+ with toolbar button highlighting - && !rPolyPoly.IsRect() -#endif - ) - { - // prepare the graphics device - if( mbInitClipRegion ) - ImplInitClipRegion(); - if( mbOutputClipped ) - return false; - if( mbInitLineColor ) - ImplInitLineColor(); - if( mbInitFillColor ) - ImplInitFillColor(); - - // get the polygon in device coordinates - basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() ); - const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); - aB2DPolyPolygon.transform( aTransform ); - - const double fTransparency = 0.01 * nTransparencePercent; - if( mbFillColor ) - { - // #i121591# - // CAUTION: Only non printing (pixel-renderer) VCL commands from OutputDevices - // should be used when printing. Normally this is avoided by the printer being - // non-AAed and thus e.g. on WIN GdiPlus calls are not used. It may be necessary - // to figure out a way of moving this code to it's own function that is - // overriden by the Print class, which will mean we deliberately override the - // functionality and we use the fallback some lines below (which is not very good, - // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and - // correct the wrong mapping (see there for details) - bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this ); - } - - if( mbLineColor ) - { - // disable the fill color for now - mpGraphics->SetFillColor(); - // draw the border line - const basegfx::B2DVector aLineWidths( 1, 1 ); - const int nPolyCount = aB2DPolyPolygon.count(); - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); - bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this ); - } - // prepare to restore the fill color - mbInitFillColor = mbFillColor; - } - } - - return bDrawn; -} - -void OutputDevice::EmulateDrawTransparent ( const PolyPolygon& rPolyPoly, - sal_uInt16 nTransparencePercent ) -{ - // debug helper: - static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA"); - - // #110958# Disable alpha VDev, we perform the necessary - VirtualDevice* pOldAlphaVDev = mpAlphaVDev; - - // operation explicitly further below. - if( mpAlphaVDev ) - mpAlphaVDev = NULL; - - GDIMetaFile* pOldMetaFile = mpMetaFile; - mpMetaFile = NULL; - - PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); - Rectangle aPolyRect( aPolyPoly.GetBoundRect() ); - Point aPoint; - Rectangle aDstRect( aPoint, GetOutputSizePixel() ); - - aDstRect.Intersection( aPolyRect ); - - ClipToPaintRegion( aDstRect ); - - if( !aDstRect.IsEmpty() ) - { - bool bDrawn = false; - - // #i66849# Added fast path for exactly rectangular - // polygons - // #i83087# Naturally, system alpha blending cannot - // work with separate alpha VDev - if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() ) - { - // setup Graphics only here (other cases delegate - // to basic OutDev methods) - if ( mbInitClipRegion ) - ImplInitClipRegion(); - if ( mbInitLineColor ) - ImplInitLineColor(); - if ( mbInitFillColor ) - ImplInitFillColor(); - - Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() ); - Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) ); - - if( !mbOutputClipped ) - { - bDrawn = mpGraphics->DrawAlphaRect( - aPixelRect.Left(), aPixelRect.Top(), - // #i98405# use methods with small g, else one pixel too much will be painted. - // This is because the source is a polygon which when painted would not paint - // the rightmost and lowest pixel line(s), so use one pixel less for the - // rectangle, too. - aPixelRect.getWidth(), aPixelRect.getHeight(), - sal::static_int_cast<sal_uInt8>(nTransparencePercent), - this ); - } - else - bDrawn = true; - } - - if( !bDrawn ) - { - VirtualDevice aVDev( *this, 1 ); - const Size aDstSz( aDstRect.GetSize() ); - const sal_uInt8 cTrans = (sal_uInt8) MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 ); - - if( aDstRect.Left() || aDstRect.Top() ) - aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() ); - - if( aVDev.SetOutputSizePixel( aDstSz ) ) - { - const bool bOldMap = mbMap; - - EnableMapMode( false ); - - aVDev.SetLineColor( COL_BLACK ); - aVDev.SetFillColor( COL_BLACK ); - aVDev.DrawPolyPolygon( aPolyPoly ); - - Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) ); - Bitmap aPolyMask( aVDev.GetBitmap( Point(), aDstSz ) ); - - // #107766# check for non-empty bitmaps before accessing them - if( !!aPaint && !!aPolyMask ) - { - BitmapWriteAccess* pW = aPaint.AcquireWriteAccess(); - BitmapReadAccess* pR = aPolyMask.AcquireReadAccess(); - - if( pW && pR ) - { - BitmapColor aPixCol; - const BitmapColor aFillCol( GetFillColor() ); - const BitmapColor aWhite( pR->GetBestMatchingColor( Color( COL_WHITE ) ) ); - const BitmapColor aBlack( pR->GetBestMatchingColor( Color( COL_BLACK ) ) ); - const long nWidth = pW->Width(), nHeight = pW->Height(); - const long nR = aFillCol.GetRed(), nG = aFillCol.GetGreen(), nB = aFillCol.GetBlue(); - long nX, nY; - - if( aPaint.GetBitCount() <= 8 ) - { - const BitmapPalette& rPal = pW->GetPalette(); - const sal_uInt16 nCount = rPal.GetEntryCount(); - BitmapColor* pMap = (BitmapColor*) new sal_uInt8[ nCount * sizeof( BitmapColor ) ]; - - for( sal_uInt16 i = 0; i < nCount; i++ ) - { - BitmapColor aCol( rPal[ i ] ); - pMap[ i ] = BitmapColor( (sal_uInt8) rPal.GetBestIndex( aCol.Merge( aFillCol, cTrans ) ) ); - } - - if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && - pW->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) - { - const sal_uInt8 cBlack = aBlack.GetIndex(); - - for( nY = 0; nY < nHeight; nY++ ) - { - Scanline pWScan = pW->GetScanline( nY ); - Scanline pRScan = pR->GetScanline( nY ); - sal_uInt8 cBit = 128; - - for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ ) - { - if( !cBit ) - cBit = 128, pRScan++; - - if( ( *pRScan & cBit ) == cBlack ) - *pWScan = (sal_uInt8) pMap[ *pWScan ].GetIndex(); - } - } - } - else - { - for( nY = 0; nY < nHeight; nY++ ) - for( nX = 0; nX < nWidth; nX++ ) - if( pR->GetPixel( nY, nX ) == aBlack ) - pW->SetPixel( nY, nX, pMap[ pW->GetPixel( nY, nX ).GetIndex() ] ); - } - - delete[] (sal_uInt8*) pMap; - } - else - { - if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && - pW->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) - { - const sal_uInt8 cBlack = aBlack.GetIndex(); - - for( nY = 0; nY < nHeight; nY++ ) - { - Scanline pWScan = pW->GetScanline( nY ); - Scanline pRScan = pR->GetScanline( nY ); - sal_uInt8 cBit = 128; - - for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 ) - { - if( !cBit ) - cBit = 128, pRScan++; - - if( ( *pRScan & cBit ) == cBlack ) - { - pWScan[ 0 ] = COLOR_CHANNEL_MERGE( pWScan[ 0 ], nB, cTrans ); - pWScan[ 1 ] = COLOR_CHANNEL_MERGE( pWScan[ 1 ], nG, cTrans ); - pWScan[ 2 ] = COLOR_CHANNEL_MERGE( pWScan[ 2 ], nR, cTrans ); - } - } - } - } - else - { - for( nY = 0; nY < nHeight; nY++ ) - { - for( nX = 0; nX < nWidth; nX++ ) - { - if( pR->GetPixel( nY, nX ) == aBlack ) - { - aPixCol = pW->GetColor( nY, nX ); - pW->SetPixel( nY, nX, aPixCol.Merge( aFillCol, cTrans ) ); - } - } - } - } - } - } - - aPolyMask.ReleaseAccess( pR ); - aPaint.ReleaseAccess( pW ); - - DrawBitmap( aDstRect.TopLeft(), aPaint ); - - EnableMapMode( bOldMap ); - - if( mbLineColor ) - { - Push( PUSH_FILLCOLOR ); - SetFillColor(); - DrawPolyPolygon( rPolyPoly ); - Pop(); - } - } - } - else - DrawPolyPolygon( rPolyPoly ); - } - } - - mpMetaFile = pOldMetaFile; - - // #110958# Restore disabled alpha VDev - mpAlphaVDev = pOldAlphaVDev; -} - -void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly, - sal_uInt16 nTransparencePercent ) -{ - // short circuit for drawing an opaque polygon - if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) ) - { - DrawPolyPolygon( rPolyPoly ); - return; - } - - // short circuit for drawing an invisible polygon - if( !mbFillColor || (nTransparencePercent >= 100) ) - { - DrawInvisiblePolygon( rPolyPoly ); - } - - // handle metafile recording - if( mpMetaFile ) - mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) ); - - bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout(); - if( bDrawn ) - return; - - // get the device graphics as drawing target - if( !mpGraphics ) - if( !ImplGetGraphics() ) - return; - - // try hard to draw it directly, because the emulation layers are slower - bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent ); - if( bDrawn ) - return; - - EmulateDrawTransparent( rPolyPoly, nTransparencePercent ); - - // #110958# Apply alpha value also to VDev alpha channel - if( mpAlphaVDev ) - { - const Color aFillCol( mpAlphaVDev->GetFillColor() ); - mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100), - sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100), - sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) ); - - mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent ); - - mpAlphaVDev->SetFillColor( aFillCol ); - } -} - -void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, - const Size& rSize, const Gradient& rTransparenceGradient ) -{ - - const Color aBlack( COL_BLACK ); - - if( mpMetaFile ) - { - // missing here is to map the data using the DeviceTransformation - mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) ); - } - - if ( !IsDeviceOutputNecessary() ) - return; - - if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) || - ( mnDrawMode & ( DRAWMODE_NOTRANSPARENCY ) ) ) - { - ( (GDIMetaFile&) rMtf ).WindStart(); - ( (GDIMetaFile&) rMtf ).Play( this, rPos, rSize ); - ( (GDIMetaFile&) rMtf ).WindStart(); - } - else - { - GDIMetaFile* pOldMetaFile = mpMetaFile; - Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) ); - Point aPoint; - Rectangle aDstRect( aPoint, GetOutputSizePixel() ); - - mpMetaFile = NULL; - aDstRect.Intersection( aOutRect ); - - ClipToPaintRegion( aDstRect ); - - if( !aDstRect.IsEmpty() ) - { - boost::scoped_ptr<VirtualDevice> pVDev(new VirtualDevice); - - ((OutputDevice*)pVDev.get())->mnDPIX = mnDPIX; - ((OutputDevice*)pVDev.get())->mnDPIY = mnDPIY; - - if( pVDev->SetOutputSizePixel( aDstRect.GetSize() ) ) - { - if(GetAntialiasing()) - { - // #i102109# - // For MetaFile replay (see task) it may now be necessary to take - // into account that the content is AntiAlialised and needs to be masked - // like that. Instead of masking, i will use a copy-modify-paste cycle - // here (as i already use in the VclPrimiziveRenderer with successs) - pVDev->SetAntialiasing(GetAntialiasing()); - - // create MapMode for buffer (offset needed) and set - MapMode aMap(GetMapMode()); - const Point aOutPos(PixelToLogic(aDstRect.TopLeft())); - aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y())); - pVDev->SetMapMode(aMap); - - // copy MapMode state and disable for target - const bool bOrigMapModeEnabled(IsMapModeEnabled()); - EnableMapMode(false); - - // copy MapMode state and disable for buffer - const bool bBufferMapModeEnabled(pVDev->IsMapModeEnabled()); - pVDev->EnableMapMode(false); - - // copy content from original to buffer - pVDev->DrawOutDev( - aPoint, pVDev->GetOutputSizePixel(), // dest - aDstRect.TopLeft(), pVDev->GetOutputSizePixel(), // source - *this); - - // draw MetaFile to buffer - pVDev->EnableMapMode(bBufferMapModeEnabled); - ((GDIMetaFile&)rMtf).WindStart(); - ((GDIMetaFile&)rMtf).Play(pVDev.get(), rPos, rSize); - ((GDIMetaFile&)rMtf).WindStart(); - - // get content bitmap from buffer - pVDev->EnableMapMode(false); - const Bitmap aPaint(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel())); - - // create alpha mask from gradient and get as Bitmap - pVDev->EnableMapMode(bBufferMapModeEnabled); - pVDev->SetDrawMode(DRAWMODE_GRAYGRADIENT); - pVDev->DrawGradient(Rectangle(rPos, rSize), rTransparenceGradient); - pVDev->SetDrawMode(DRAWMODE_DEFAULT); - pVDev->EnableMapMode(false); - const AlphaMask aAlpha(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel())); - - pVDev.reset(); - - // draw masked content to target and restore MapMode - DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha)); - EnableMapMode(bOrigMapModeEnabled); - } - else - { - Bitmap aPaint, aMask; - AlphaMask aAlpha; - MapMode aMap( GetMapMode() ); - Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) ); - const bool bOldMap = mbMap; - - aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) ); - pVDev->SetMapMode( aMap ); - const bool bVDevOldMap = pVDev->IsMapModeEnabled(); - - // create paint bitmap - ( (GDIMetaFile&) rMtf ).WindStart(); - ( (GDIMetaFile&) rMtf ).Play( pVDev.get(), rPos, rSize ); - ( (GDIMetaFile&) rMtf ).WindStart(); - pVDev->EnableMapMode( false ); - aPaint = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); - pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here! - - // create mask bitmap - pVDev->SetLineColor( COL_BLACK ); - pVDev->SetFillColor( COL_BLACK ); - pVDev->DrawRect( Rectangle( pVDev->PixelToLogic( Point() ), pVDev->GetOutputSize() ) ); - pVDev->SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT | - DRAWMODE_WHITEBITMAP | DRAWMODE_WHITEGRADIENT ); - ( (GDIMetaFile&) rMtf ).WindStart(); - ( (GDIMetaFile&) rMtf ).Play( pVDev.get(), rPos, rSize ); - ( (GDIMetaFile&) rMtf ).WindStart(); - pVDev->EnableMapMode( false ); - aMask = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); - pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here! - - // create alpha mask from gradient - pVDev->SetDrawMode( DRAWMODE_GRAYGRADIENT ); - pVDev->DrawGradient( Rectangle( rPos, rSize ), rTransparenceGradient ); - pVDev->SetDrawMode( DRAWMODE_DEFAULT ); - pVDev->EnableMapMode( false ); - pVDev->DrawMask( Point(), pVDev->GetOutputSizePixel(), aMask, Color( COL_WHITE ) ); - - aAlpha = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); - - pVDev.reset(); - - EnableMapMode( false ); - DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) ); - EnableMapMode( bOldMap ); - } - } - } - - mpMetaFile = pOldMetaFile; - } -} - -void OutputDevice::ImplDrawColorWallpaper( long nX, long nY, - long nWidth, long nHeight, - const Wallpaper& rWallpaper ) -{ - // draw wallpaper without border - Color aOldLineColor = GetLineColor(); - Color aOldFillColor = GetFillColor(); - SetLineColor(); - SetFillColor( rWallpaper.GetColor() ); - bool bMap = mbMap; - EnableMapMode( false ); - DrawRect( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); - SetLineColor( aOldLineColor ); - SetFillColor( aOldFillColor ); - EnableMapMode( bMap ); -} - -void OutputDevice::ImplDrawBitmapWallpaper( long nX, long nY, - long nWidth, long nHeight, - const Wallpaper& rWallpaper ) -{ - BitmapEx aBmpEx; - const BitmapEx* pCached = rWallpaper.ImplGetImpWallpaper()->ImplGetCachedBitmap(); - Point aPos; - Size aSize; - GDIMetaFile* pOldMetaFile = mpMetaFile; - const WallpaperStyle eStyle = rWallpaper.GetStyle(); - const bool bOldMap = mbMap; - bool bDrawn = false; - bool bDrawGradientBackground = false; - bool bDrawColorBackground = false; - - if( pCached ) - aBmpEx = *pCached; - else - aBmpEx = rWallpaper.GetBitmap(); - - const long nBmpWidth = aBmpEx.GetSizePixel().Width(); - const long nBmpHeight = aBmpEx.GetSizePixel().Height(); - const bool bTransparent = aBmpEx.IsTransparent(); - - // draw background - if( bTransparent ) - { - if( rWallpaper.IsGradient() ) - bDrawGradientBackground = true; - else - { - if( !pCached && !rWallpaper.GetColor().GetTransparency() ) - { - VirtualDevice aVDev( *this ); - aVDev.SetBackground( rWallpaper.GetColor() ); - aVDev.SetOutputSizePixel( Size( nBmpWidth, nBmpHeight ) ); - aVDev.DrawBitmapEx( Point(), aBmpEx ); - aBmpEx = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() ); - } - - bDrawColorBackground = true; - } - } - else if( eStyle != WALLPAPER_TILE && eStyle != WALLPAPER_SCALE ) - { - if( rWallpaper.IsGradient() ) - bDrawGradientBackground = true; - else - bDrawColorBackground = true; - } - - // background of bitmap? - if( bDrawGradientBackground ) - ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); - else if( bDrawColorBackground && bTransparent ) - { - ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); - bDrawColorBackground = false; - } - - // calc pos and size - if( rWallpaper.IsRect() ) - { - const Rectangle aBound( LogicToPixel( rWallpaper.GetRect() ) ); - aPos = aBound.TopLeft(); - aSize = aBound.GetSize(); - } - else - { - aPos = Point( 0, 0 ); - aSize = Size( mnOutWidth, mnOutHeight ); - } - - mpMetaFile = NULL; - EnableMapMode( false ); - Push( PUSH_CLIPREGION ); - IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); - - switch( eStyle ) - { - case( WALLPAPER_SCALE ): - { - if( !pCached || ( pCached->GetSizePixel() != aSize ) ) - { - if( pCached ) - rWallpaper.ImplGetImpWallpaper()->ImplReleaseCachedBitmap(); - - aBmpEx = rWallpaper.GetBitmap(); - aBmpEx.Scale( aSize ); - aBmpEx = BitmapEx( aBmpEx.GetBitmap().CreateDisplayBitmap( this ), aBmpEx.GetMask() ); - } - } - break; - - case( WALLPAPER_TOPLEFT ): - break; - - case( WALLPAPER_TOP ): - aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1; - break; - - case( WALLPAPER_TOPRIGHT ): - aPos.X() += ( aSize.Width() - nBmpWidth ); - break; - - case( WALLPAPER_LEFT ): - aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1; - break; - - case( WALLPAPER_CENTER ): - { - aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1; - aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1; - } - break; - - case( WALLPAPER_RIGHT ): - { - aPos.X() += ( aSize.Width() - nBmpWidth ); - aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1; - } - break; - - case( WALLPAPER_BOTTOMLEFT ): - aPos.Y() += ( aSize.Height() - nBmpHeight ); - break; - - case( WALLPAPER_BOTTOM ): - { - aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1; - aPos.Y() += ( aSize.Height() - nBmpHeight ); - } - break; - - case( WALLPAPER_BOTTOMRIGHT ): - { - aPos.X() += ( aSize.Width() - nBmpWidth ); - aPos.Y() += ( aSize.Height() - nBmpHeight ); - } - break; - - default: - { - const long nRight = nX + nWidth - 1L; - const long nBottom = nY + nHeight - 1L; - long nFirstX; - long nFirstY; - - if( eStyle == WALLPAPER_TILE ) - { - nFirstX = aPos.X(); - nFirstY = aPos.Y(); - } - else - { - nFirstX = aPos.X() + ( ( aSize.Width() - nBmpWidth ) >> 1 ); - nFirstY = aPos.Y() + ( ( aSize.Height() - nBmpHeight ) >> 1 ); - } - - const long nOffX = ( nFirstX - nX ) % nBmpWidth; - const long nOffY = ( nFirstY - nY ) % nBmpHeight; - long nStartX = nX + nOffX; - long nStartY = nY + nOffY; - - if( nOffX > 0L ) - nStartX -= nBmpWidth; - - if( nOffY > 0L ) - nStartY -= nBmpHeight; - - for( long nBmpY = nStartY; nBmpY <= nBottom; nBmpY += nBmpHeight ) - for( long nBmpX = nStartX; nBmpX <= nRight; nBmpX += nBmpWidth ) - DrawBitmapEx( Point( nBmpX, nBmpY ), aBmpEx ); - - bDrawn = true; - } - break; - } - - if( !bDrawn ) - { - // optimized for non-transparent bitmaps - if( bDrawColorBackground ) - { - const Size aBmpSize( aBmpEx.GetSizePixel() ); - const Point aTmpPoint; - const Rectangle aOutRect( aTmpPoint, GetOutputSizePixel() ); - const Rectangle aColRect( Point( nX, nY ), Size( nWidth, nHeight ) ); - Rectangle aWorkRect; - - aWorkRect = Rectangle( 0, 0, aOutRect.Right(), aPos.Y() - 1L ); - aWorkRect.Justify(); - aWorkRect.Intersection( aColRect ); - if( !aWorkRect.IsEmpty() ) - { - ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), - aWorkRect.GetWidth(), aWorkRect.GetHeight(), - rWallpaper ); - } - - aWorkRect = Rectangle( 0, aPos.Y(), aPos.X() - 1L, aPos.Y() + aBmpSize.Height() - 1L ); - aWorkRect.Justify(); - aWorkRect.Intersection( aColRect ); - if( !aWorkRect.IsEmpty() ) - { - ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), - aWorkRect.GetWidth(), aWorkRect.GetHeight(), - rWallpaper ); - } - - aWorkRect = Rectangle( aPos.X() + aBmpSize.Width(), aPos.Y(), aOutRect.Right(), aPos.Y() + aBmpSize.Height() - 1L ); - aWorkRect.Justify(); - aWorkRect.Intersection( aColRect ); - if( !aWorkRect.IsEmpty() ) - { - ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), - aWorkRect.GetWidth(), aWorkRect.GetHeight(), - rWallpaper ); - } - - aWorkRect = Rectangle( 0, aPos.Y() + aBmpSize.Height(), aOutRect.Right(), aOutRect.Bottom() ); - aWorkRect.Justify(); - aWorkRect.Intersection( aColRect ); - if( !aWorkRect.IsEmpty() ) - { - ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), - aWorkRect.GetWidth(), aWorkRect.GetHeight(), - rWallpaper ); - } - } - - DrawBitmapEx( aPos, aBmpEx ); - } - - rWallpaper.ImplGetImpWallpaper()->ImplSetCachedBitmap( aBmpEx ); - - Pop(); - EnableMapMode( bOldMap ); - mpMetaFile = pOldMetaFile; -} - -void OutputDevice::ImplDrawGradientWallpaper( long nX, long nY, - long nWidth, long nHeight, - const Wallpaper& rWallpaper ) -{ - Rectangle aBound; - GDIMetaFile* pOldMetaFile = mpMetaFile; - const bool bOldMap = mbMap; - bool bNeedGradient = true; - - aBound = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ); - - mpMetaFile = NULL; - EnableMapMode( false ); - Push( PUSH_CLIPREGION ); - IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); - - if( OUTDEV_WINDOW == meOutDevType && rWallpaper.GetStyle() == WALLPAPER_APPLICATIONGRADIENT ) - { - Window *pWin = dynamic_cast< Window* >( this ); - if( pWin ) - { - // limit gradient to useful size, so that it still can be noticed - // in maximized windows - long gradientWidth = pWin->GetDesktopRectPixel().GetSize().Width(); - if( gradientWidth > 1024 ) - gradientWidth = 1024; - if( mnOutOffX+nWidth > gradientWidth ) - ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper.GetGradient().GetEndColor() ); - if( mnOutOffX > gradientWidth ) - bNeedGradient = false; - else - aBound = Rectangle( Point( -mnOutOffX, nY ), Size( gradientWidth, nHeight ) ); - } - } - - if( bNeedGradient ) - DrawGradient( aBound, rWallpaper.GetGradient() ); - - Pop(); - EnableMapMode( bOldMap ); - mpMetaFile = pOldMetaFile; -} - -void OutputDevice::ImplDrawWallpaper( long nX, long nY, - long nWidth, long nHeight, - const Wallpaper& rWallpaper ) -{ - if( rWallpaper.IsBitmap() ) - ImplDrawBitmapWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); - else if( rWallpaper.IsGradient() ) - ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); - else - ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); -} - -void OutputDevice::DrawWallpaper( const Rectangle& rRect, - const Wallpaper& rWallpaper ) -{ - if ( mpMetaFile ) - mpMetaFile->AddAction( new MetaWallpaperAction( rRect, rWallpaper ) ); - - if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) - return; - - if ( rWallpaper.GetStyle() != WALLPAPER_NULL ) - { - Rectangle aRect = LogicToPixel( rRect ); - aRect.Justify(); - - if ( !aRect.IsEmpty() ) - { - ImplDrawWallpaper( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), - rWallpaper ); - } - } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawWallpaper( rRect, rWallpaper ); -} - -void OutputDevice::Erase() -{ - if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) - return; - - bool bNativeOK = false; - - if( meOutDevType == OUTDEV_WINDOW ) - { - Window* pWindow = static_cast<Window*>(this); - ControlPart aCtrlPart = pWindow->ImplGetWindowImpl()->mnNativeBackground; - if( aCtrlPart != 0 && ! pWindow->IsControlBackground() ) - { - ImplControlValue aControlValue; - Point aGcc3WorkaroundTemporary; - Rectangle aCtrlRegion( aGcc3WorkaroundTemporary, GetOutputSizePixel() ); - ControlState nState = 0; - - if( pWindow->IsEnabled() ) nState |= CTRL_STATE_ENABLED; - bNativeOK = pWindow->DrawNativeControl( CTRL_WINDOW_BACKGROUND, aCtrlPart, aCtrlRegion, - nState, aControlValue, OUString() ); - } - } - - if ( mbBackground && ! bNativeOK ) - { - RasterOp eRasterOp = GetRasterOp(); - if ( eRasterOp != ROP_OVERPAINT ) - SetRasterOp( ROP_OVERPAINT ); - ImplDrawWallpaper( 0, 0, mnOutWidth, mnOutHeight, maBackground ); - if ( eRasterOp != ROP_OVERPAINT ) - SetRasterOp( eRasterOp ); - } - - if( mpAlphaVDev ) - mpAlphaVDev->Erase(); -} - -bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, - const GfxLink& rGfxLink, GDIMetaFile* pSubst ) -{ - bool bDrawn(true); - - if ( mpMetaFile ) - { - GDIMetaFile aSubst; - - if( pSubst ) - aSubst = *pSubst; - - mpMetaFile->AddAction( new MetaEPSAction( rPoint, rSize, rGfxLink, aSubst ) ); - } - - if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) - return bDrawn; - - if( mbOutputClipped ) - return bDrawn; - - Rectangle aRect( ImplLogicToDevicePixel( Rectangle( rPoint, rSize ) ) ); - - if( !aRect.IsEmpty() ) - { - // draw the real EPS graphics - if( rGfxLink.GetData() && rGfxLink.GetDataSize() ) - { - if( !mpGraphics && !ImplGetGraphics() ) - return bDrawn; - - if( mbInitClipRegion ) - ImplInitClipRegion(); - - aRect.Justify(); - bDrawn = mpGraphics->DrawEPS( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), - (sal_uInt8*) rGfxLink.GetData(), rGfxLink.GetDataSize(), this ); - } - - // else draw the substitution graphics - if( !bDrawn && pSubst ) - { - GDIMetaFile* pOldMetaFile = mpMetaFile; - - mpMetaFile = NULL; - Graphic( *pSubst ).Draw( this, rPoint, rSize ); - mpMetaFile = pOldMetaFile; - } - } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawEPS( rPoint, rSize, rGfxLink, pSubst ); - - return bDrawn; -} - -void OutputDevice::DrawCheckered(const Point& rPos, const Size& rSize, sal_uInt32 nLen, Color aStart, Color aEnd) -{ - const sal_uInt32 nMaxX(rPos.X() + rSize.Width()); - const sal_uInt32 nMaxY(rPos.Y() + rSize.Height()); - - Push(PUSH_LINECOLOR|PUSH_FILLCOLOR); - SetLineColor(); - - for(sal_uInt32 x(0), nX(rPos.X()); nX < nMaxX; x++, nX += nLen) - { - const sal_uInt32 nRight(std::min(nMaxX, nX + nLen)); - - for(sal_uInt32 y(0), nY(rPos.Y()); nY < nMaxY; y++, nY += nLen) - { - const sal_uInt32 nBottom(std::min(nMaxY, nY + nLen)); - - SetFillColor((x & 0x0001) ^ (y & 0x0001) ? aStart : aEnd); - DrawRect(Rectangle(nX, nY, nRight, nBottom)); - } - } - - Pop(); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx index 09561a6055a2..312625dfd850 100644 --- a/vcl/source/outdev/polygon.cxx +++ b/vcl/source/outdev/polygon.cxx @@ -476,3 +476,97 @@ void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon& rPolyPoly, const Poly if( pClipPolyPoly ) delete pPolyPoly; } + +void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLong nFlags ) +{ + + Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() ); + aDstRect.Intersection( rRect ); + + if( aDstRect.IsEmpty() || ImplIsRecordLayout() ) + return; + + if( !mpGraphics && !ImplGetGraphics() ) + return; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + + if( mbOutputClipped ) + return; + + const long nDistX = std::max( rDist.Width(), 1L ); + const long nDistY = std::max( rDist.Height(), 1L ); + long nX = ( rRect.Left() >= aDstRect.Left() ) ? rRect.Left() : ( rRect.Left() + ( ( aDstRect.Left() - rRect.Left() ) / nDistX ) * nDistX ); + long nY = ( rRect.Top() >= aDstRect.Top() ) ? rRect.Top() : ( rRect.Top() + ( ( aDstRect.Top() - rRect.Top() ) / nDistY ) * nDistY ); + const long nRight = aDstRect.Right(); + const long nBottom = aDstRect.Bottom(); + const long nStartX = ImplLogicXToDevicePixel( nX ); + const long nEndX = ImplLogicXToDevicePixel( nRight ); + const long nStartY = ImplLogicYToDevicePixel( nY ); + const long nEndY = ImplLogicYToDevicePixel( nBottom ); + long nHorzCount = 0L; + long nVertCount = 0L; + + ::com::sun::star::uno::Sequence< sal_Int32 > aVertBuf; + ::com::sun::star::uno::Sequence< sal_Int32 > aHorzBuf; + + if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_HORZLINES ) ) + { + aVertBuf.realloc( aDstRect.GetHeight() / nDistY + 2L ); + aVertBuf[ nVertCount++ ] = nStartY; + while( ( nY += nDistY ) <= nBottom ) + aVertBuf[ nVertCount++ ] = ImplLogicYToDevicePixel( nY ); + } + + if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_VERTLINES ) ) + { + aHorzBuf.realloc( aDstRect.GetWidth() / nDistX + 2L ); + aHorzBuf[ nHorzCount++ ] = nStartX; + while( ( nX += nDistX ) <= nRight ) + aHorzBuf[ nHorzCount++ ] = ImplLogicXToDevicePixel( nX ); + } + + if( mbInitLineColor ) + ImplInitLineColor(); + + if( mbInitFillColor ) + ImplInitFillColor(); + + const bool bOldMap = mbMap; + EnableMapMode( false ); + + if( nFlags & GRID_DOTS ) + { + for( long i = 0L; i < nVertCount; i++ ) + for( long j = 0L, Y = aVertBuf[ i ]; j < nHorzCount; j++ ) + mpGraphics->DrawPixel( aHorzBuf[ j ], Y, this ); + } + else + { + if( nFlags & GRID_HORZLINES ) + { + for( long i = 0L; i < nVertCount; i++ ) + { + nY = aVertBuf[ i ]; + mpGraphics->DrawLine( nStartX, nY, nEndX, nY, this ); + } + } + + if( nFlags & GRID_VERTLINES ) + { + for( long i = 0L; i < nHorzCount; i++ ) + { + nX = aHorzBuf[ i ]; + mpGraphics->DrawLine( nX, nStartY, nX, nEndY, this ); + } + } + } + + EnableMapMode( bOldMap ); + + if( mpAlphaVDev ) + mpAlphaVDev->DrawGrid( rRect, rDist, nFlags ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx index 9bc8e392b701..c5b630abc22c 100644 --- a/vcl/source/outdev/transparent.cxx +++ b/vcl/source/outdev/transparent.cxx @@ -40,6 +40,48 @@ #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <boost/scoped_array.hpp> + +namespace +{ + /** + * Perform a safe approximation of a polygon from double-precision + * coordinates to integer coordinates, to ensure that it has at least 2 + * pixels in both X and Y directions. + */ + Polygon toPolygon( const basegfx::B2DPolygon& rPoly ) + { + basegfx::B2DRange aRange = rPoly.getB2DRange(); + double fW = aRange.getWidth(), fH = aRange.getHeight(); + if (0.0 < fW && 0.0 < fH && (fW <= 1.0 || fH <= 1.0)) + { + // This polygon not empty but is too small to display. Approximate it + // with a rectangle large enough to be displayed. + double nX = aRange.getMinX(), nY = aRange.getMinY(); + double nW = std::max<double>(1.0, rtl::math::round(fW)); + double nH = std::max<double>(1.0, rtl::math::round(fH)); + + Polygon aTarget; + aTarget.Insert(0, Point(nX, nY)); + aTarget.Insert(1, Point(nX+nW, nY)); + aTarget.Insert(2, Point(nX+nW, nY+nH)); + aTarget.Insert(3, Point(nX, nY+nH)); + aTarget.Insert(4, Point(nX, nY)); + return aTarget; + } + return Polygon(rPoly); + } + + PolyPolygon toPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly ) + { + PolyPolygon aTarget; + for (sal_uInt32 i = 0; i < rPolyPoly.count(); ++i) + aTarget.Insert(toPolygon(rPolyPoly.getB2DPolygon(i))); + + return aTarget; + } + +} + void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask, const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel ) @@ -133,4 +175,565 @@ void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask } } +// Caution: This method is nearly the same as +// void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly ) +// so when changes are made here do not forget to make changes there, too + +void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency) +{ + // AW: Do NOT paint empty PolyPolygons + if(!rB2DPolyPoly.count()) + return; + + // we need a graphics + if( !mpGraphics ) + if( !ImplGetGraphics() ) + return; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + if( mbOutputClipped ) + return; + + if( mbInitLineColor ) + ImplInitLineColor(); + if( mbInitFillColor ) + ImplInitFillColor(); + + if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) + && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) + && ROP_OVERPAINT == GetRasterOp() ) + { + // b2dpolygon support not implemented yet on non-UNX platforms + const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); + basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly); + + // transform the polygon into device space and ensure it is closed + aB2DPolyPolygon.transform( aTransform ); + aB2DPolyPolygon.setClosed( true ); + + bool bDrawnOk = true; + if( IsFillColor() ) + bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this ); + if( bDrawnOk && IsLineColor() ) + { + const basegfx::B2DVector aHairlineWidth(1,1); + const int nPolyCount = aB2DPolyPolygon.count(); + for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) + { + const ::basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); + mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this ); + } + } + + if( bDrawnOk ) + { + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaTransparentAction( PolyPolygon( rB2DPolyPoly ), static_cast< sal_uInt16 >(fTransparency * 100.0))); + return; + } + } + + // fallback to old polygon drawing if needed + DrawTransparent(toPolyPolygon(rB2DPolyPoly), static_cast<sal_uInt16>(fTransparency * 100.0)); +} + +void OutputDevice::DrawInvisiblePolygon( const PolyPolygon& rPolyPoly ) +{ + // short circuit if the polygon border is invisible too + if( !mbLineColor ) + return; + + // we assume that the border is NOT to be drawn transparently??? + Push( PUSH_FILLCOLOR ); + SetFillColor(); + DrawPolyPolygon( rPolyPoly ); + Pop(); +} + +bool OutputDevice::DrawTransparentNatively ( const PolyPolygon& rPolyPoly, + sal_uInt16 nTransparencePercent ) +{ + bool bDrawn = false; + + // debug helper: + static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA"); + + if( !pDisableNative + && mpGraphics->supportsOperation( OutDevSupport_B2DDraw ) +#if defined UNX && ! defined MACOSX && ! defined IOS + && GetBitCount() > 8 +#endif +#ifdef WIN32 + // workaround bad dithering on remote displaying when using GDI+ with toolbar button highlighting + && !rPolyPoly.IsRect() +#endif + ) + { + // prepare the graphics device + if( mbInitClipRegion ) + ImplInitClipRegion(); + if( mbOutputClipped ) + return false; + if( mbInitLineColor ) + ImplInitLineColor(); + if( mbInitFillColor ) + ImplInitFillColor(); + + // get the polygon in device coordinates + basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() ); + const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); + aB2DPolyPolygon.transform( aTransform ); + + const double fTransparency = 0.01 * nTransparencePercent; + if( mbFillColor ) + { + // #i121591# + // CAUTION: Only non printing (pixel-renderer) VCL commands from OutputDevices + // should be used when printing. Normally this is avoided by the printer being + // non-AAed and thus e.g. on WIN GdiPlus calls are not used. It may be necessary + // to figure out a way of moving this code to it's own function that is + // overriden by the Print class, which will mean we deliberately override the + // functionality and we use the fallback some lines below (which is not very good, + // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and + // correct the wrong mapping (see there for details) + bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this ); + } + + if( mbLineColor ) + { + // disable the fill color for now + mpGraphics->SetFillColor(); + // draw the border line + const basegfx::B2DVector aLineWidths( 1, 1 ); + const int nPolyCount = aB2DPolyPolygon.count(); + for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) + { + const ::basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); + bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this ); + } + // prepare to restore the fill color + mbInitFillColor = mbFillColor; + } + } + + return bDrawn; +} + +void OutputDevice::EmulateDrawTransparent ( const PolyPolygon& rPolyPoly, + sal_uInt16 nTransparencePercent ) +{ + // debug helper: + static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA"); + + // #110958# Disable alpha VDev, we perform the necessary + VirtualDevice* pOldAlphaVDev = mpAlphaVDev; + + // operation explicitly further below. + if( mpAlphaVDev ) + mpAlphaVDev = NULL; + + GDIMetaFile* pOldMetaFile = mpMetaFile; + mpMetaFile = NULL; + + PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); + Rectangle aPolyRect( aPolyPoly.GetBoundRect() ); + Point aPoint; + Rectangle aDstRect( aPoint, GetOutputSizePixel() ); + + aDstRect.Intersection( aPolyRect ); + + ClipToPaintRegion( aDstRect ); + + if( !aDstRect.IsEmpty() ) + { + bool bDrawn = false; + + // #i66849# Added fast path for exactly rectangular + // polygons + // #i83087# Naturally, system alpha blending cannot + // work with separate alpha VDev + if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() ) + { + // setup Graphics only here (other cases delegate + // to basic OutDev methods) + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + + Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() ); + Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) ); + + if( !mbOutputClipped ) + { + bDrawn = mpGraphics->DrawAlphaRect( + aPixelRect.Left(), aPixelRect.Top(), + // #i98405# use methods with small g, else one pixel too much will be painted. + // This is because the source is a polygon which when painted would not paint + // the rightmost and lowest pixel line(s), so use one pixel less for the + // rectangle, too. + aPixelRect.getWidth(), aPixelRect.getHeight(), + sal::static_int_cast<sal_uInt8>(nTransparencePercent), + this ); + } + else + bDrawn = true; + } + + if( !bDrawn ) + { + VirtualDevice aVDev( *this, 1 ); + const Size aDstSz( aDstRect.GetSize() ); + const sal_uInt8 cTrans = (sal_uInt8) MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 ); + + if( aDstRect.Left() || aDstRect.Top() ) + aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() ); + + if( aVDev.SetOutputSizePixel( aDstSz ) ) + { + const bool bOldMap = mbMap; + + EnableMapMode( false ); + + aVDev.SetLineColor( COL_BLACK ); + aVDev.SetFillColor( COL_BLACK ); + aVDev.DrawPolyPolygon( aPolyPoly ); + + Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) ); + Bitmap aPolyMask( aVDev.GetBitmap( Point(), aDstSz ) ); + + // #107766# check for non-empty bitmaps before accessing them + if( !!aPaint && !!aPolyMask ) + { + BitmapWriteAccess* pW = aPaint.AcquireWriteAccess(); + BitmapReadAccess* pR = aPolyMask.AcquireReadAccess(); + + if( pW && pR ) + { + BitmapColor aPixCol; + const BitmapColor aFillCol( GetFillColor() ); + const BitmapColor aWhite( pR->GetBestMatchingColor( Color( COL_WHITE ) ) ); + const BitmapColor aBlack( pR->GetBestMatchingColor( Color( COL_BLACK ) ) ); + const long nWidth = pW->Width(), nHeight = pW->Height(); + const long nR = aFillCol.GetRed(), nG = aFillCol.GetGreen(), nB = aFillCol.GetBlue(); + long nX, nY; + + if( aPaint.GetBitCount() <= 8 ) + { + const BitmapPalette& rPal = pW->GetPalette(); + const sal_uInt16 nCount = rPal.GetEntryCount(); + BitmapColor* pMap = (BitmapColor*) new sal_uInt8[ nCount * sizeof( BitmapColor ) ]; + + for( sal_uInt16 i = 0; i < nCount; i++ ) + { + BitmapColor aCol( rPal[ i ] ); + pMap[ i ] = BitmapColor( (sal_uInt8) rPal.GetBestIndex( aCol.Merge( aFillCol, cTrans ) ) ); + } + + if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && + pW->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + const sal_uInt8 cBlack = aBlack.GetIndex(); + + for( nY = 0; nY < nHeight; nY++ ) + { + Scanline pWScan = pW->GetScanline( nY ); + Scanline pRScan = pR->GetScanline( nY ); + sal_uInt8 cBit = 128; + + for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ ) + { + if( !cBit ) + cBit = 128, pRScan++; + + if( ( *pRScan & cBit ) == cBlack ) + *pWScan = (sal_uInt8) pMap[ *pWScan ].GetIndex(); + } + } + } + else + { + for( nY = 0; nY < nHeight; nY++ ) + for( nX = 0; nX < nWidth; nX++ ) + if( pR->GetPixel( nY, nX ) == aBlack ) + pW->SetPixel( nY, nX, pMap[ pW->GetPixel( nY, nX ).GetIndex() ] ); + } + + delete[] (sal_uInt8*) pMap; + } + else + { + if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && + pW->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) + { + const sal_uInt8 cBlack = aBlack.GetIndex(); + + for( nY = 0; nY < nHeight; nY++ ) + { + Scanline pWScan = pW->GetScanline( nY ); + Scanline pRScan = pR->GetScanline( nY ); + sal_uInt8 cBit = 128; + + for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 ) + { + if( !cBit ) + cBit = 128, pRScan++; + + if( ( *pRScan & cBit ) == cBlack ) + { + pWScan[ 0 ] = COLOR_CHANNEL_MERGE( pWScan[ 0 ], nB, cTrans ); + pWScan[ 1 ] = COLOR_CHANNEL_MERGE( pWScan[ 1 ], nG, cTrans ); + pWScan[ 2 ] = COLOR_CHANNEL_MERGE( pWScan[ 2 ], nR, cTrans ); + } + } + } + } + else + { + for( nY = 0; nY < nHeight; nY++ ) + { + for( nX = 0; nX < nWidth; nX++ ) + { + if( pR->GetPixel( nY, nX ) == aBlack ) + { + aPixCol = pW->GetColor( nY, nX ); + pW->SetPixel( nY, nX, aPixCol.Merge( aFillCol, cTrans ) ); + } + } + } + } + } + } + + aPolyMask.ReleaseAccess( pR ); + aPaint.ReleaseAccess( pW ); + + DrawBitmap( aDstRect.TopLeft(), aPaint ); + + EnableMapMode( bOldMap ); + + if( mbLineColor ) + { + Push( PUSH_FILLCOLOR ); + SetFillColor(); + DrawPolyPolygon( rPolyPoly ); + Pop(); + } + } + } + else + DrawPolyPolygon( rPolyPoly ); + } + } + + mpMetaFile = pOldMetaFile; + + // #110958# Restore disabled alpha VDev + mpAlphaVDev = pOldAlphaVDev; +} + +void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly, + sal_uInt16 nTransparencePercent ) +{ + // short circuit for drawing an opaque polygon + if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) ) + { + DrawPolyPolygon( rPolyPoly ); + return; + } + + // short circuit for drawing an invisible polygon + if( !mbFillColor || (nTransparencePercent >= 100) ) + { + DrawInvisiblePolygon( rPolyPoly ); + } + + // handle metafile recording + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) ); + + bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout(); + if( bDrawn ) + return; + + // get the device graphics as drawing target + if( !mpGraphics ) + if( !ImplGetGraphics() ) + return; + + // try hard to draw it directly, because the emulation layers are slower + bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent ); + if( bDrawn ) + return; + + EmulateDrawTransparent( rPolyPoly, nTransparencePercent ); + + // #110958# Apply alpha value also to VDev alpha channel + if( mpAlphaVDev ) + { + const Color aFillCol( mpAlphaVDev->GetFillColor() ); + mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100), + sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100), + sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) ); + + mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent ); + + mpAlphaVDev->SetFillColor( aFillCol ); + } +} + +void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, + const Size& rSize, const Gradient& rTransparenceGradient ) +{ + + const Color aBlack( COL_BLACK ); + + if( mpMetaFile ) + { + // missing here is to map the data using the DeviceTransformation + mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) ); + } + + if ( !IsDeviceOutputNecessary() ) + return; + + if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) || + ( mnDrawMode & ( DRAWMODE_NOTRANSPARENCY ) ) ) + { + ( (GDIMetaFile&) rMtf ).WindStart(); + ( (GDIMetaFile&) rMtf ).Play( this, rPos, rSize ); + ( (GDIMetaFile&) rMtf ).WindStart(); + } + else + { + GDIMetaFile* pOldMetaFile = mpMetaFile; + Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) ); + Point aPoint; + Rectangle aDstRect( aPoint, GetOutputSizePixel() ); + + mpMetaFile = NULL; + aDstRect.Intersection( aOutRect ); + + ClipToPaintRegion( aDstRect ); + + if( !aDstRect.IsEmpty() ) + { + boost::scoped_ptr<VirtualDevice> pVDev(new VirtualDevice); + + ((OutputDevice*)pVDev.get())->mnDPIX = mnDPIX; + ((OutputDevice*)pVDev.get())->mnDPIY = mnDPIY; + + if( pVDev->SetOutputSizePixel( aDstRect.GetSize() ) ) + { + if(GetAntialiasing()) + { + // #i102109# + // For MetaFile replay (see task) it may now be necessary to take + // into account that the content is AntiAlialised and needs to be masked + // like that. Instead of masking, i will use a copy-modify-paste cycle + // here (as i already use in the VclPrimiziveRenderer with successs) + pVDev->SetAntialiasing(GetAntialiasing()); + + // create MapMode for buffer (offset needed) and set + MapMode aMap(GetMapMode()); + const Point aOutPos(PixelToLogic(aDstRect.TopLeft())); + aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y())); + pVDev->SetMapMode(aMap); + + // copy MapMode state and disable for target + const bool bOrigMapModeEnabled(IsMapModeEnabled()); + EnableMapMode(false); + + // copy MapMode state and disable for buffer + const bool bBufferMapModeEnabled(pVDev->IsMapModeEnabled()); + pVDev->EnableMapMode(false); + + // copy content from original to buffer + pVDev->DrawOutDev( + aPoint, pVDev->GetOutputSizePixel(), // dest + aDstRect.TopLeft(), pVDev->GetOutputSizePixel(), // source + *this); + + // draw MetaFile to buffer + pVDev->EnableMapMode(bBufferMapModeEnabled); + ((GDIMetaFile&)rMtf).WindStart(); + ((GDIMetaFile&)rMtf).Play(pVDev.get(), rPos, rSize); + ((GDIMetaFile&)rMtf).WindStart(); + + // get content bitmap from buffer + pVDev->EnableMapMode(false); + const Bitmap aPaint(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel())); + + // create alpha mask from gradient and get as Bitmap + pVDev->EnableMapMode(bBufferMapModeEnabled); + pVDev->SetDrawMode(DRAWMODE_GRAYGRADIENT); + pVDev->DrawGradient(Rectangle(rPos, rSize), rTransparenceGradient); + pVDev->SetDrawMode(DRAWMODE_DEFAULT); + pVDev->EnableMapMode(false); + const AlphaMask aAlpha(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel())); + + pVDev.reset(); + + // draw masked content to target and restore MapMode + DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha)); + EnableMapMode(bOrigMapModeEnabled); + } + else + { + Bitmap aPaint, aMask; + AlphaMask aAlpha; + MapMode aMap( GetMapMode() ); + Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) ); + const bool bOldMap = mbMap; + + aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) ); + pVDev->SetMapMode( aMap ); + const bool bVDevOldMap = pVDev->IsMapModeEnabled(); + + // create paint bitmap + ( (GDIMetaFile&) rMtf ).WindStart(); + ( (GDIMetaFile&) rMtf ).Play( pVDev.get(), rPos, rSize ); + ( (GDIMetaFile&) rMtf ).WindStart(); + pVDev->EnableMapMode( false ); + aPaint = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); + pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here! + + // create mask bitmap + pVDev->SetLineColor( COL_BLACK ); + pVDev->SetFillColor( COL_BLACK ); + pVDev->DrawRect( Rectangle( pVDev->PixelToLogic( Point() ), pVDev->GetOutputSize() ) ); + pVDev->SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT | + DRAWMODE_WHITEBITMAP | DRAWMODE_WHITEGRADIENT ); + ( (GDIMetaFile&) rMtf ).WindStart(); + ( (GDIMetaFile&) rMtf ).Play( pVDev.get(), rPos, rSize ); + ( (GDIMetaFile&) rMtf ).WindStart(); + pVDev->EnableMapMode( false ); + aMask = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); + pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here! + + // create alpha mask from gradient + pVDev->SetDrawMode( DRAWMODE_GRAYGRADIENT ); + pVDev->DrawGradient( Rectangle( rPos, rSize ), rTransparenceGradient ); + pVDev->SetDrawMode( DRAWMODE_DEFAULT ); + pVDev->EnableMapMode( false ); + pVDev->DrawMask( Point(), pVDev->GetOutputSizePixel(), aMask, Color( COL_WHITE ) ); + + aAlpha = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); + + pVDev.reset(); + + EnableMapMode( false ); + DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) ); + EnableMapMode( bOldMap ); + } + } + } + + mpMetaFile = pOldMetaFile; + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/wallpaper.cxx b/vcl/source/outdev/wallpaper.cxx new file mode 100644 index 000000000000..c53c1ecf6a39 --- /dev/null +++ b/vcl/source/outdev/wallpaper.cxx @@ -0,0 +1,384 @@ +/* -*- 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 <tools/debug.hxx> +#include <vcl/outdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/metaact.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/graph.hxx> + +#include <wall2.hxx> +#include <salgdi.hxx> +#include <window.h> +#include <svdata.hxx> +#include <outdev.h> + +#include <com/sun/star/uno/Sequence.hxx> + +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <math.h> +#include <boost/scoped_ptr.hpp> + +void OutputDevice::ImplDrawColorWallpaper( long nX, long nY, + long nWidth, long nHeight, + const Wallpaper& rWallpaper ) +{ + // draw wallpaper without border + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); + SetLineColor(); + SetFillColor( rWallpaper.GetColor() ); + bool bMap = mbMap; + EnableMapMode( false ); + DrawRect( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); + EnableMapMode( bMap ); +} + +void OutputDevice::ImplDrawBitmapWallpaper( long nX, long nY, + long nWidth, long nHeight, + const Wallpaper& rWallpaper ) +{ + BitmapEx aBmpEx; + const BitmapEx* pCached = rWallpaper.ImplGetImpWallpaper()->ImplGetCachedBitmap(); + Point aPos; + Size aSize; + GDIMetaFile* pOldMetaFile = mpMetaFile; + const WallpaperStyle eStyle = rWallpaper.GetStyle(); + const bool bOldMap = mbMap; + bool bDrawn = false; + bool bDrawGradientBackground = false; + bool bDrawColorBackground = false; + + if( pCached ) + aBmpEx = *pCached; + else + aBmpEx = rWallpaper.GetBitmap(); + + const long nBmpWidth = aBmpEx.GetSizePixel().Width(); + const long nBmpHeight = aBmpEx.GetSizePixel().Height(); + const bool bTransparent = aBmpEx.IsTransparent(); + + // draw background + if( bTransparent ) + { + if( rWallpaper.IsGradient() ) + bDrawGradientBackground = true; + else + { + if( !pCached && !rWallpaper.GetColor().GetTransparency() ) + { + VirtualDevice aVDev( *this ); + aVDev.SetBackground( rWallpaper.GetColor() ); + aVDev.SetOutputSizePixel( Size( nBmpWidth, nBmpHeight ) ); + aVDev.DrawBitmapEx( Point(), aBmpEx ); + aBmpEx = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() ); + } + + bDrawColorBackground = true; + } + } + else if( eStyle != WALLPAPER_TILE && eStyle != WALLPAPER_SCALE ) + { + if( rWallpaper.IsGradient() ) + bDrawGradientBackground = true; + else + bDrawColorBackground = true; + } + + // background of bitmap? + if( bDrawGradientBackground ) + ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); + else if( bDrawColorBackground && bTransparent ) + { + ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); + bDrawColorBackground = false; + } + + // calc pos and size + if( rWallpaper.IsRect() ) + { + const Rectangle aBound( LogicToPixel( rWallpaper.GetRect() ) ); + aPos = aBound.TopLeft(); + aSize = aBound.GetSize(); + } + else + { + aPos = Point( 0, 0 ); + aSize = Size( mnOutWidth, mnOutHeight ); + } + + mpMetaFile = NULL; + EnableMapMode( false ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); + + switch( eStyle ) + { + case( WALLPAPER_SCALE ): + { + if( !pCached || ( pCached->GetSizePixel() != aSize ) ) + { + if( pCached ) + rWallpaper.ImplGetImpWallpaper()->ImplReleaseCachedBitmap(); + + aBmpEx = rWallpaper.GetBitmap(); + aBmpEx.Scale( aSize ); + aBmpEx = BitmapEx( aBmpEx.GetBitmap().CreateDisplayBitmap( this ), aBmpEx.GetMask() ); + } + } + break; + + case( WALLPAPER_TOPLEFT ): + break; + + case( WALLPAPER_TOP ): + aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1; + break; + + case( WALLPAPER_TOPRIGHT ): + aPos.X() += ( aSize.Width() - nBmpWidth ); + break; + + case( WALLPAPER_LEFT ): + aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1; + break; + + case( WALLPAPER_CENTER ): + { + aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1; + aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1; + } + break; + + case( WALLPAPER_RIGHT ): + { + aPos.X() += ( aSize.Width() - nBmpWidth ); + aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1; + } + break; + + case( WALLPAPER_BOTTOMLEFT ): + aPos.Y() += ( aSize.Height() - nBmpHeight ); + break; + + case( WALLPAPER_BOTTOM ): + { + aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1; + aPos.Y() += ( aSize.Height() - nBmpHeight ); + } + break; + + case( WALLPAPER_BOTTOMRIGHT ): + { + aPos.X() += ( aSize.Width() - nBmpWidth ); + aPos.Y() += ( aSize.Height() - nBmpHeight ); + } + break; + + default: + { + const long nRight = nX + nWidth - 1L; + const long nBottom = nY + nHeight - 1L; + long nFirstX; + long nFirstY; + + if( eStyle == WALLPAPER_TILE ) + { + nFirstX = aPos.X(); + nFirstY = aPos.Y(); + } + else + { + nFirstX = aPos.X() + ( ( aSize.Width() - nBmpWidth ) >> 1 ); + nFirstY = aPos.Y() + ( ( aSize.Height() - nBmpHeight ) >> 1 ); + } + + const long nOffX = ( nFirstX - nX ) % nBmpWidth; + const long nOffY = ( nFirstY - nY ) % nBmpHeight; + long nStartX = nX + nOffX; + long nStartY = nY + nOffY; + + if( nOffX > 0L ) + nStartX -= nBmpWidth; + + if( nOffY > 0L ) + nStartY -= nBmpHeight; + + for( long nBmpY = nStartY; nBmpY <= nBottom; nBmpY += nBmpHeight ) + for( long nBmpX = nStartX; nBmpX <= nRight; nBmpX += nBmpWidth ) + DrawBitmapEx( Point( nBmpX, nBmpY ), aBmpEx ); + + bDrawn = true; + } + break; + } + + if( !bDrawn ) + { + // optimized for non-transparent bitmaps + if( bDrawColorBackground ) + { + const Size aBmpSize( aBmpEx.GetSizePixel() ); + const Point aTmpPoint; + const Rectangle aOutRect( aTmpPoint, GetOutputSizePixel() ); + const Rectangle aColRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + Rectangle aWorkRect; + + aWorkRect = Rectangle( 0, 0, aOutRect.Right(), aPos.Y() - 1L ); + aWorkRect.Justify(); + aWorkRect.Intersection( aColRect ); + if( !aWorkRect.IsEmpty() ) + { + ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), + aWorkRect.GetWidth(), aWorkRect.GetHeight(), + rWallpaper ); + } + + aWorkRect = Rectangle( 0, aPos.Y(), aPos.X() - 1L, aPos.Y() + aBmpSize.Height() - 1L ); + aWorkRect.Justify(); + aWorkRect.Intersection( aColRect ); + if( !aWorkRect.IsEmpty() ) + { + ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), + aWorkRect.GetWidth(), aWorkRect.GetHeight(), + rWallpaper ); + } + + aWorkRect = Rectangle( aPos.X() + aBmpSize.Width(), aPos.Y(), aOutRect.Right(), aPos.Y() + aBmpSize.Height() - 1L ); + aWorkRect.Justify(); + aWorkRect.Intersection( aColRect ); + if( !aWorkRect.IsEmpty() ) + { + ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), + aWorkRect.GetWidth(), aWorkRect.GetHeight(), + rWallpaper ); + } + + aWorkRect = Rectangle( 0, aPos.Y() + aBmpSize.Height(), aOutRect.Right(), aOutRect.Bottom() ); + aWorkRect.Justify(); + aWorkRect.Intersection( aColRect ); + if( !aWorkRect.IsEmpty() ) + { + ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(), + aWorkRect.GetWidth(), aWorkRect.GetHeight(), + rWallpaper ); + } + } + + DrawBitmapEx( aPos, aBmpEx ); + } + + rWallpaper.ImplGetImpWallpaper()->ImplSetCachedBitmap( aBmpEx ); + + Pop(); + EnableMapMode( bOldMap ); + mpMetaFile = pOldMetaFile; +} + +void OutputDevice::ImplDrawGradientWallpaper( long nX, long nY, + long nWidth, long nHeight, + const Wallpaper& rWallpaper ) +{ + Rectangle aBound; + GDIMetaFile* pOldMetaFile = mpMetaFile; + const bool bOldMap = mbMap; + bool bNeedGradient = true; + + aBound = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ); + + mpMetaFile = NULL; + EnableMapMode( false ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); + + if( OUTDEV_WINDOW == meOutDevType && rWallpaper.GetStyle() == WALLPAPER_APPLICATIONGRADIENT ) + { + Window *pWin = dynamic_cast< Window* >( this ); + if( pWin ) + { + // limit gradient to useful size, so that it still can be noticed + // in maximized windows + long gradientWidth = pWin->GetDesktopRectPixel().GetSize().Width(); + if( gradientWidth > 1024 ) + gradientWidth = 1024; + if( mnOutOffX+nWidth > gradientWidth ) + ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper.GetGradient().GetEndColor() ); + if( mnOutOffX > gradientWidth ) + bNeedGradient = false; + else + aBound = Rectangle( Point( -mnOutOffX, nY ), Size( gradientWidth, nHeight ) ); + } + } + + if( bNeedGradient ) + DrawGradient( aBound, rWallpaper.GetGradient() ); + + Pop(); + EnableMapMode( bOldMap ); + mpMetaFile = pOldMetaFile; +} + +void OutputDevice::ImplDrawWallpaper( long nX, long nY, + long nWidth, long nHeight, + const Wallpaper& rWallpaper ) +{ + if( rWallpaper.IsBitmap() ) + ImplDrawBitmapWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); + else if( rWallpaper.IsGradient() ) + ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); + else + ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper ); +} + +void OutputDevice::DrawWallpaper( const Rectangle& rRect, + const Wallpaper& rWallpaper ) +{ + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaWallpaperAction( rRect, rWallpaper ) ); + + if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) + return; + + if ( rWallpaper.GetStyle() != WALLPAPER_NULL ) + { + Rectangle aRect = LogicToPixel( rRect ); + aRect.Justify(); + + if ( !aRect.IsEmpty() ) + { + ImplDrawWallpaper( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), + rWallpaper ); + } + } + + if( mpAlphaVDev ) + mpAlphaVDev->DrawWallpaper( rRect, rWallpaper ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |